1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

refactor(kube/volumes): migrate to react [EE-4695] (#10987)

This commit is contained in:
Chaim Lev-Ari 2024-04-02 22:10:22 +03:00 committed by GitHub
parent 2b53bebcb3
commit da615afc92
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 347 additions and 397 deletions

View file

@ -0,0 +1,94 @@
import { Database } from 'lucide-react';
import { useAuthorizations } from '@/react/hooks/useUser';
import KubernetesVolumeHelper from '@/kubernetes/helpers/volumeHelper';
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
import { refreshableSettings } from '@@/datatables/types';
import { Datatable, TableSettingsMenu } from '@@/datatables';
import { useTableStateWithStorage } from '@@/datatables/useTableState';
import { DeleteButton } from '@@/buttons/DeleteButton';
import { useRepeater } from '@@/datatables/useRepeater';
import { systemResourcesSettings } from '../../datatables/SystemResourcesSettings';
import { CreateFromManifestButton } from '../../components/CreateFromManifestButton';
import {
DefaultDatatableSettings,
TableSettings,
} from '../../datatables/DefaultDatatableSettings';
import { SystemResourceDescription } from '../../datatables/SystemResourceDescription';
import { useNamespacesQuery } from '../../namespaces/queries/useNamespacesQuery';
import { VolumeViewModel } from './types';
import { columns } from './columns';
export function VolumesDatatable({
dataset,
onRemove,
onRefresh,
}: {
dataset: Array<VolumeViewModel>;
onRemove(items: Array<VolumeViewModel>): void;
onRefresh(): void;
}) {
const tableState = useTableStateWithStorage<TableSettings>(
'kube-volumes',
'Name',
(set) => ({
...systemResourcesSettings(set),
...refreshableSettings(set),
})
);
const hasWriteAuth = useAuthorizations('K8sVolumesW', undefined, true);
useRepeater(tableState.autoRefreshRate, onRefresh);
const envId = useEnvironmentId();
const namespaceListQuery = useNamespacesQuery(envId);
const filteredDataset = tableState.showSystemResources
? dataset
: dataset.filter((item) => !isSystem(item));
return (
<Datatable
noWidget
data-cy="k8s-volumes-datatable"
dataset={filteredDataset}
columns={columns}
settingsManager={tableState}
title="Volumes"
titleIcon={Database}
isRowSelectable={({ original: item }) =>
hasWriteAuth &&
!(isSystem(item) && !KubernetesVolumeHelper.isUsed(item))
}
renderTableActions={(selectedItems) => (
<>
<DeleteButton
confirmMessage="Do you want to remove the selected volume(s)?"
onConfirmed={() => onRemove(selectedItems)}
disabled={selectedItems.length === 0}
/>
<CreateFromManifestButton />
</>
)}
renderTableSettings={() => (
<TableSettingsMenu>
<DefaultDatatableSettings settings={tableState} />
</TableSettingsMenu>
)}
description={
<SystemResourceDescription
showSystemResources={tableState.showSystemResources}
/>
}
/>
);
function isSystem(item: VolumeViewModel) {
return !!namespaceListQuery.data?.[item.ResourcePool.Namespace.Name]
.IsSystem;
}
}

View file

@ -0,0 +1,5 @@
import { createColumnHelper } from '@tanstack/react-table';
import { VolumeViewModel } from './types';
export const helper = createColumnHelper<VolumeViewModel>();

View file

@ -0,0 +1,49 @@
import { CellContext } from '@tanstack/react-table';
import KubernetesVolumeHelper from '@/kubernetes/helpers/volumeHelper';
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
import { Link } from '@@/Link';
import { SystemBadge } from '@@/Badge/SystemBadge';
import { ExternalBadge } from '@@/Badge/ExternalBadge';
import { UnusedBadge } from '@@/Badge/UnusedBadge';
import { useNamespacesQuery } from '../../namespaces/queries/useNamespacesQuery';
import { VolumeViewModel } from './types';
import { helper } from './columns.helper';
export const name = helper.accessor('PersistentVolumeClaim.Name', {
header: 'Name',
cell: NameCell,
});
export function NameCell({
row: { original: item },
}: CellContext<VolumeViewModel, string>) {
const envId = useEnvironmentId();
const namespaceListQuery = useNamespacesQuery(envId);
const isSystem =
namespaceListQuery.data?.[item.ResourcePool.Namespace.Name].IsSystem;
return (
<>
<Link
to="kubernetes.volumes.volume"
params={{
namespace: item.ResourcePool.Namespace.Name,
name: item.PersistentVolumeClaim.Name,
}}
>
{item.PersistentVolumeClaim.Name}
</Link>
{isSystem ? (
<SystemBadge />
) : (
<>
{KubernetesVolumeHelper.isExternalVolume(item) && <ExternalBadge />}
{!KubernetesVolumeHelper.isUsed(item) && <UnusedBadge />}
</>
)}
</>
);
}

View file

@ -0,0 +1,67 @@
import { isoDate } from '@/portainer/filters/filters';
import { Link } from '@@/Link';
import { name } from './columns.name';
import { helper } from './columns.helper';
export const columns = [
name,
helper.accessor('ResourcePool.Namespace.Name', {
header: 'Namespace',
cell: ({ getValue }) => {
const namespace = getValue();
return (
<Link
to="kubernetes.resourcePools.resourcePool"
params={{ id: namespace }}
>
{namespace}
</Link>
);
},
}),
helper.accessor((item) => item.Applications[0]?.Name, {
header: 'Used by',
cell: ({ row: { original: item } }) => {
if (!item.Applications.length) {
return '-';
}
return (
<>
<Link
to="kubernetes.applications.application"
params={{
name: item.Applications[0].Name,
namespace: item.ResourcePool.Namespace.Name,
}}
>
{item.Applications[0].Name}
</Link>
{item.Applications.length > 1 && (
<> + {item.Applications.length - 1}</>
)}
</>
);
},
}),
helper.accessor('PersistentVolumeClaim.storageClass.Name', {
header: 'Storage',
}),
helper.accessor('PersistentVolumeClaim.Storage', {
header: 'Size',
}),
helper.accessor('PersistentVolumeClaim.CreationDate', {
header: 'Created',
cell: ({ row: { original: item } }) => (
<>
{isoDate(item.PersistentVolumeClaim.CreationDate)}
{item.PersistentVolumeClaim.ApplicationOwner
? ` by ${item.PersistentVolumeClaim.ApplicationOwner}`
: ''}
</>
),
}),
];

View file

@ -0,0 +1,19 @@
export interface VolumeViewModel {
Applications: Array<{
Name: string;
}>;
PersistentVolumeClaim: {
Name: string;
storageClass: {
Name: string;
};
Storage?: unknown;
CreationDate: number;
ApplicationOwner?: string;
};
ResourcePool: {
Namespace: {
Name: string;
};
};
}