mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(docker/networks): migrate networks datatable to React [EE-4670] (#10351)
Co-authored-by: LP B <xAt0mZ@users.noreply.github.com>
This commit is contained in:
parent
0dc1805881
commit
b933bee95e
17 changed files with 333 additions and 440 deletions
20
app/react/docker/networks/ListView/NestedNetwordsTable.tsx
Normal file
20
app/react/docker/networks/ListView/NestedNetwordsTable.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
|
||||
import { NestedDatatable } from '@@/datatables/NestedDatatable';
|
||||
|
||||
import { useIsSwarm } from '../../proxy/queries/useInfo';
|
||||
|
||||
import { useColumns } from './columns';
|
||||
import { DecoratedNetwork } from './types';
|
||||
|
||||
export function NestedNetworksDatatable({
|
||||
dataset,
|
||||
}: {
|
||||
dataset: Array<DecoratedNetwork>;
|
||||
}) {
|
||||
const environmentId = useEnvironmentId();
|
||||
const isSwarm = useIsSwarm(environmentId);
|
||||
|
||||
const columns = useColumns(isSwarm);
|
||||
return <NestedDatatable columns={columns} dataset={dataset} />;
|
||||
}
|
113
app/react/docker/networks/ListView/NetworksDatatable.tsx
Normal file
113
app/react/docker/networks/ListView/NetworksDatatable.tsx
Normal file
|
@ -0,0 +1,113 @@
|
|||
import { Plus, Share2, Trash2 } from 'lucide-react';
|
||||
|
||||
import { Authorized } from '@/react/hooks/useUser';
|
||||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
|
||||
import { ExpandableDatatable } from '@@/datatables/ExpandableDatatable';
|
||||
import {
|
||||
BasicTableSettings,
|
||||
createPersistedStore,
|
||||
refreshableSettings,
|
||||
RefreshableTableSettings,
|
||||
} from '@@/datatables/types';
|
||||
import { Button } from '@@/buttons';
|
||||
import { TableSettingsMenu } from '@@/datatables';
|
||||
import { TableSettingsMenuAutoRefresh } from '@@/datatables/TableSettingsMenuAutoRefresh';
|
||||
import { useRepeater } from '@@/datatables/useRepeater';
|
||||
import { useTableState } from '@@/datatables/useTableState';
|
||||
import { Link } from '@@/Link';
|
||||
|
||||
import { useIsSwarm } from '../../proxy/queries/useInfo';
|
||||
|
||||
import { useColumns } from './columns';
|
||||
import { DecoratedNetwork } from './types';
|
||||
import { NestedNetworksDatatable } from './NestedNetwordsTable';
|
||||
|
||||
const storageKey = 'docker.networks';
|
||||
|
||||
interface TableSettings extends BasicTableSettings, RefreshableTableSettings {}
|
||||
|
||||
const settingsStore = createPersistedStore<TableSettings>(
|
||||
storageKey,
|
||||
'name',
|
||||
(set) => ({
|
||||
...refreshableSettings(set),
|
||||
})
|
||||
);
|
||||
|
||||
type DatasetType = Array<DecoratedNetwork>;
|
||||
interface Props {
|
||||
dataset: DatasetType;
|
||||
onRemove(selectedItems: DatasetType): void;
|
||||
onRefresh(): Promise<void>;
|
||||
}
|
||||
|
||||
export function NetworksDatatable({ dataset, onRemove, onRefresh }: Props) {
|
||||
const settings = useTableState(settingsStore, storageKey);
|
||||
|
||||
const environmentId = useEnvironmentId();
|
||||
const isSwarm = useIsSwarm(environmentId);
|
||||
|
||||
const columns = useColumns(isSwarm);
|
||||
|
||||
useRepeater(settings.autoRefreshRate, onRefresh);
|
||||
|
||||
return (
|
||||
<ExpandableDatatable<DecoratedNetwork>
|
||||
settingsManager={settings}
|
||||
title="Networks"
|
||||
titleIcon={Share2}
|
||||
dataset={dataset}
|
||||
columns={columns}
|
||||
getRowCanExpand={({ original: item }) =>
|
||||
!!(item.Subs && item.Subs?.length > 0)
|
||||
}
|
||||
isRowSelectable={({ original: item }) => !item.ResourceControl?.System}
|
||||
renderSubRow={(row) => (
|
||||
<>
|
||||
{row.original.Subs && (
|
||||
<tr>
|
||||
<td colSpan={Number.MAX_SAFE_INTEGER}>
|
||||
<NestedNetworksDatatable dataset={row.original.Subs} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
emptyContentLabel="No networks available."
|
||||
renderTableActions={(selectedRows) => (
|
||||
<div className="flex gap-3">
|
||||
<Authorized
|
||||
authorizations={['DockerNetworkDelete', 'DockerNetworkCreate']}
|
||||
>
|
||||
<Button
|
||||
disabled={selectedRows.length === 0}
|
||||
color="dangerlight"
|
||||
onClick={() => onRemove(selectedRows)}
|
||||
icon={Trash2}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
</Authorized>
|
||||
<Authorized
|
||||
authorizations="DockerNetworkCreate"
|
||||
data-cy="network-addNetworkButton"
|
||||
>
|
||||
<Button icon={Plus} as={Link} props={{ to: '.new' }}>
|
||||
Add network
|
||||
</Button>
|
||||
</Authorized>
|
||||
</div>
|
||||
)}
|
||||
renderTableSettings={() => (
|
||||
<TableSettingsMenu>
|
||||
<TableSettingsMenuAutoRefresh
|
||||
onChange={settings.setAutoRefreshRate}
|
||||
value={settings.autoRefreshRate}
|
||||
/>
|
||||
</TableSettingsMenu>
|
||||
)}
|
||||
getRowId={(row) => `${row.Name}-${row.Id}`}
|
||||
/>
|
||||
);
|
||||
}
|
5
app/react/docker/networks/ListView/columns/helper.ts
Normal file
5
app/react/docker/networks/ListView/columns/helper.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { createColumnHelper } from '@tanstack/react-table';
|
||||
|
||||
import { DecoratedNetwork } from '../types';
|
||||
|
||||
export const columnHelper = createColumnHelper<DecoratedNetwork>();
|
63
app/react/docker/networks/ListView/columns/index.ts
Normal file
63
app/react/docker/networks/ListView/columns/index.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
import _ from 'lodash';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { createOwnershipColumn } from '@/react/docker/components/datatable/createOwnershipColumn';
|
||||
|
||||
import { buildExpandColumn } from '@@/datatables/expand-column';
|
||||
|
||||
import { DecoratedNetwork } from '../types';
|
||||
|
||||
import { columnHelper } from './helper';
|
||||
import { name } from './name';
|
||||
|
||||
export function useColumns(isHostColumnVisible?: boolean) {
|
||||
return useMemo(
|
||||
() =>
|
||||
_.compact([
|
||||
buildExpandColumn<DecoratedNetwork>(),
|
||||
name,
|
||||
columnHelper.accessor((item) => item.StackName || '-', {
|
||||
header: 'Stack',
|
||||
}),
|
||||
columnHelper.accessor('Driver', {
|
||||
header: 'Driver',
|
||||
}),
|
||||
columnHelper.accessor('Attachable', {
|
||||
header: 'Attachable',
|
||||
}),
|
||||
columnHelper.accessor('IPAM.Driver', {
|
||||
header: 'IPAM Driver',
|
||||
}),
|
||||
columnHelper.accessor(
|
||||
(item) => item.IPAM?.IPV4Configs?.[0]?.Subnet ?? '-',
|
||||
{
|
||||
header: 'IPV4 IPAM Subnet',
|
||||
}
|
||||
),
|
||||
columnHelper.accessor(
|
||||
(item) => item.IPAM?.IPV4Configs?.[0]?.Gateway ?? '-',
|
||||
{
|
||||
header: 'IPV4 IPAM Gateway',
|
||||
}
|
||||
),
|
||||
columnHelper.accessor(
|
||||
(item) => item.IPAM?.IPV6Configs?.[0]?.Subnet ?? '-',
|
||||
{
|
||||
header: 'IPV6 IPAM Subnet',
|
||||
}
|
||||
),
|
||||
columnHelper.accessor(
|
||||
(item) => item.IPAM?.IPV6Configs?.[0]?.Gateway ?? '-',
|
||||
{
|
||||
header: 'IPV6 IPAM Gateway',
|
||||
}
|
||||
),
|
||||
isHostColumnVisible &&
|
||||
columnHelper.accessor('NodeName', {
|
||||
header: 'Node',
|
||||
}),
|
||||
createOwnershipColumn<DecoratedNetwork>(),
|
||||
]),
|
||||
[isHostColumnVisible]
|
||||
);
|
||||
}
|
31
app/react/docker/networks/ListView/columns/name.tsx
Normal file
31
app/react/docker/networks/ListView/columns/name.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { truncate } from '@/portainer/filters/filters';
|
||||
|
||||
import { Link } from '@@/Link';
|
||||
|
||||
import { columnHelper } from './helper';
|
||||
|
||||
export const name = columnHelper.accessor('Name', {
|
||||
header: 'Name',
|
||||
id: 'name',
|
||||
cell({ row: { original: item } }) {
|
||||
return (
|
||||
<>
|
||||
<Link
|
||||
to=".network"
|
||||
params={{ id: item.Id, nodeName: item.NodeName }}
|
||||
title={item.Name}
|
||||
>
|
||||
{truncate(item.Name, 40)}
|
||||
</Link>
|
||||
{item.ResourceControl?.System && (
|
||||
<span
|
||||
style={{ marginLeft: '10px' }}
|
||||
className="label label-info image-tag space-left"
|
||||
>
|
||||
System
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
},
|
||||
});
|
11
app/react/docker/networks/ListView/types.ts
Normal file
11
app/react/docker/networks/ListView/types.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { IPAMConfig } from 'docker-types/generated/1.41';
|
||||
|
||||
import { NetworkViewModel } from '@/docker/models/network';
|
||||
|
||||
export type DecoratedNetwork = NetworkViewModel & {
|
||||
Subs?: DecoratedNetwork[];
|
||||
IPAM: NetworkViewModel['IPAM'] & {
|
||||
IPV4Configs?: Array<IPAMConfig>;
|
||||
IPV6Configs?: Array<IPAMConfig>;
|
||||
};
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue