Skip to content

Commit

Permalink
feat: Prefix and ContextMenu for ResourceKind nav section items
Browse files Browse the repository at this point in the history
  • Loading branch information
devcatalin committed Sep 17, 2021
1 parent 8189b7c commit 2f0e007
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 2 deletions.
60 changes: 60 additions & 0 deletions src/components/molecules/ResourceRefLink/ResourceRefLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';
import MonoIcon, {MonoIconTypes} from '@components/atoms/MonoIcon';
import {ResourceMapType} from '@models/appstate';
import {ResourceRef} from '@models/k8sresource';
import {isIncomingRef, isOutgoingRef, isUnsatisfiedRef} from '@redux/services/resourceRefs';
import {FontColors} from '@styles/Colors';
import styled from 'styled-components';

const StyledRefText = styled.span<{isUnsatisfied: boolean}>`
cursor: pointer;
&:hover {
text-decoration: underline;
}
${props => {
if (props.isUnsatisfied) {
return `color: ${FontColors.warning};`;
}
}}
`;

const Icon = React.memo((props: {resourceRef: ResourceRef; style: React.CSSProperties}) => {
const {resourceRef, style} = props;
if (isOutgoingRef(resourceRef.type)) {
return <MonoIcon type={MonoIconTypes.OutgoingRefs} style={style} />;
}
if (isIncomingRef(resourceRef.type)) {
return <MonoIcon type={MonoIconTypes.IncomingRefs} style={style} />;
}
if (isUnsatisfiedRef(resourceRef.type)) {
return <MonoIcon type={MonoIconTypes.Warning} style={style} />;
}
return null;
});

const ResourceRefLink = (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;

let linkText = targetName;

if (resourceRef.targetResourceKind) {
linkText = `${resourceRef.targetResourceKind}: ${targetName}`;
} else if (resourceRef.targetResourceId) {
const resourceKind = resourceMap[resourceRef.targetResourceId].kind;
linkText = `${resourceKind}: ${targetName}`;
}

return (
<div onClick={onClick}>
{Icon && <Icon resourceRef={resourceRef} style={{marginRight: 5}} />}
<StyledRefText isUnsatisfied={isUnsatisfiedRef(resourceRef.type)}>{linkText}</StyledRefText>
</div>
);
};

export default ResourceRefLink;
1 change: 1 addition & 0 deletions src/components/molecules/ResourceRefLink/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default} from './ResourceRefLink';
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import {ResourceRef} from '@models/k8sresource';
import {ResourceMapType} from '@models/appstate';
import styled from 'styled-components';
import {Typography, Divider} from 'antd';
import ResourceRefLink from '@components/molecules/ResourceRefLink';

const {Text} = Typography;

const PopoverTitle = styled(Text)`
font-weight: 500;
`;

const StyledDivider = styled(Divider)`
margin: 5px 0;
`;

const StyledRefDiv = styled.div`
display: block;
margin: 5px 0;
`;

const ResourceRefsPopover = (props: {
children: React.ReactNode;
resourceRefs: ResourceRef[];
resourceMap: ResourceMapType;
selectResource: (selectedResource: string) => void;
}) => {
const {children, resourceRefs, resourceMap, selectResource} = props;

const onLinkClick = (ref: ResourceRef) => {
if (ref.targetResourceId) {
selectResource(ref.targetResourceId);
}
};

return (
<>
<PopoverTitle>{children}</PopoverTitle>
<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;
}
if (kindA && kindB) {
return kindA.localeCompare(kindB);
}
return 0;
})
.map(resourceRef => (
<StyledRefDiv key={resourceRef.targetResourceId || resourceRef.name}>
<ResourceRefLink
resourceRef={resourceRef}
resourceMap={resourceMap}
onClick={() => onLinkClick(resourceRef)}
/>
</StyledRefDiv>
))}
</>
);
};
export default ResourceRefsPopover;
1 change: 1 addition & 0 deletions src/components/molecules/ResourceRefsPopover/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default} from './ResourceRefsPopover';
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {selectK8sResource} from '@redux/reducers/main';
import {isPassingKeyValueFilter} from '@utils/filter';
import {activeResourcesSelector} from '@redux/selectors';
import {isUnsavedResource} from '@redux/services/resource';
import K8sResourceContextMenu from './K8sResourceContextMenu';
import ResourceKindContextMenu from './ResourceKindContextMenu';
import ResourceKindPrefix from './ResourceKindPrefix';

function isResourcePassingFilter(resource: K8sResource, filters: ResourceFilterType) {
if (
Expand Down Expand Up @@ -100,7 +101,8 @@ export function makeResourceKindNavSection(
},
},
itemCustomization: {
ContextMenu: K8sResourceContextMenu,
Prefix: ResourceKindPrefix,
ContextMenu: ResourceKindContextMenu,
},
};
return navSection;
Expand Down
49 changes: 49 additions & 0 deletions src/navsections/K8sResourceNavSection/ResourceKindPrefix.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import MonoIcon, {MonoIconTypes} from '@components/atoms/MonoIcon';
import ResourceRefsPopover from '@components/molecules/ResourceRefsPopover';
import {K8sResource} from '@models/k8sresource';
import {NavSectionItemCustomComponentProps} from '@models/navsection';
import {useAppDispatch, useAppSelector} from '@redux/hooks';
import {selectK8sResource} from '@redux/reducers/main';
import {isIncomingRef} from '@redux/services/resourceRefs';
import {Popover} from 'antd';
import styled from 'styled-components';

const StyledIconsContainer = styled.span`
display: flex;
align-items: center;
cursor: pointer;
`;

const Prefix = (props: NavSectionItemCustomComponentProps<K8sResource>) => {
const {item} = props;
const dispatch = useAppDispatch();
const resourceMap = useAppSelector(state => state.main.resourceMap);

const incomingRefs = item.refs?.filter(r => isIncomingRef(r.type));

const selectResource = (resId: string) => {
dispatch(selectK8sResource({resourceId: resId}));
};

if (!incomingRefs || incomingRefs.length === 0) {
return null;
}

return (
<Popover
mouseEnterDelay={0.5}
placement="rightTop"
content={
<ResourceRefsPopover resourceRefs={incomingRefs} resourceMap={resourceMap} selectResource={selectResource}>
Incoming Links <MonoIcon type={MonoIconTypes.IncomingRefs} />
</ResourceRefsPopover>
}
>
<StyledIconsContainer>
<MonoIcon type={MonoIconTypes.IncomingRefs} style={{marginRight: 5}} />
</StyledIconsContainer>
</Popover>
);
};

export default Prefix;
5 changes: 5 additions & 0 deletions src/navsections/K8sResourceNavSection/ResourceKindSuffix.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const Suffix = () => {
return null;
};

export default Suffix;

0 comments on commit 2f0e007

Please sign in to comment.