Skip to content

Commit

Permalink
create topology side panel using dynamic plugin extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
sahil143 committed Jun 22, 2021
1 parent 315f017 commit bae8517
Show file tree
Hide file tree
Showing 17 changed files with 415 additions and 8 deletions.
Expand Up @@ -103,4 +103,5 @@ export type DetailsResourceAlertContent = {
content: React.Component | undefined;
variant?: 'success' | 'danger' | 'warning' | 'info' | 'default';
actionLinks?: React.ReactNode;
onClose?: () => void;
};
81 changes: 81 additions & 0 deletions frontend/packages/helm-plugin/console-extensions.json
Expand Up @@ -74,5 +74,86 @@
"flags": {
"required": ["OPENSHIFT_HELM"]
}
},
{
"type": "topology.details/resource-link",
"properties": {
"priority": 1000,
"link": { "$codeRef": "helmTopology.getHelmReleasePanelResourceLink" }
},
"flags": {
"required": ["OPENSHIFT_HELM"]
}
},
{
"type": "topology.details/tab",
"properties": {
"id": "helm-release-panel-tab-details",
"label": "%helm-plugin~Details%",
"insertBefore": "helm-release-panel-tab-resource"
},
"flags": {
"required": ["OPENSHIFT_HELM"]
}
},
{
"type": "topology.details/tab",
"properties": {
"id": "helm-release-panel-tab-resource",
"label": "%helm-plugin~Resources%",
"insertBefore": "helm-release-panel-tab-releaseNotes",
"insertAfter": "helm-release-panel-tab-details"
},
"flags": {
"required": ["OPENSHIFT_HELM"]
}
},
{
"type": "topology.details/tab",
"properties": {
"id": "helm-release-panel-tab-releaseNotes",
"label": "%helm-plugin~Release notes%",
"insertAfter": "helm-release-panel-tab-resource"
},
"flags": {
"required": ["OPENSHIFT_HELM"]
}
},
{
"type": "topology.details/tab-section",
"properties": {
"id": "helm-release-panel-tab-section-details",
"tab": "helm-release-panel-tab-details",
"section": { "$codeRef": "helmTopology.getHelmReleasePanelDetailsTabSection" },
"insertBefore": "helm-release-panel-tab-section-resource"
},
"flags": {
"required": ["OPENSHIFT_HELM"]
}
},
{
"type": "topology.details/tab-section",
"properties": {
"id": "helm-release-panel-tab-section-resource",
"tab": "helm-release-panel-tab-resource",
"section": { "$codeRef": "helmTopology.getHelmReleasePanelResourceTabSection" },
"insertAfter": "helm-release-panel-tab-section-details",
"insertBefore": "helm-release-panel-tab-section-releaseNotes"
},
"flags": {
"required": ["OPENSHIFT_HELM"]
}
},
{
"type": "topology.details/tab-section",
"properties": {
"id": "helm-release-panel-tab-section-releaseNotes",
"tab": "helm-release-panel-tab-releaseNotes",
"section": { "$codeRef": "helmTopology.getHelmReleasePanelReleaseNotesTabSection" },
"insertAfter": "helm-release-panel-tab-section-resource"
},
"flags": {
"required": ["OPENSHIFT_HELM"]
}
}
]
3 changes: 2 additions & 1 deletion frontend/packages/helm-plugin/package.json
Expand Up @@ -13,7 +13,8 @@
"exposedModules": {
"icons": "src/utils/icons.ts",
"catalog": "src/catalog",
"actions": "src/actions"
"actions": "src/actions",
"helmTopology": "src/topology/sidebar"
}
}
}
@@ -1,7 +1,8 @@
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { ResourceSummary, SectionHeading } from '@console/internal/components/utils';
import { K8sResourceKind } from '@console/internal/module/k8s';
import { ResourceSummary } from '@console/internal/components/utils/details-page';
import { SectionHeading } from '@console/internal/components/utils/headings';
import { K8sResourceKind } from '@console/internal/module/k8s/types';
import { HelmRelease } from '../../../types/helm-types';
import HelmChartSummary from './HelmChartSummary';

Expand Down
@@ -0,0 +1 @@
export * from './release-panel';
@@ -0,0 +1,6 @@
export { default as getHelmReleasePanelResourceLink } from './resource-link';
export {
useHelmReleasePanelDetailsTabSection as getHelmReleasePanelDetailsTabSection,
useHelmReleasePanelReleaseNotesTabSection as getHelmReleasePanelReleaseNotesTabSection,
useHelmReleasePanelResourceTabSection as getHelmReleasePanelResourceTabSection,
} from './tab-sections';
@@ -0,0 +1,27 @@
import * as React from 'react';
import { GraphElement, Node } from '@patternfly/react-topology';
import { Link } from 'react-router-dom';
import { ResourceIcon } from '@console/internal/components/utils/resource-icon';
import { getResource } from '@console/topology/src/utils';
import { TYPE_HELM_RELEASE } from '../../components/const';

