Skip to content

Commit

Permalink
feat: refactored refs to use RefTarget type
Browse files Browse the repository at this point in the history
  • Loading branch information
olensmar committed Sep 14, 2021
1 parent 3ff29a5 commit 4e66371
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 89 deletions.
24 changes: 15 additions & 9 deletions src/components/molecules/GraphView/GraphView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@ function mapResourceToElement(resource: K8sResource): Node {
};
}

function mapRefToElement(source: K8sResource, ref: ResourceRef): Edge {
return {
id: `${source.id}-${ref.targetResourceId}-${ref.type}`,
source: source.id,
target: ref.targetResourceId || ref.name,
animated: false,
type: 'smoothstep',
};
function mapRefToElement(source: K8sResource, ref: ResourceRef): Edge | undefined {
if (ref.target?.type === 'resource') {
return {
id: `${source.id}-${ref.target.resourceId}-${ref.type}`,
source: source.id,
target: ref.target.resourceId || ref.name,
animated: false,
type: 'smoothstep',
};
}
return undefined;
}

const dagreGraph = new dagre.graphlib.Graph();
Expand Down Expand Up @@ -94,7 +97,10 @@ const GraphView = (props: {editorHeight: string}) => {
function getElementData(resource: K8sResource) {
let data: any[] = [mapResourceToElement(resource)];
if (resource.refs) {
const refs = resource.refs.filter(ref => !isUnsatisfiedRef(ref.type)).map(ref => mapRefToElement(resource, ref));
const refs = resource.refs
.filter(ref => !isUnsatisfiedRef(ref.type))
.map(ref => mapRefToElement(resource, ref))
.filter(ref => Boolean(ref));
data = data.concat(refs);
}
return data;
Expand Down
16 changes: 10 additions & 6 deletions src/components/molecules/Monaco/Monaco.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,15 @@ const Monaco = (props: {editorHeight: string; diffSelectedResource: () => void;
const isInPreviewMode = useSelector(isInPreviewModeSelector);
const dispatch = useAppDispatch();

const selectResourceOrFile = (selectedId: string) => {
if (resourceMap[selectedId]) {
dispatch(selectK8sResource({resourceId: selectedId}));
} else if (fileMap[selectedId]) {
dispatch(selectFile({filePath: selectedId}));
const selectResource = (resourceId: string) => {
if (resourceMap[resourceId]) {
dispatch(selectK8sResource({resourceId}));
}
};

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

Expand Down Expand Up @@ -335,7 +339,7 @@ const Monaco = (props: {editorHeight: string; diffSelectedResource: () => void;
if (editor && selectedResourceId && resourceMap[selectedResourceId]) {
const resource = resourceMap[selectedResourceId];
const {newDecorations, newHoverDisposables, newCommandDisposables, newLinkDisposables} =
codeIntel.applyForResource(resource, selectResourceOrFile, resourceMap);
codeIntel.applyForResource(resource, selectResource, selectFilePath, resourceMap, fileMap);
const idsOfNewDecorations = setDecorations(editor, newDecorations, idsOfDecorationsRef.current);
idsOfDecorationsRef.current = idsOfNewDecorations;
hoverDisposablesRef.current = newHoverDisposables;
Expand Down
56 changes: 39 additions & 17 deletions src/components/molecules/Monaco/codeIntel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {isUnsatisfiedRef, isOutgoingRef} from '@redux/services/resourceRefs';
import {K8sResource, ResourceRef, RefPosition} from '@models/k8sresource';

import {ResourceKindHandlers, getIncomingRefMappers} from '@src/kindhandlers';
import {ResourceMapType} from '@models/appstate';
import {FileMapType, ResourceMapType} from '@models/appstate';
import {GlyphDecorationTypes, InlineDecorationTypes} from './editorConstants';

import {
Expand Down Expand Up @@ -117,7 +117,9 @@ function areRefPosEqual(a: RefPosition, b: RefPosition) {
export function applyForResource(
resource: K8sResource,
selectResource: (resourceId: string) => void,
resourceMap: ResourceMapType
selectFilePath: (filePath: string) => void,
resourceMap: ResourceMapType,
fileMap: FileMapType
) {
const refs = resource.refs;
const newDecorations: monaco.editor.IModelDeltaDecoration[] = [];
Expand Down Expand Up @@ -175,23 +177,40 @@ export function applyForResource(

const commandMarkdownLinkList: monaco.IMarkdownString[] = [];
outgoingRefs.forEach(outgoingRef => {
if (!outgoingRef.targetResourceId) {
return;
}
const outgoingRefResource = resourceMap[outgoingRef.targetResourceId];
if (!outgoingRefResource) {
if (!outgoingRef.target) {
return;
}
const {commandMarkdownLink, commandDisposable} = createCommandMarkdownLink(
`${outgoingRefResource.kind}: ${outgoingRefResource.name}`,
() => {
if (outgoingRef.targetResourceId) {
selectResource(outgoingRef.targetResourceId);

if (outgoingRef.target.type === 'resource' && outgoingRef.target.resourceId) {
const outgoingRefResource = resourceMap[outgoingRef.target.resourceId];
if (!outgoingRefResource) {
return;
}
const {commandMarkdownLink, commandDisposable} = createCommandMarkdownLink(
`${outgoingRefResource.kind}: ${outgoingRefResource.name}`,
() => {
// @ts-ignore
selectResource(outgoingRef.target?.resourceId);
}
);
commandMarkdownLinkList.push(commandMarkdownLink);
newCommandDisposables.push(commandDisposable);
}
if (outgoingRef.target.type === 'file') {
const outgoingRefFile = fileMap[outgoingRef.target.filePath];
if (!outgoingRefFile) {
return;
}
);
commandMarkdownLinkList.push(commandMarkdownLink);
newCommandDisposables.push(commandDisposable);
const {commandMarkdownLink, commandDisposable} = createCommandMarkdownLink(
`File: ${outgoingRefFile.name}`,
() => {
// @ts-ignore
selectFilePath(outgoingRef.target?.filePath);
}
);
commandMarkdownLinkList.push(commandMarkdownLink);
newCommandDisposables.push(commandDisposable);
}
});

if (commandMarkdownLinkList.length > 0) {
Expand All @@ -205,8 +224,11 @@ export function applyForResource(
if (outgoingRefs.length === 1) {
const outgoingRef = outgoingRefs[0];
const linkDisposable = createLinkProvider(inlineRange, () => {
if (outgoingRef.targetResourceId) {
selectResource(outgoingRef.targetResourceId);
if (outgoingRef.target?.type === 'resource' && outgoingRef.target.resourceId) {
selectResource(outgoingRef.target.resourceId);
}
if (outgoingRef.target?.type === 'file' && outgoingRef.target.filePath) {
selectFilePath(outgoingRef.target.filePath);
}
});
newLinkDisposables.push(linkDisposable);
Expand Down
97 changes: 61 additions & 36 deletions src/components/molecules/NavigatorRowLabel/NavigatorRowLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import {NAVIGATOR_HEIGHT_OFFSET} from '@constants/constants';

import {useAppDispatch, useAppSelector} from '@redux/hooks';
import {selectFile, selectK8sResource} from '@redux/reducers/main';
import {K8sResource, ResourceRef, ResourceRefType, ResourceValidationError} from '@models/k8sresource';
import {K8sResource, ResourceRef, ResourceValidationError} from '@models/k8sresource';
import {ResourceMapType} from '@models/appstate';
import {isIncomingRef, isOutgoingRef, isUnsatisfiedRef} from '@redux/services/resourceRefs';
import {isUnsavedResource} from '@redux/services/resource';
import ScrollIntoView from '@molecules/ScrollIntoView';
import {isInPreviewModeSelector} from '@redux/selectors';
import {isKustomizationResource} from '@redux/services/kustomize';
import path from 'path';
import ActionsMenu from './ActionsMenu';

const {Text} = Typography;
Expand Down Expand Up @@ -134,23 +135,48 @@ const UnsatisfiedRefLink = (props: {text: string}) => {
);
};

const getRefTargetName = (ref: ResourceRef, resourceMap: ResourceMapType) => {
if (ref.target?.type === 'resource') {
if (ref.target.resourceId && resourceMap[ref.target.resourceId]) {
return resourceMap[ref.target.resourceId].name;
}
}
if (ref.target?.type === 'file') {
return path.parse(ref.target.filePath).name;
}
return ref.name;
};

const getRefKind = (ref: ResourceRef, resourceMap: ResourceMapType) => {
if (ref.target?.type === 'file') {
return 'File';
}

if (ref.target?.type === 'resource') {
if (ref.target.resourceKind) {
return ref.target.resourceKind;
}
if (ref.target.resourceId) {
return resourceMap[ref.target.resourceId]?.kind;
}
}
};

const RefLink = (props: {resourceRef: ResourceRef; resourceMap: ResourceMapType; onClick?: () => void}) => {
const {resourceRef, resourceMap, onClick} = props;

const targetName =
resourceRef.targetResourceId && resourceMap[resourceRef.targetResourceId]
? resourceMap[resourceRef.targetResourceId].name
: resourceRef.name;

const targetName = getRefTargetName(resourceRef, resourceMap);
let linkText = targetName;

if (resourceRef.type === ResourceRefType.File) {
if (resourceRef.target?.type === 'file') {
linkText = `File: ${targetName}`;
} else if (resourceRef.targetResourceKind) {
linkText = `${resourceRef.targetResourceKind}: ${targetName}`;
} else if (resourceRef.targetResourceId) {
const resourceKind = resourceMap[resourceRef.targetResourceId].kind;
linkText = `${resourceKind}: ${targetName}`;
} else if (resourceRef.target?.type === 'resource') {
if (resourceRef.target.resourceKind) {
linkText = `${resourceRef.target.resourceKind}: ${targetName}`;
} else if (resourceRef.target.resourceId) {
const resourceKind = resourceMap[resourceRef.target.resourceId].kind;
linkText = `${resourceKind}: ${targetName}`;
}
}

if (isOutgoingRef(resourceRef.type)) {
Expand All @@ -170,13 +196,17 @@ const PopoverContent = (props: {
children: React.ReactNode;
resourceRefs: ResourceRef[];
resourceMap: ResourceMapType;
selectResourceOrFile: (selectedResourceOrFile: string) => void;
selectResource: (resourceId: string) => void;
selectFilePath: (filePath: string) => void;
}) => {
const {children, resourceRefs, resourceMap, selectResourceOrFile} = props;
const {children, resourceRefs, resourceMap, selectResource, selectFilePath} = props;

const onLinkClick = (ref: ResourceRef) => {
if (ref.targetResourceId) {
selectResourceOrFile(ref.targetResourceId);
if (ref.target?.type === 'resource' && ref.target.resourceId) {
selectResource(ref.target.resourceId);
}
if (ref.target?.type === 'file') {
selectFilePath(ref.target.filePath);
}
};

Expand All @@ -186,27 +216,16 @@ const PopoverContent = (props: {
<StyledDivider />
{resourceRefs
.sort((a, b) => {
let kindA;
let kindB;
if (a.targetResourceKind) {
kindA = a.targetResourceKind;
} else if (a.targetResourceId) {
const targetResourceA = resourceMap[a.targetResourceId];
kindA = targetResourceA?.kind;
}
if (b.targetResourceKind) {
kindB = b.targetResourceKind;
} else if (b.targetResourceId) {
const targetResourceB = resourceMap[b.targetResourceId];
kindB = targetResourceB?.kind;
}
let kindA = getRefKind(a, resourceMap);
let kindB = getRefKind(b, resourceMap);

if (kindA && kindB) {
return kindA.localeCompare(kindB);
}
return 0;
})
.map(resourceRef => (
<StyledRefDiv key={resourceRef.targetResourceId || resourceRef.name}>
<StyledRefDiv key={resourceRef.name}>
<RefLink resourceRef={resourceRef} resourceMap={resourceMap} onClick={() => onLinkClick(resourceRef)} />
</StyledRefDiv>
))}
Expand Down Expand Up @@ -292,11 +311,15 @@ const NavigatorRowLabel = (props: NavigatorRowLabelProps) => {
return Boolean(resource && isUnsavedResource(resource));
}, [resource]);

const selectResourceOrFile = (selectedId: string) => {
const selectResource = (selectedId: string) => {
if (resourceMap[selectedId]) {
dispatch(selectK8sResource({resourceId: selectedId}));
} else if (fileMap[selectedId]) {
dispatch(selectFile({filePath: selectedId}));
}
};

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

Expand All @@ -314,7 +337,8 @@ const NavigatorRowLabel = (props: NavigatorRowLabelProps) => {
<PopoverContent
resourceRefs={resource.refs.filter(r => isIncomingRef(r.type))}
resourceMap={resourceMap}
selectResourceOrFile={selectResourceOrFile}
selectResource={selectResource}
selectFilePath={selectFilePath}
>
Incoming Links <MonoIcon type={MonoIconTypes.IncomingRefs} />
</PopoverContent>
Expand Down Expand Up @@ -346,7 +370,8 @@ const NavigatorRowLabel = (props: NavigatorRowLabelProps) => {
<PopoverContent
resourceRefs={resource.refs.filter(r => isOutgoingRef(r.type) || isUnsatisfiedRef(r.type))}
resourceMap={resourceMap}
selectResourceOrFile={selectResourceOrFile}
selectResource={selectResource}
selectFilePath={selectFilePath}
>
Outgoing Links <MonoIcon type={MonoIconTypes.OutgoingRefs} />
</PopoverContent>
Expand Down
19 changes: 14 additions & 5 deletions src/models/k8sresource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,27 @@ export enum ResourceRefType {
Incoming = 'incoming',
Outgoing = 'outgoing',
Unsatisfied = 'unsatisfied-outgoing',
File = 'file',
}

type RefTargetResource = {
type: 'resource';
resourceId?: string;
resourceKind?: string;
};
type RefTargetFile = {
type: 'file';
filePath: string;
};

type RefTarget = RefTargetResource | RefTargetFile;

interface ResourceRef {
/** the type of ref (see enum) */
type: ResourceRefType;
/** the ref value - for example the name of a configmap */
name: string;
/** the resource this is referring to (empty for unsatisfied refs, filePath for File refs) */
targetResourceId?: string;
/** the resource kind of the target resource */
targetResourceKind?: string;
/** the target resource or file this is referring to (empty for unsatisfied refs) */
target?: RefTarget;
/** the position in the document of the refName (undefined for incoming file refs) */
position?: RefPosition;
}
Expand Down
8 changes: 4 additions & 4 deletions src/redux/services/kustomize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,13 @@ export function getKustomizationRefs(
kustomization.refs
.filter(r => r.type === ResourceRefType.Outgoing || (selectParent && r.type === ResourceRefType.Incoming))
.forEach(r => {
if (r.targetResourceId) {
const target = resourceMap[r.targetResourceId];
if (r.target?.type === 'resource' && r.target.resourceId) {
const target = resourceMap[r.target.resourceId];
if (target) {
linkedResourceIds.push(r.targetResourceId);
linkedResourceIds.push(r.target.resourceId);

if (target.kind === 'Kustomization' && r.type === ResourceRefType.Outgoing) {
linkedResourceIds = linkedResourceIds.concat(getKustomizationRefs(resourceMap, r.targetResourceId));
linkedResourceIds = linkedResourceIds.concat(getKustomizationRefs(resourceMap, r.target.resourceId));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/redux/services/renameResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export const renameResource = (
const newResourceText = stringify(newResourceContent);
if (shouldUpdateRefs && resource.refs) {
resource.refs.forEach(ref => {
if (!isIncomingRef(ref.type) || !ref.targetResourceId) {
if (!isIncomingRef(ref.type) || !(ref.target?.type === 'resource' && ref.target.resourceId)) {
return;
}
const dependentResource = resourceMap[ref.targetResourceId];
const dependentResource = resourceMap[ref.target.resourceId];
if (!dependentResource || !dependentResource.refs) {
return;
}
Expand Down
Loading

0 comments on commit 4e66371

Please sign in to comment.