diff --git a/src/renderer/api/endpoints/persistent-volume.api.ts b/src/renderer/api/endpoints/persistent-volume.api.ts index 27a0279a0b..db286db062 100644 --- a/src/renderer/api/endpoints/persistent-volume.api.ts +++ b/src/renderer/api/endpoints/persistent-volume.api.ts @@ -70,6 +70,10 @@ export class PersistentVolume extends KubeObject { getClaimRefName(): string { return this.spec.claimRef?.name ?? ""; } + + getStorageClassName() { + return this.spec.storageClassName || ""; + } } export const persistentVolumeApi = new KubeApi({ diff --git a/src/renderer/components/+storage-classes/storage-class-details.tsx b/src/renderer/components/+storage-classes/storage-class-details.tsx index 4ee8a197f2..1d47df8ecb 100644 --- a/src/renderer/components/+storage-classes/storage-class-details.tsx +++ b/src/renderer/components/+storage-classes/storage-class-details.tsx @@ -10,14 +10,22 @@ import { KubeObjectDetailsProps } from "../kube-object"; import { StorageClass } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; +import { storageClassStore } from "./storage-class.store"; +import { VolumeDetailsList } from "../+storage-volumes/volume-details-list"; +import { volumesStore } from "../+storage-volumes/volumes.store"; interface Props extends KubeObjectDetailsProps { } @observer export class StorageClassDetails extends React.Component { + async componentDidMount() { + volumesStore.reloadAll(); + } + render() { const { object: storageClass } = this.props; + const persistentVolumes = storageClassStore.getPersistentVolumes(storageClass); if (!storageClass) return null; const { provisioner, parameters, mountOptions } = storageClass; @@ -55,6 +63,7 @@ export class StorageClassDetails extends React.Component { } )} + ); } diff --git a/src/renderer/components/+storage-classes/storage-class.store.ts b/src/renderer/components/+storage-classes/storage-class.store.ts index 9e388456a5..0050c432b5 100644 --- a/src/renderer/components/+storage-classes/storage-class.store.ts +++ b/src/renderer/components/+storage-classes/storage-class.store.ts @@ -2,10 +2,15 @@ import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { StorageClass, storageClassApi } from "../../api/endpoints/storage-class.api"; import { apiManager } from "../../api/api-manager"; +import { volumesStore } from "../+storage-volumes/volumes.store"; @autobind() export class StorageClassStore extends KubeObjectStore { api = storageClassApi; + + getPersistentVolumes(storageClass: StorageClass) { + return volumesStore.getByStorageClass(storageClass); + } } export const storageClassStore = new StorageClassStore(); diff --git a/src/renderer/components/+storage-volumes/volume-details-list.scss b/src/renderer/components/+storage-volumes/volume-details-list.scss new file mode 100644 index 0000000000..aed61b4b5f --- /dev/null +++ b/src/renderer/components/+storage-volumes/volume-details-list.scss @@ -0,0 +1,31 @@ +@import "../+storage/storage-mixins"; + +.VolumeDetailsList { + position: relative; + + .Table { + margin: 0 (-$margin * 3); + + &.virtual { + height: 500px; // applicable for 100+ items + } + } + + .TableCell { + &:first-child { + margin-left: $margin; + } + + &:last-child { + margin-right: $margin; + } + + &.name { + flex-grow: 2; + } + + &.status { + @include pv-status-colors; + } + } +} diff --git a/src/renderer/components/+storage-volumes/volume-details-list.tsx b/src/renderer/components/+storage-volumes/volume-details-list.tsx new file mode 100644 index 0000000000..91dbcf3dd1 --- /dev/null +++ b/src/renderer/components/+storage-volumes/volume-details-list.tsx @@ -0,0 +1,88 @@ +import "./volume-details-list.scss"; + +import React from "react"; +import { observer } from "mobx-react"; +import { PersistentVolume } from "../../api/endpoints/persistent-volume.api"; +import { autobind } from "../../../common/utils/autobind"; +import { TableRow } from "../table/table-row"; +import { cssNames, prevDefault } from "../../utils"; +import { showDetails } from "../kube-object/kube-object-details"; +import { TableCell } from "../table/table-cell"; +import { Spinner } from "../spinner/spinner"; +import { DrawerTitle } from "../drawer/drawer-title"; +import { Table } from "../table/table"; +import { TableHead } from "../table/table-head"; +import { volumesStore } from "./volumes.store"; +import kebabCase from "lodash/kebabCase"; + +interface Props { + persistentVolumes: PersistentVolume[]; +} + +enum sortBy { + name = "name", + status = "status", + capacity = "capacity", +} + +@observer +export class VolumeDetailsList extends React.Component { + private sortingCallbacks = { + [sortBy.name]: (volume: PersistentVolume) => volume.getName(), + [sortBy.capacity]: (volume: PersistentVolume) => volume.getCapacity(), + [sortBy.status]: (volume: PersistentVolume) => volume.getStatus(), + }; + + @autobind() + getTableRow(uid: string) { + const { persistentVolumes } = this.props; + const volume = persistentVolumes.find(volume => volume.getId() === uid); + + return ( + showDetails(volume.selfLink, false))} + > + {volume.getName()} + {volume.getCapacity()} + {volume.getStatus()} + + ); + } + + render() { + const { persistentVolumes } = this.props; + const virtual = persistentVolumes.length > 100; + + if (!persistentVolumes.length) { + return !volumesStore.isLoaded && ; + } + + return ( +
+ + + + Name + Capacity + Status + + { + !virtual && persistentVolumes.map(volume => this.getTableRow(volume.getId())) + } +
+
+ ); + } +} diff --git a/src/renderer/components/+storage-volumes/volumes.scss b/src/renderer/components/+storage-volumes/volumes.scss index 272aa3fd89..9aa1e616b1 100644 --- a/src/renderer/components/+storage-volumes/volumes.scss +++ b/src/renderer/components/+storage-volumes/volumes.scss @@ -26,7 +26,7 @@ flex-grow: 3; } - .status { + &.status { @include pv-status-colors; } diff --git a/src/renderer/components/+storage-volumes/volumes.store.ts b/src/renderer/components/+storage-volumes/volumes.store.ts index ea61525735..b2601f9b12 100644 --- a/src/renderer/components/+storage-volumes/volumes.store.ts +++ b/src/renderer/components/+storage-volumes/volumes.store.ts @@ -2,10 +2,17 @@ import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { PersistentVolume, persistentVolumeApi } from "../../api/endpoints/persistent-volume.api"; import { apiManager } from "../../api/api-manager"; +import { StorageClass } from "../../api/endpoints/storage-class.api"; @autobind() export class PersistentVolumesStore extends KubeObjectStore { api = persistentVolumeApi; + + getByStorageClass(storageClass: StorageClass): PersistentVolume[] { + return this.items.filter(volume => + volume.getStorageClassName() === storageClass.getName() + ); + } } export const volumesStore = new PersistentVolumesStore();