const helmReleasePanelResourceLink = (element: GraphElement) => {
if (element.getType() !== TYPE_HELM_RELEASE) return undefined;
const name = element.getLabel();
const { namespace } = getResource(element as Node).metadata;
return (
<>
<ResourceIcon className="co-m-resource-icon--lg" kind="HelmRelease" />
{name && (
<Link
to={`/helm-releases/ns/${namespace}/release/${name}`}
className="co-resource-item__resource-name"
>
{name}
</Link>
)}
</>
);
};

export default helmReleasePanelResourceLink;
@@ -0,0 +1,51 @@
import * as React from 'react';
import { GraphElement, Node } from '@patternfly/react-topology';
import { useTranslation } from 'react-i18next';
import { StatusBox } from '@console/internal/components/utils/status-box';
import TopologyGroupResourcesPanel from '@console/topology/src/components/side-bar/TopologyGroupResourcesPanel';
import { getResource } from '@console/topology/src/utils';
import HelmReleaseOverview from '../../../components/details-page/overview/HelmReleaseOverview';
import { TYPE_HELM_RELEASE } from '../../components/const';
import TopologyHelmReleaseNotesPanel from '../../TopologyHelmReleaseNotesPanel';

export const useHelmReleasePanelDetailsTabSection = (element: GraphElement) => {
const { t } = useTranslation();
if (element.getType() !== TYPE_HELM_RELEASE) return undefined;
const secret = element.getData().resources.obj;
return !secret ? (
<>
<StatusBox
loaded
loadError={{
message: t('helm-plugin~Unable to find resource for {{helmLabel}}', {
helmLabel: element.getLabel(),
}),
}}
/>
<p>Status Box</p>
</>
) : (
<HelmReleaseOverview obj={secret} customData={undefined} />
);
};

export const useHelmReleasePanelResourceTabSection = (element: GraphElement) => {
if (element.getType() !== TYPE_HELM_RELEASE) return undefined;
const { manifestResources } = element.getData().data;
const { namespace } = getResource(element as Node).metadata;

return manifestResources ? (
<div className="overview__sidebar-pane-body">
<TopologyGroupResourcesPanel
manifestResources={manifestResources}
releaseNamespace={namespace}
/>
</div>
) : null;
};

export const useHelmReleasePanelReleaseNotesTabSection = (element: GraphElement) => {
if (element.getType() !== TYPE_HELM_RELEASE) return undefined;
const { releaseNotes } = element.getData().data;
return <TopologyHelmReleaseNotesPanel releaseNotes={releaseNotes} />;
};
Expand Up @@ -6,7 +6,7 @@ import TopologyGroupResourceList from './TopologyGroupResourceList';
type TopologyGroupResourcesPanelProps = {
manifestResources: K8sResourceKind[];
releaseNamespace: string;
linkForResource?: (obj: K8sResourceKind) => React.ReactElement;
linkForResource?: (obj) => React.ReactElement;
};

const TopologyGroupResourcesPanel: React.SFC<TopologyGroupResourcesPanelProps> = ({
Expand All @@ -29,7 +29,7 @@ const TopologyGroupResourcesPanel: React.SFC<TopologyGroupResourcesPanelProps> =
const resources = manifestResources.filter((resource) => resource.kind === model.kind);
if (resources.length) {
lists.push(
<div key={model.kind}>
<div key={'kind'}>
<SidebarSectionHeading text={model.labelPlural} />
<TopologyGroupResourceList
resources={resources}
Expand Down
@@ -0,0 +1,15 @@
import * as React from 'react';
import { GraphElement } from '@patternfly/react-topology';
import SideBarBody from './components/SideBarBody';
import SideBarHeading from './components/SideBarHeading';

const TopologySideBarContent: React.FC<{ element: GraphElement }> = ({ element }) => {
return (
<div className="overview__sidebar-pane resource-overview">
<SideBarHeading element={element} />
<SideBarBody element={element} />
</div>
);
};

export default TopologySideBarContent;
@@ -0,0 +1,60 @@
import * as React from 'react';
import { Alert, AlertActionCloseButton } from '@patternfly/react-core';
import { GraphElement } from '@patternfly/react-topology';
import {
DetailsResourceAlert,
DetailsResourceAlertContent,
isDetailsResourceAlert,
useResolvedExtensions,
} from '@console/dynamic-plugin-sdk';

const ResolveResourceAlerts: React.FC<{
id?: string;
dismissible?: boolean;
title?: string;
useResourceAlertsContent?: (element: GraphElement) => DetailsResourceAlertContent;
element: GraphElement;
}> = ({ title, dismissible = false, useResourceAlertsContent, element }) => {
const [showAlert, setShowAlert] = React.useState<boolean>(true);
const alertConfigs = useResourceAlertsContent(element);
if (!alertConfigs) return null;
const { variant, content, actionLinks, onClose } = alertConfigs;
return showAlert ? (
<Alert
isInline
variant={variant}
title={title}
actionLinks={actionLinks}
actionClose={
<AlertActionCloseButton
onClose={() => {
if (dismissible) setShowAlert(false);
else onClose?.();
}}
/>
}
>
{content}
</Alert>
) : null;
};

const SideBarAlerts: React.FC<{ element: GraphElement }> = ({ element }) => {
const [resourceAlertsExtension, resolved] = useResolvedExtensions<DetailsResourceAlert>(
isDetailsResourceAlert,
);
return resolved ? (
<>
{resourceAlertsExtension.map(({ uid, properties: { contentProvider, ...props } }) => (
<ResolveResourceAlerts
key={uid}
{...props}
useResourceAlertsContent={contentProvider}
element={element}
/>
))}
</>
) : null;
};

export default SideBarAlerts;
@@ -0,0 +1,22 @@
import * as React from 'react';
import { GraphElement } from '@patternfly/react-topology';
import { SimpleTabNav } from '@console/internal/components/utils';
import SideBarTabLoader from '../providers/SideBarTabLoader';

const SideBarBody: React.FC<{ element: GraphElement }> = ({ element }) => {
return (
<SideBarTabLoader element={element}>
{(tabs, loaded) =>
loaded ? (
<SimpleTabNav
tabs={tabs}
tabProps={null}
additionalClassNames="co-m-horizontal-nav__menu--within-sidebar co-m-horizontal-nav__menu--within-overview-sidebar"
/>
) : null
}
</SideBarTabLoader>
);
};

export default SideBarBody;
@@ -0,0 +1,3 @@
.topology-sidebar-alert {
margin: 0 20px var(--pf-global--spacer--md);
}
@@ -0,0 +1,22 @@
import * as React from 'react';
import { GraphElement } from '@patternfly/react-topology';
import { useDetailsResourceLink } from '../providers/useDetailsResourceLink';
import SideBarAlerts from './SideBarAlerts';
import './SideBarHeading.scss';

const SideBarHeading: React.FC<{ element: GraphElement }> = ({ element }) => {
const resourceLink = useDetailsResourceLink(element);
return (
<div className="overview__sidebar-pane-head resource-overview__heading">
<h1 className="co-m-pane__heading">
<div className="co-m-pane__name co-resource-item">{resourceLink}</div>
<div className="co-actions">{/** actions */}</div>
</h1>
<div className="topology-sidebar-alert">
<SideBarAlerts element={element} />
</div>
</div>
);
};

export default SideBarHeading;
Expand Up @@ -4,7 +4,6 @@ import {
TYPE_HELM_RELEASE,
TYPE_HELM_WORKLOAD,
} from '@console/helm-plugin/src/topology/components/const';
import TopologyHelmReleasePanel from '@console/helm-plugin/src/topology/TopologyHelmReleasePanel';
import TopologyHelmWorkloadPanel from '@console/helm-plugin/src/topology/TopologyHelmWorkloadPanel';
import KnativeResourceOverviewPage from '@console/knative-plugin/src/components/overview/KnativeResourceOverviewPage';
import KnativeTopologyEdgePanel from '@console/knative-plugin/src/components/overview/KnativeTopologyEdgePanel';
Expand All @@ -16,6 +15,7 @@ import {
} from '@console/knative-plugin/src/topology/const';
import { TYPE_VIRTUAL_MACHINE } from '@console/kubevirt-plugin/src/topology/components/const';
import TopologyVmPanel from '@console/kubevirt-plugin/src/topology/TopologyVmPanel';
// import TopologyHelmReleasePanel from '@console/helm-plugin/src/topology/TopologyHelmReleasePanel';
import { TYPE_MANAGED_KAFKA_CONNECTION } from '@console/rhoas-plugin/src/topology/components/const';
import TopologyKafkaPanel from '@console/rhoas-plugin/src/topology/components/TopologyKafkaPanel';
import { TYPE_APPLICATION_GROUP, TYPE_SERVICE_BINDING } from '../../const';
Expand All @@ -28,6 +28,7 @@ import { TopologyDataObject } from '../../topology-types';
import TopologyApplicationPanel from '../application-panel/TopologyApplicationPanel';
import ConnectedTopologyEdgePanel from './TopologyEdgePanel';
import TopologyResourcePanel from './TopologyResourcePanel';
import TopologySideBarContent from './TopologySideBarContent';

export const getSelectedEntityDetails = (selectedEntity: GraphElement) => {
if (!selectedEntity) {
Expand All @@ -47,9 +48,8 @@ export const getSelectedEntityDetails = (selectedEntity: GraphElement) => {
/>
);
}
// TODO: Use Plugins
if (selectedEntity.getType() === TYPE_HELM_RELEASE) {
return <TopologyHelmReleasePanel helmRelease={selectedEntity} />;
return <TopologySideBarContent element={selectedEntity} />;
}
if (selectedEntity.getType() === TYPE_MANAGED_KAFKA_CONNECTION) {
return <TopologyKafkaPanel item={selectedEntity} />;
Expand Down

0 comments on commit bae8517

Please sign in to comment.