Skip to content

Commit

Permalink
feat: resource ref selection in Monaco editor
Browse files Browse the repository at this point in the history
  • Loading branch information
devcatalin committed Sep 22, 2021
1 parent 5180ab2 commit 04ab1c7
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 46 deletions.
4 changes: 2 additions & 2 deletions src/components/molecules/Monaco/Monaco.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import useCodeIntel from './useCodeIntel';
import useEditorKeybindings from './useEditorKeybindings';
import useResourceYamlSchema from './useResourceYamlSchema';
import useDebouncedCodeSave from './useDebouncedCodeSave';
import useEditorUiState from './useEditorUiState';
import useMonacoUiState from './useMonacoUiState';
import * as S from './Monaco.styled';

// @ts-ignore
Expand Down Expand Up @@ -97,7 +97,7 @@ const Monaco = (props: {editorHeight: string; diffSelectedResource: () => void;
selectedPath,
setOrgCode
);
const {onEditorFocus} = useEditorUiState(editor, selectedResourceId);
const {onEditorFocus} = useMonacoUiState(editor, selectedResourceId, selectedPath);

const onDidChangeMarkers = (e: monaco.Uri[]) => {
const flag = monaco.editor.getModelMarkers({}).length > 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import {setMonacoEditor} from '@redux/reducers/ui';
import {useCallback, useEffect} from 'react';
import {monaco} from 'react-monaco-editor';

function useEditorUiState(editor: monaco.editor.IStandaloneCodeEditor | null, selectedResourceId: string | undefined) {
function useMonacoUiState(
editor: monaco.editor.IStandaloneCodeEditor | null,
selectedResourceId: string | undefined,
selectedPath: string | undefined
) {
const dispatch = useAppDispatch();
const monacoEditor = useAppSelector(state => state.ui.monacoEditor);

Expand All @@ -26,6 +30,21 @@ function useEditorUiState(editor: monaco.editor.IStandaloneCodeEditor | null, se
};
}, []);

useEffect(() => {
const selection = monacoEditor.selection;
if (!selection || !editor) {
return;
}
if (
(selection.type === 'file' && selection.filePath === selectedPath) ||
(selection.type === 'resource' && selection.resourceId === selectedResourceId)
) {
editor.setSelection(selection.range);
editor.revealLineInCenter(selection.range.startLineNumber);
dispatch(setMonacoEditor({selection: undefined}));
}
}, [monacoEditor, selectedPath, selectedResourceId]);

useEffect(() => {
if (!monacoEditor.focused) {
return;
Expand All @@ -52,4 +71,4 @@ function useEditorUiState(editor: monaco.editor.IStandaloneCodeEditor | null, se
return {onEditorFocus};
}

export default useEditorUiState;
export default useMonacoUiState;
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from 'react';
import {ResourceRef} from '@models/k8sresource';
import {K8sResource, ResourceRef, ResourceRefType} from '@models/k8sresource';
import {ResourceMapType} from '@models/appstate';
import styled from 'styled-components';
import {Typography, Divider} from 'antd';
import {useAppDispatch, useAppSelector} from '@redux/hooks';
import {selectFile, selectK8sResource} from '@redux/reducers/main';
import {setMonacoEditor} from '@redux/reducers/ui';
import {MonacoRange} from '@models/ui';
import RefLink from './RefLink';

const {Text} = Typography;
Expand Down Expand Up @@ -35,21 +39,96 @@ const getRefKind = (ref: ResourceRef, resourceMap: ResourceMapType) => {
}
};

const getRefRange = (ref: ResourceRef) => {
if (!ref.position) {
return undefined;
}
return {
startLineNumber: ref.position.line,
endLineNumber: ref.position.line,
startColumn: ref.position.column,
endColumn: ref.position.column + ref.position.length,
};
};

const ResourceRefsPopover = (props: {
children: React.ReactNode;
resource: K8sResource;
resourceRefs: ResourceRef[];
resourceMap: ResourceMapType;
selectResource: (selectedResource: string) => void;
selectFilePath: (filePath: string) => void;
}) => {
const {children, resourceRefs, resourceMap, selectResource, selectFilePath} = props;
const {children, resourceRefs, resource} = props;
const dispatch = useAppDispatch();
const resourceMap = useAppSelector(state => state.main.resourceMap);
const fileMap = useAppSelector(state => state.main.fileMap);
const selectedResourceId = useAppSelector(state => state.main.selectedResourceId);
const selectedPath = useAppSelector(state => state.main.selectedPath);

const selectResource = (selectedId: string) => {
if (resourceMap[selectedId]) {
dispatch(selectK8sResource({resourceId: selectedId}));
}
};

const selectFilePath = (filePath: string) => {
if (fileMap[filePath]) {
dispatch(selectFile({filePath}));
}
};

const makeMonacoSelection = (type: 'resource' | 'file', target: string, range: MonacoRange) => {
const selection =
type === 'resource'
? {
type,
resourceId: target,
range,
}
: {type, filePath: target, range};
dispatch(
setMonacoEditor({
selection,
})
);
};

const onLinkClick = (ref: ResourceRef) => {
if (ref.target?.type === 'resource' && ref.target.resourceId) {
selectResource(ref.target.resourceId);
if (ref.type !== ResourceRefType.Incoming) {
if (selectedResourceId !== resource.id) {
selectResource(resource.id);
}
const refRange = getRefRange(ref);
if (refRange) {
makeMonacoSelection('resource', resource.id, refRange);
}
return;
}

if (ref.target?.type === 'resource') {
if (!ref.target.resourceId) {
return;
}
const targetResource = resourceMap[ref.target.resourceId];
if (!targetResource) {
return;
}
if (selectedResourceId !== targetResource.id) {
selectResource(targetResource.id);
}
const targetOutgoingRef = targetResource.refs?.find(
r => r.type === ResourceRefType.Outgoing && r.target?.type === 'resource' && r.target.resourceId === resource.id
);
if (!targetOutgoingRef) {
return;
}
const targetOutgoingRefRange = getRefRange(targetOutgoingRef);
if (targetOutgoingRefRange) {
makeMonacoSelection('resource', targetResource.id, targetOutgoingRefRange);
}
}
if (ref.target?.type === 'file') {
selectFilePath(ref.target.filePath);
if (selectedPath !== ref.target.filePath) {
selectFilePath(ref.target.filePath);
}
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import MonoIcon, {MonoIconTypes} from '@components/atoms/MonoIcon';
import {K8sResource} from '@models/k8sresource';
import {useAppDispatch, useAppSelector} from '@redux/hooks';
import {selectFile, selectK8sResource} from '@redux/reducers/main';
import {isIncomingRef, isOutgoingRef, isUnsatisfiedRef} from '@redux/services/resourceRefs';
import {Popover} from 'antd';
import {useMemo} from 'react';
Expand All @@ -16,9 +14,7 @@ const StyledIconsContainer = styled.span`

const ResourceRefsIconPopover = (props: {resource: K8sResource; type: 'incoming' | 'outgoing'}) => {
const {resource, type} = props;
const dispatch = useAppDispatch();
const resourceMap = useAppSelector(state => state.main.resourceMap);
const fileMap = useAppSelector(state => state.main.fileMap);

const resourceRefs = useMemo(
() =>
resource.refs?.filter(r => {
Expand All @@ -36,18 +32,6 @@ const ResourceRefsIconPopover = (props: {resource: K8sResource; type: 'incoming'
return resourceRefs?.some(r => isUnsatisfiedRef(r.type));
}, [resourceRefs, type]);

const selectResource = (selectedId: string) => {
if (resourceMap[selectedId]) {
dispatch(selectK8sResource({resourceId: selectedId}));
}
};

const selectFilePath = (filePath: string) => {
if (fileMap[filePath]) {
dispatch(selectFile({filePath}));
}
};

if (!resourceRefs || resourceRefs.length === 0) {
return null;
}
Expand All @@ -57,12 +41,7 @@ const ResourceRefsIconPopover = (props: {resource: K8sResource; type: 'incoming'
mouseEnterDelay={0.5}
placement="rightTop"
content={
<RefsPopoverContent
resourceRefs={resourceRefs}
resourceMap={resourceMap}
selectResource={selectResource}
selectFilePath={selectFilePath}
>
<RefsPopoverContent resource={resource} resourceRefs={resourceRefs}>
{type === 'incoming' ? (
<>
Incoming Links <MonoIcon type={MonoIconTypes.IncomingRefs} />
Expand Down
42 changes: 33 additions & 9 deletions src/models/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,38 @@ export type NewResourceWizardInput = {
selectedResourceId?: string;
};

export type MonacoRange = {
startLineNumber: number;
endLineNumber: number;
startColumn: number;
endColumn: number;
};

export type MonacoSelectionResource = {
type: 'resource';
resourceId: string;
range: MonacoRange;
};

export type MonacoSelectionFile = {
type: 'file';
filePath: string;
range: MonacoRange;
};

export type MonacoUiSelection = MonacoSelectionResource | MonacoSelectionFile;

export type MonacoUiState = {
focused: boolean;
undo: boolean;
redo: boolean;
find: boolean;
replace: boolean;
apply: boolean;
diff: boolean;
selection?: MonacoUiSelection;
};

export type UiState = {
isSettingsOpen: boolean;
newResourceWizard: {
Expand Down Expand Up @@ -37,15 +69,7 @@ export type UiState = {
folderExplorer: {
isOpen: boolean;
};
monacoEditor: {
focused: boolean;
undo: boolean;
redo: boolean;
find: boolean;
replace: boolean;
apply: boolean;
diff: boolean;
};
monacoEditor: MonacoUiState;
paneConfiguration: PaneConfiguration;
shouldExpandAllNodes: boolean;
resetLayout: boolean;
Expand Down
4 changes: 2 additions & 2 deletions src/redux/reducers/ui.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {createAsyncThunk, createSlice, Draft, PayloadAction} from '@reduxjs/toolkit';
import {setRootFolder} from '@redux/thunks/setRootFolder';
import {PaneConfiguration, UiState, NewResourceWizardInput} from '@models/ui';
import {PaneConfiguration, UiState, NewResourceWizardInput, MonacoUiState} from '@models/ui';
import initialState from '@redux/initialState';
import {ResourceValidationError} from '@models/k8sresource';
import electronStore from '@utils/electronStore';
Expand Down Expand Up @@ -110,7 +110,7 @@ export const uiSlice = createSlice({
closeFolderExplorer: (state: Draft<UiState>) => {
state.folderExplorer = {isOpen: false};
},
setMonacoEditor: (state: Draft<UiState>, action: PayloadAction<any>) => {
setMonacoEditor: (state: Draft<UiState>, action: PayloadAction<Partial<MonacoUiState>>) => {
state.monacoEditor = {
...state.monacoEditor,
...action.payload,
Expand Down

0 comments on commit 04ab1c7

Please sign in to comment.