diff --git a/.vscode/settings.json b/.vscode/settings.json index fa0a104..508cefe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,8 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "typescript.tsc.autoDetect": "off", + "cSpell.words": [ + "klusterlet" + ] } diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx index 924eb7b..f18c0d2 100644 --- a/webview-ui/src/App.tsx +++ b/webview-ui/src/App.tsx @@ -1,11 +1,10 @@ import React from "react"; import ShowSelectedContext from "./comp/SelectedContext"; -import ShowKlusterlets from "./comp/Klusterlets"; -import ShowAppliedManifestWorks from "./comp/AppliedManifestWorks"; -import ShowSubscriptionStatuses from "./comp/SubscriptionStatuses"; + import OcmHeader from "./comp/Header"; import { Page, PageSection } from "@patternfly/react-core"; import ClusterManagerPage from "./parent/clusterManagerParent"; +import ManagedClusterPage from "./parent/managedClusterParent"; @@ -20,11 +19,8 @@ export default class App extends React.Component { header= { } > - - - - - + + ) diff --git a/webview-ui/src/common/Graph.tsx b/webview-ui/src/common/Graph.tsx index 7ee2eca..15a6e30 100644 --- a/webview-ui/src/common/Graph.tsx +++ b/webview-ui/src/common/Graph.tsx @@ -31,7 +31,7 @@ const resourceTranslationMap:ResourceObject = { configmap: 'cm', secret: 'secret', ingress: 'ing', - serviceaccount: 'sa', + serviceaccount: 'sa', cronjob: 'cronjob', endpoint: 'ep', limitrange: 'limits', @@ -67,14 +67,16 @@ export const Graph: React.FC = ({ data ,images }) => { namespace: data.namespace, children: data.children.map(mf => { images.forEach( (image: kubeImage) => { - let field = mf.kind.toLowerCase() - let shortKind = resourceTranslationMap[field] - if (shortKind === image.name.toLowerCase()) { + if (resourceTranslationMap[mf.kind.toLowerCase()] === image.name.toLowerCase()) { mf.icon = image.uri return mf + } + else if (resourceTranslationMap[mf.kind.toLowerCase().slice(0, -1)] === image.name.toLowerCase()) { + mf.icon = image.uri + return mf } return mf - }) + }) return mf }) } diff --git a/webview-ui/src/comp/AppliedManifestWorks.tsx b/webview-ui/src/comp/AppliedManifestWorks.tsx index 9ab3683..8674321 100644 --- a/webview-ui/src/comp/AppliedManifestWorks.tsx +++ b/webview-ui/src/comp/AppliedManifestWorks.tsx @@ -1,21 +1,19 @@ -import { useState, useEffect } from 'react'; import { OcmResource } from '../../../src/data/loader' import { Gallery, Title } from '@patternfly/react-core'; import GalleryTableComponent from '../common/ConditionTable'; -import {DateFormat} from '../common/common' -export default function ShowAppliedManifestWorks() { - let [appliedManifestWorks, setAppliedManifestWorks] = useState([]); +import {DateFormat, kubeImage} from '../common/common' +import Graph from '../common/Graph'; - useEffect(() => { - window.addEventListener("message", event => { - if ('crsDistribution' in event.data.msg && 'AppliedManifestWork' === event.data.msg.crsDistribution.kind) { - setAppliedManifestWorks(JSON.parse(event.data.msg.crsDistribution.crs)); - } - }); - }); - const AppliedResourcesColumn: Object[] = [ - +type AppliedManifestWorksProps = { + appliedManifestWorks: OcmResource[], + kubeImages: kubeImage[] +} + +export default function ShowAppliedManifestWorks(Props:AppliedManifestWorksProps) { + + + const AppliedResourcesColumn: Object[] = [ {title: "Resource Name",}, {title: "Resource"}, {title: "Group" , }, @@ -23,15 +21,18 @@ export default function ShowAppliedManifestWorks() { ] return (
- { appliedManifestWorks.length > 0 && - <> + { Props.appliedManifestWorks.length > 0 && + <> + Applied ManifestWorks - {appliedManifestWorks.map(appliedManifestWork => { + {Props.appliedManifestWorks.map(appliedManifestWork => { + console.log(`appliedManifestWork`) + console.log(appliedManifestWork) const row = appliedManifestWork.kr.status.appliedResources.map( (resource:any) => { return [ resource.name, resource.resource, resource.group, resource.namespace] }) - + return + > + { + + return { + group: appliedResources.group, + name: appliedResources.name, + namespace: appliedResources.namespace, + kind: appliedResources.resource, + version: appliedResources.version + } + }) + } } images={Props.kubeImages} + /> + } )} diff --git a/webview-ui/src/comp/ClusterManagerDashboard.tsx b/webview-ui/src/comp/ClusterManagerDashboard.tsx index df439f5..71deb00 100644 --- a/webview-ui/src/comp/ClusterManagerDashboard.tsx +++ b/webview-ui/src/comp/ClusterManagerDashboard.tsx @@ -1,4 +1,6 @@ -import { Panel, PanelMain, PanelMainBody } from "@patternfly/react-core" +import { Divider, Flex, FlexItem, Icon, Panel, PanelMain, PanelMainBody } from "@patternfly/react-core" +import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon' +import TopologyIcon from '@patternfly/react-icons/dist/esm/icons/topology-icon' import { OcmResource } from "../../../src/data/loader" import { kubeImage } from "../common/common" @@ -21,14 +23,35 @@ type ClusterManagerDashboardProps = { export default function ClusterManagerDashboard( Props: ClusterManagerDashboardProps) { return( - + { (Props.data.clusterManagers && Props.data.clusterManagers.length > 0) && - - { Props.data.clusterManagers?

Hub Clusters: {Props.data.clusterManagers.length}

:null} - { Props.data.managedClusters?

Managed Clusters: {Props.data.managedClusters.length}

:null} - { Props.data.managedClusterSets?

managedClusterSets: {Props.data.managedClusterSets.length}

:null} - { Props.data.placements?

Placements: {Props.data.placements.length}

:null} + + + + + + + { Props.data.clusterManagers?

Hub Clusters: {Props.data.clusterManagers.length}

:null} + { Props.data.managedClusters?

Managed Clusters: {Props.data.managedClusters.length}

:null} + +
+ + + + + + { Props.data.placements?

Placements: {Props.data.placements.length}

:null} + { Props.data.managedClusterSets?

managedClusterSets: {Props.data.managedClusterSets.length}

:null} + +
+
} diff --git a/webview-ui/src/comp/Klusterlets.tsx b/webview-ui/src/comp/Klusterlet.tsx similarity index 66% rename from webview-ui/src/comp/Klusterlets.tsx rename to webview-ui/src/comp/Klusterlet.tsx index 9411692..ad2b8a7 100644 --- a/webview-ui/src/comp/Klusterlets.tsx +++ b/webview-ui/src/comp/Klusterlet.tsx @@ -1,21 +1,17 @@ -import { useState, useEffect } from 'react'; import { OcmResource } from '../../../src/data/loader' import { ConditionTableComponent } from '../common/ConditionTable'; import { DateFormat } from '../common/common'; import { OcmLabels } from '../common/Labels'; -export default function ShowKlusterlets() { - let [klusterlets, setKlusterlets] = useState([]); +type klusterletProps = { + klusterlet: OcmResource[] +} + +export default function ShowKlusterlet(Props: klusterletProps) { + - useEffect(() => { - window.addEventListener("message", event => { - if ('crsDistribution' in event.data.msg && 'Klusterlet' === event.data.msg.crsDistribution.kind) { - setKlusterlets(JSON.parse(event.data.msg.crsDistribution.crs)); - } - }); - }); - const row = klusterlets.map(klusterlet => { + const row = Props.klusterlet.map(klusterlet => { return klusterlet.kr.status.conditions.map( (condition:any) => { return [new Date(condition.lastTransitionTime).toLocaleString("en-US",DateFormat), condition.message, @@ -26,11 +22,11 @@ export default function ShowKlusterlets() { }) return ( //TODO-Add panel - //TODO-add clusterlet dashboard + //TODO-add Klusterlet dashboard
- { klusterlets.length > 0 && + { Props.klusterlet.length > 0 && <> - {klusterlets.map(klusterlet => { + {Props.klusterlet.map(klusterlet => { return <> {klusterlet.kr.metadata.labels?:null } diff --git a/webview-ui/src/comp/ManagedClusterSets.tsx b/webview-ui/src/comp/ManagedClusterSets.tsx index 0aabc8c..c9a325e 100644 --- a/webview-ui/src/comp/ManagedClusterSets.tsx +++ b/webview-ui/src/comp/ManagedClusterSets.tsx @@ -21,8 +21,6 @@ export default function ShowManagedClusterSets(Props: managedClusterSetsProps) { {Props.managedClusterSets.map(managedClusterSet => { - console.log(`managedClusterSet`) - console.log(managedClusterSet) const code = yaml.dump(managedClusterSet.kr.spec.clusterSelector) const row = managedClusterSet.kr.status.conditions.map( (condition:any) => { return [new Date(condition.lastTransitionTime).toLocaleString("en-US",DateFormat), diff --git a/webview-ui/src/comp/SubscriptionReports.tsx b/webview-ui/src/comp/SubscriptionReports.tsx index 599be96..93ab813 100644 --- a/webview-ui/src/comp/SubscriptionReports.tsx +++ b/webview-ui/src/comp/SubscriptionReports.tsx @@ -29,14 +29,19 @@ export default function ShowSubscriptionReports(Props: SubscriptionReportsProps) {Props.subscriptionReports.map( subscriptionReport => { - const rows = [[subscriptionReport.kr.summary.clusters, - subscriptionReport.kr.summary.deployed, - subscriptionReport.kr.summary.failed, - subscriptionReport.kr.summary.inProgress, - subscriptionReport.kr.summary.propagationFailed - ]] - - console.log(rows) + console.log(`subscriptionReport`) + console.log(subscriptionReport) + + let rows = [[0,0,0,0,0]] + + if (subscriptionReport.kr.summary && subscriptionReport.kr.summary.clusters > -1 ) { + rows = [[subscriptionReport.kr.summary.clusters, + subscriptionReport.kr.summary.deployed, + subscriptionReport.kr.summary.failed, + subscriptionReport.kr.summary.inProgress, + subscriptionReport.kr.summary.propagationFailed + ]] + } return @@ -45,21 +50,19 @@ export default function ShowSubscriptionReports(Props: SubscriptionReportsProps) Namespace: {subscriptionReport.kr.metadata.namespace?subscriptionReport.kr.metadata.namespace:'missing namespace'} +

Report Type: {subscriptionReport.kr.reportType}

+ {/*TODO add placement name and chanel */}
-
- - -
})} diff --git a/webview-ui/src/comp/SubscriptionStatuses.tsx b/webview-ui/src/comp/SubscriptionStatuses.tsx index 22d65de..99c3831 100644 --- a/webview-ui/src/comp/SubscriptionStatuses.tsx +++ b/webview-ui/src/comp/SubscriptionStatuses.tsx @@ -1,39 +1,49 @@ -import { VSCodeDataGrid, VSCodeDataGridCell, VSCodeDataGridRow, } from '@vscode/webview-ui-toolkit/react'; -import { useState, useEffect } from 'react'; import { OcmResource } from '../../../src/data/loader' -import { Title } from '@patternfly/react-core'; +import { Gallery, Title } from '@patternfly/react-core'; +import GalleryTableComponent from '../common/ConditionTable'; -export default function ShowSubscriptionStatuses() { - let [subscriptionStatuses, setSubscriptionStatuses] = useState([]); +type SubscriptionStatusesProps ={ + subscriptionStatuses: OcmResource[], + subscription: OcmResource[], +} - useEffect(() => { - window.addEventListener("message", event => { - if ('crsDistribution' in event.data.msg && 'SubscriptionStatus' === event.data.msg.crsDistribution.kind) { - setSubscriptionStatuses(JSON.parse(event.data.msg.crsDistribution.crs)); - } - }); - }); +const SubscriptionStatusesColumns: Object[] = [ + {title: "kind" ,}, + {title: "LastUpdateTime", }, + {title: "Name" }, + {title: "Namespace" }, + {title: "PropagationFailed" } +] + +export default function ShowSubscriptionStatuses(Props: SubscriptionStatusesProps) { return (
- { subscriptionStatuses.length >0 && + { Props.subscriptionStatuses.length >0 && <> Subscription Status - - - Subscription Name - Report Type - - - {subscriptionStatuses.map(subscriptionStatus => { - return - {subscriptionStatus.kr.metadata.name} - {subscriptionStatus.kr.statuses.packages.map( ( pkg:any )=> { return

- kind: {pkg.kind}, lastUpdateTime: {pkg.lastUpdateTime}, name: {pkg.name}, namespace: {pkg.namespace}, phase: {pkg.phase}

})}
-
- } ) - } -
+ + {Props.subscriptionStatuses.map(subscriptionStatus => { + console.log(`subscriptionStatus`) + console.log(subscriptionStatus) + return {return [ pkg.kind, + pkg.lastUpdateTime, + pkg.name, + pkg.namespace, + pkg.phase + ]} + ) } + cells={SubscriptionStatusesColumns} + id={`${subscriptionStatus.kr.metadata.name}`} + > +

Namespace: {subscriptionStatus.namespace}

+
+ } + )}
+
}
diff --git a/webview-ui/src/parent/clusterManagerParent.tsx b/webview-ui/src/parent/clusterManagerParent.tsx index 5cb394a..876f2e9 100644 --- a/webview-ui/src/parent/clusterManagerParent.tsx +++ b/webview-ui/src/parent/clusterManagerParent.tsx @@ -94,8 +94,8 @@ export default function ClusterManagerPage(){ clusterManagersDataRef.current = newClusterManagersData },[kubeImages]); - if(dataRequests.current > 15 ){ - return (<> {console.log(dataRequests)} + if(dataRequests.current > 35 ){ + return (<> @@ -108,9 +108,11 @@ export default function ClusterManagerPage(){ ) } - else { - return( - + else if(clusterManagersRef.current.length === 0 ) { + return <> + } + else { + return ( ) } diff --git a/webview-ui/src/parent/managedClusterParent.tsx b/webview-ui/src/parent/managedClusterParent.tsx new file mode 100644 index 0000000..762c44a --- /dev/null +++ b/webview-ui/src/parent/managedClusterParent.tsx @@ -0,0 +1,78 @@ +import { useState, useEffect, useRef} from 'react'; +import { OcmResource } from '../../../src/data/loader' +import { kubeImage } from '../common/common'; +import { Spinner } from '@patternfly/react-core'; +import ShowSubscriptionStatuses from '../comp/SubscriptionStatuses'; +import ShowAppliedManifestWorks from '../comp/AppliedManifestWorks'; +import ShowKlusterlet from '../comp/Klusterlet'; + +export default function ManagedClusterPage(){ + let [kubeImages, setKubeImages] = useState([]); + let dataRequests = useRef(0); + let klusterletRef = useRef([]); + let appliedManifestWorkRef = useRef([]); + let managedClusterSetsRef = useRef([]); + let subscriptionStatusRef = useRef([]); + let subscriptionRef = useRef([]); + let kubeImagesRef = useRef([]); + + useEffect(() => { + dataRequests.current += 1 + + window.addEventListener("message", event => { + if ('crsDistribution' in event.data.msg) { + dataRequests.current += 1 + let crsData = JSON.parse(event.data.msg.crsDistribution.crs) + switch (event.data.msg.crsDistribution.kind) { + case 'Klusterlet' : + klusterletRef.current = crsData; + break; + case 'AppliedManifestWork': + if (appliedManifestWorkRef.current.length !== crsData.length) { + appliedManifestWorkRef.current = crsData; + } + break; + case 'ManagedClusterSet': + if (managedClusterSetsRef.current.length !== crsData.length) { + managedClusterSetsRef.current = crsData ; + } + break; + case 'SubscriptionStatus': + if (subscriptionStatusRef.current.length !== crsData.length) { + subscriptionStatusRef.current = crsData ; + } + break; + case 'Subscription': + if (subscriptionRef.current.length !== crsData.length) { + subscriptionRef.current = crsData ; + } + break; + } + if (event.data.images) { + if (event.data.images) { + //TODO move this logic to Graph + kubeImagesRef.current = event.data.images + //setting the image state re-renders the component + setKubeImages(kubeImagesRef.current) + } + } + } + }); + },[kubeImages]); + + if(dataRequests.current > 5 ){ + return (<> + + + + + ) + } + + + else { + return ( + ) + } + +} \ No newline at end of file