mirror of
https://github.com/portainer/portainer.git
synced 2025-07-24 07:49:41 +02:00
refactor(tables): use add and delete buttons [EE-6297] (#10668)
Co-authored-by: Chaim Lev-Ari <chaim.levi-ari@portaienr.io>
This commit is contained in:
parent
d88ef03ddb
commit
9600eb6fa1
41 changed files with 369 additions and 727 deletions
|
@ -1,13 +1,13 @@
|
|||
import { Clipboard, Plus, Trash2 } from 'lucide-react';
|
||||
import { Clipboard } from 'lucide-react';
|
||||
|
||||
import { Authorized, useAuthorizations } from '@/react/hooks/useUser';
|
||||
|
||||
import { Datatable, TableSettingsMenu } from '@@/datatables';
|
||||
import { TableSettingsMenuAutoRefresh } from '@@/datatables/TableSettingsMenuAutoRefresh';
|
||||
import { useRepeater } from '@@/datatables/useRepeater';
|
||||
import { Button } from '@@/buttons';
|
||||
import { Link } from '@@/Link';
|
||||
import { AddButton } from '@@/buttons';
|
||||
import { useTableState } from '@@/datatables/useTableState';
|
||||
import { DeleteButton } from '@@/buttons/DeleteButton';
|
||||
|
||||
import { DockerConfig } from '../../types';
|
||||
|
||||
|
@ -17,7 +17,7 @@ import { createStore } from './store';
|
|||
interface Props {
|
||||
dataset: Array<DockerConfig>;
|
||||
onRemoveClick: (configs: Array<DockerConfig>) => void;
|
||||
onRefresh: () => Promise<void>;
|
||||
onRefresh: () => void;
|
||||
}
|
||||
|
||||
const storageKey = 'docker_configs';
|
||||
|
@ -54,24 +54,15 @@ export function ConfigsDatatable({ dataset, onRefresh, onRemoveClick }: Props) {
|
|||
hasWriteAccessQuery.authorized && (
|
||||
<div className="flex items-center gap-3">
|
||||
<Authorized authorizations="DockerConfigDelete">
|
||||
<Button
|
||||
icon={Trash2}
|
||||
color="dangerlight"
|
||||
onClick={() => onRemoveClick(selectedRows)}
|
||||
<DeleteButton
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
onConfirmed={() => onRemoveClick(selectedRows)}
|
||||
confirmMessage="Do you want to remove the selected config(s)?"
|
||||
/>
|
||||
</Authorized>
|
||||
|
||||
<Authorized authorizations="DockerConfigCreate">
|
||||
<Button
|
||||
icon={Plus}
|
||||
as={Link}
|
||||
props={{ to: 'docker.configs.new' }}
|
||||
>
|
||||
Add config
|
||||
</Button>
|
||||
<AddButton>Add config</AddButton>
|
||||
</Authorized>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
import { useRouter } from '@uirouter/react';
|
||||
import {
|
||||
Pause,
|
||||
Play,
|
||||
Plus,
|
||||
RefreshCw,
|
||||
Slash,
|
||||
Square,
|
||||
Trash2,
|
||||
} from 'lucide-react';
|
||||
import { Pause, Play, RefreshCw, Slash, Square, Trash2 } from 'lucide-react';
|
||||
|
||||
import * as notifications from '@/portainer/services/notifications';
|
||||
import { useAuthorizations, Authorized } from '@/react/hooks/useUser';
|
||||
|
@ -29,8 +21,7 @@ import {
|
|||
} from '@/react/docker/containers/containers.service';
|
||||
import type { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
import { Link } from '@@/Link';
|
||||
import { ButtonGroup, Button } from '@@/buttons';
|
||||
import { ButtonGroup, Button, AddButton } from '@@/buttons';
|
||||
|
||||
type ContainerServiceAction = (
|
||||
endpointId: EnvironmentId,
|
||||
|
@ -166,11 +157,11 @@ export function ContainersDatatableActions({
|
|||
</Authorized>
|
||||
</ButtonGroup>
|
||||
{isAddActionVisible && (
|
||||
<Authorized authorizations="DockerContainerCreate">
|
||||
<Link to="docker.containers.new" className="space-left">
|
||||
<Button icon={Plus}>Add container</Button>
|
||||
</Link>
|
||||
</Authorized>
|
||||
<div className="space-left">
|
||||
<Authorized authorizations="DockerContainerCreate">
|
||||
<AddButton>Add container</AddButton>
|
||||
</Authorized>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
import {
|
||||
ChevronDown,
|
||||
Download,
|
||||
List,
|
||||
Plus,
|
||||
Trash2,
|
||||
Upload,
|
||||
} from 'lucide-react';
|
||||
import { ChevronDown, Download, List, Trash2, Upload } from 'lucide-react';
|
||||
import { Menu, MenuButton, MenuItem, MenuPopover } from '@reach/menu-button';
|
||||
import { positionRight } from '@reach/popover';
|
||||
import { useMemo } from 'react';
|
||||
|
@ -21,7 +14,7 @@ import {
|
|||
RefreshableTableSettings,
|
||||
} from '@@/datatables/types';
|
||||
import { useTableState } from '@@/datatables/useTableState';
|
||||
import { Button, ButtonGroup, LoadingButton } from '@@/buttons';
|
||||
import { AddButton, Button, ButtonGroup, LoadingButton } from '@@/buttons';
|
||||
import { Link } from '@@/Link';
|
||||
import { ButtonWithRef } from '@@/buttons/Button';
|
||||
import { TableSettingsMenuAutoRefresh } from '@@/datatables/TableSettingsMenuAutoRefresh';
|
||||
|
@ -82,14 +75,12 @@ export function ImagesDatatable({
|
|||
/>
|
||||
|
||||
<Authorized authorizations="DockerImageBuild">
|
||||
<Button
|
||||
as={Link}
|
||||
props={{ to: 'docker.images.build' }}
|
||||
<AddButton
|
||||
to="docker.images.build"
|
||||
data-cy="image-buildImageButton"
|
||||
icon={Plus}
|
||||
>
|
||||
Build a new image
|
||||
</Button>
|
||||
</AddButton>
|
||||
</Authorized>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -8,7 +8,6 @@ import { DockerContainer } from '@/react/docker/containers/types';
|
|||
import { ResourceControlViewModel } from '@/react/portainer/access-control/models/ResourceControlViewModel';
|
||||
import { useContainers } from '@/react/docker/containers/queries/containers';
|
||||
|
||||
import { confirmDelete } from '@@/modals/confirm';
|
||||
import { PageHeader } from '@@/PageHeader';
|
||||
|
||||
import { useNetwork, useDeleteNetwork } from '../queries';
|
||||
|
@ -95,19 +94,14 @@ export function ItemView() {
|
|||
);
|
||||
|
||||
async function onRemoveNetworkClicked() {
|
||||
const message = 'Do you want to delete the network?';
|
||||
const confirmed = await confirmDelete(message);
|
||||
|
||||
if (confirmed) {
|
||||
deleteNetworkMutation.mutate(
|
||||
{ environmentId, networkId },
|
||||
{
|
||||
onSuccess: () => {
|
||||
router.stateService.go('docker.networks');
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
deleteNetworkMutation.mutate(
|
||||
{ environmentId, networkId },
|
||||
{
|
||||
onSuccess: () => {
|
||||
router.stateService.go('docker.networks');
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { Fragment } from 'react';
|
||||
import { Network, Trash2 } from 'lucide-react';
|
||||
import { Network } from 'lucide-react';
|
||||
|
||||
import DockerNetworkHelper from '@/docker/helpers/networkHelper';
|
||||
import { Authorized } from '@/react/hooks/useUser';
|
||||
|
||||
import { TableContainer, TableTitle } from '@@/datatables';
|
||||
import { DetailsTable } from '@@/DetailsTable';
|
||||
import { Button } from '@@/buttons';
|
||||
import { Icon } from '@@/Icon';
|
||||
import { DeleteButton } from '@@/buttons/DeleteButton';
|
||||
|
||||
import { isSystemNetwork } from '../network.helper';
|
||||
import { DockerNetwork, IPConfig } from '../types';
|
||||
|
@ -38,21 +37,18 @@ export function NetworkDetailsTable({
|
|||
<DetailsTable.Row label="Id">
|
||||
{network.Id}
|
||||
{allowRemoveNetwork && (
|
||||
<Authorized authorizations="DockerNetworkDelete">
|
||||
<Button
|
||||
data-cy="networkDetails-deleteNetwork"
|
||||
size="xsmall"
|
||||
color="danger"
|
||||
onClick={() => onRemoveNetworkClicked()}
|
||||
>
|
||||
<Icon
|
||||
icon={Trash2}
|
||||
className="space-right"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Delete this network
|
||||
</Button>
|
||||
</Authorized>
|
||||
<span className="ml-2">
|
||||
<Authorized authorizations="DockerNetworkDelete">
|
||||
<DeleteButton
|
||||
data-cy="networkDetails-deleteNetwork"
|
||||
size="xsmall"
|
||||
onConfirmed={onRemoveNetworkClicked}
|
||||
confirmMessage="Do you want to delete the network?"
|
||||
>
|
||||
Delete this network
|
||||
</DeleteButton>
|
||||
</Authorized>
|
||||
</span>
|
||||
)}
|
||||
</DetailsTable.Row>
|
||||
<DetailsTable.Row label="Driver">{network.Driver}</DetailsTable.Row>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Plus, Network, Trash2 } from 'lucide-react';
|
||||
import { Network } from 'lucide-react';
|
||||
|
||||
import { Authorized } from '@/react/hooks/useUser';
|
||||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
|
@ -10,12 +10,12 @@ import {
|
|||
refreshableSettings,
|
||||
RefreshableTableSettings,
|
||||
} from '@@/datatables/types';
|
||||
import { Button } from '@@/buttons';
|
||||
import { AddButton } 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 { DeleteButton } from '@@/buttons/DeleteButton';
|
||||
|
||||
import { useIsSwarm } from '../../proxy/queries/useInfo';
|
||||
|
||||
|
@ -80,22 +80,16 @@ export function NetworksDatatable({ dataset, onRemove, onRefresh }: Props) {
|
|||
<Authorized
|
||||
authorizations={['DockerNetworkDelete', 'DockerNetworkCreate']}
|
||||
>
|
||||
<Button
|
||||
<DeleteButton
|
||||
disabled={selectedRows.length === 0}
|
||||
color="dangerlight"
|
||||
onClick={() => onRemove(selectedRows)}
|
||||
icon={Trash2}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
confirmMessage="Do you want to remove the selected network(s)?"
|
||||
onConfirmed={() => onRemove(selectedRows)}
|
||||
/>
|
||||
</Authorized>
|
||||
<Authorized
|
||||
authorizations="DockerNetworkCreate"
|
||||
data-cy="network-addNetworkButton"
|
||||
>
|
||||
<Button icon={Plus} as={Link} props={{ to: '.new' }}>
|
||||
<Authorized authorizations="DockerNetworkCreate">
|
||||
<AddButton data-cy="network-addNetworkButton">
|
||||
Add network
|
||||
</Button>
|
||||
</AddButton>
|
||||
</Authorized>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createColumnHelper } from '@tanstack/react-table';
|
||||
import { Lock, Plus, Trash2 } from 'lucide-react';
|
||||
import { Lock } from 'lucide-react';
|
||||
|
||||
import { SecretViewModel } from '@/docker/models/secret';
|
||||
import { isoDate } from '@/portainer/filters/filters';
|
||||
|
@ -15,9 +15,9 @@ import {
|
|||
} from '@@/datatables/types';
|
||||
import { useTableState } from '@@/datatables/useTableState';
|
||||
import { TableSettingsMenuAutoRefresh } from '@@/datatables/TableSettingsMenuAutoRefresh';
|
||||
import { Button } from '@@/buttons';
|
||||
import { Link } from '@@/Link';
|
||||
import { AddButton } from '@@/buttons';
|
||||
import { useRepeater } from '@@/datatables/useRepeater';
|
||||
import { DeleteButton } from '@@/buttons/DeleteButton';
|
||||
|
||||
import { createOwnershipColumn } from '../../components/datatable/createOwnershipColumn';
|
||||
|
||||
|
@ -96,28 +96,16 @@ function TableActions({
|
|||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Authorized authorizations="DockerSecretDelete">
|
||||
<Button
|
||||
color="dangerlight"
|
||||
<DeleteButton
|
||||
disabled={selectedItems.length === 0}
|
||||
onClick={() => onRemove(selectedItems)}
|
||||
icon={Trash2}
|
||||
className="!m-0"
|
||||
onConfirmed={() => onRemove(selectedItems)}
|
||||
confirmMessage="Do you want to remove the selected secret(s)?"
|
||||
data-cy="secret-removeSecretButton"
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
/>
|
||||
</Authorized>
|
||||
|
||||
<Authorized authorizations="DockerSecretCreate">
|
||||
<Button
|
||||
as={Link}
|
||||
props={{ to: '.new' }}
|
||||
icon={Plus}
|
||||
className="!m-0"
|
||||
data-cy="secret-addSecretButton"
|
||||
>
|
||||
Add secret
|
||||
</Button>
|
||||
<AddButton data-cy="secret-addSecretButton">Add secret</AddButton>
|
||||
</Authorized>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Trash2, Plus, RefreshCw } from 'lucide-react';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import { useRouter } from '@uirouter/react';
|
||||
|
||||
import { ServiceViewModel } from '@/docker/models/service';
|
||||
|
@ -6,9 +6,8 @@ import { Authorized } from '@/react/hooks/useUser';
|
|||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
import { notifySuccess } from '@/portainer/services/notifications';
|
||||
|
||||
import { Link } from '@@/Link';
|
||||
import { Button, ButtonGroup } from '@@/buttons';
|
||||
import { confirmDelete } from '@@/modals/confirm';
|
||||
import { AddButton, Button, ButtonGroup } from '@@/buttons';
|
||||
import { DeleteButton } from '@@/buttons/DeleteButton';
|
||||
|
||||
import { confirmServiceForceUpdate } from '../../common/update-service-modal';
|
||||
|
||||
|
@ -46,28 +45,18 @@ export function TableActions({
|
|||
</Authorized>
|
||||
)}
|
||||
<Authorized authorizations="DockerServiceDelete">
|
||||
<Button
|
||||
color="dangerlight"
|
||||
<DeleteButton
|
||||
disabled={selectedItems.length === 0}
|
||||
onClick={() => handleRemove(selectedItems)}
|
||||
icon={Trash2}
|
||||
onConfirmed={() => handleRemove(selectedItems)}
|
||||
confirmMessage="Do you want to remove the selected service(s)? All the containers associated to the selected service(s) will be removed too."
|
||||
data-cy="service-removeServiceButton"
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
/>
|
||||
</Authorized>
|
||||
</ButtonGroup>
|
||||
|
||||
{isAddActionVisible && (
|
||||
<Authorized authorizations="DockerServiceCreate">
|
||||
<Button
|
||||
as={Link}
|
||||
props={{ to: '.new' }}
|
||||
icon={Plus}
|
||||
className="!ml-0"
|
||||
>
|
||||
Add service
|
||||
</Button>
|
||||
<AddButton>Add service</AddButton>
|
||||
</Authorized>
|
||||
)}
|
||||
</div>
|
||||
|
@ -97,14 +86,6 @@ export function TableActions({
|
|||
}
|
||||
|
||||
async function handleRemove(selectedItems: Array<ServiceViewModel>) {
|
||||
const confirmed = await confirmDelete(
|
||||
'Do you want to remove the selected service(s)? All the containers associated to the selected service(s) will be removed too.'
|
||||
);
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeMutation.mutate(
|
||||
selectedItems.map((service) => service.Id),
|
||||
{
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { Trash2, Plus } from 'lucide-react';
|
||||
|
||||
import { Authorized } from '@/react/hooks/useUser';
|
||||
|
||||
import { Link } from '@@/Link';
|
||||
import { Button } from '@@/buttons';
|
||||
import { AddButton } from '@@/buttons';
|
||||
import { DeleteButton } from '@@/buttons/DeleteButton';
|
||||
|
||||
import { DecoratedStack } from './types';
|
||||
|
||||
|
@ -17,28 +15,18 @@ export function TableActions({
|
|||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Authorized authorizations="PortainerStackDelete">
|
||||
<Button
|
||||
color="dangerlight"
|
||||
<DeleteButton
|
||||
disabled={selectedItems.length === 0}
|
||||
onClick={() => onRemove(selectedItems)}
|
||||
icon={Trash2}
|
||||
className="!m-0"
|
||||
onConfirmed={() => onRemove(selectedItems)}
|
||||
confirmMessage="Do you want to remove the selected stack(s)? Associated services will be removed as well."
|
||||
data-cy="stack-removeStackButton"
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
/>
|
||||
</Authorized>
|
||||
|
||||
<Authorized authorizations="PortainerStackCreate">
|
||||
<Button
|
||||
as={Link}
|
||||
props={{ to: '.newstack' }}
|
||||
icon={Plus}
|
||||
className="!m-0"
|
||||
data-cy="stack-addStackButton"
|
||||
>
|
||||
<AddButton data-cy="stack-addStackButton" to=".newstack">
|
||||
Add stack
|
||||
</Button>
|
||||
</AddButton>
|
||||
</Authorized>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { Plus, Trash2 } from 'lucide-react';
|
||||
|
||||
import { Authorized } from '@/react/hooks/useUser';
|
||||
|
||||
import { Link } from '@@/Link';
|
||||
import { Button } from '@@/buttons';
|
||||
import { AddButton } from '@@/buttons';
|
||||
import { DeleteButton } from '@@/buttons/DeleteButton';
|
||||
|
||||
import { DecoratedVolume } from '../types';
|
||||
|
||||
|
@ -17,27 +15,15 @@ export function TableActions({
|
|||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Authorized authorizations="DockerVolumeDelete">
|
||||
<Button
|
||||
color="dangerlight"
|
||||
<DeleteButton
|
||||
disabled={selectedItems.length === 0}
|
||||
onClick={() => onRemove(selectedItems)}
|
||||
icon={Trash2}
|
||||
className="!m-0"
|
||||
onConfirmed={() => onRemove(selectedItems)}
|
||||
confirmMessage="Do you want to remove the selected volume(s)?"
|
||||
data-cy="volume-removeVolumeButton"
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
/>
|
||||
</Authorized>
|
||||
<Authorized authorizations="DockerVolumeCreate">
|
||||
<Button
|
||||
as={Link}
|
||||
props={{ to: '.new' }}
|
||||
icon={Plus}
|
||||
className="!m-0"
|
||||
data-cy="volume-addVolumeButton"
|
||||
>
|
||||
Add volume
|
||||
</Button>
|
||||
<AddButton data-cy="volume-addVolumeButton">Add volume</AddButton>
|
||||
</Authorized>
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue