ソースを参照

fix(dashboard): Implement bulk actions for the zone members table (#3966)

Fixes #3927
Will Nahmens 2 ヶ月 前
コミット
26997d3917

+ 49 - 1
packages/dashboard/src/app/routes/_authenticated/_zones/components/zone-bulk-actions.tsx

@@ -1,6 +1,12 @@
 import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
-import { deleteZonesDocument } from '../zones.graphql.js';
+import { deleteZonesDocument, removeCountryFromZoneMutation } from '../zones.graphql.js';
+import { DataTableBulkActionItem } from '@/vdb/components/data-table/data-table-bulk-action-item.js';
+import { TrashIcon } from 'lucide-react';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { api } from '@/vdb/graphql/api.js';
+import { toast } from 'sonner';
+import { Trans, useLingui } from '@lingui/react/macro';
 
 
 export const DeleteZonesBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
 export const DeleteZonesBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
     return (
     return (
@@ -13,3 +19,45 @@ export const DeleteZonesBulkAction: BulkActionComponent<any> = ({ selection, tab
         />
         />
     );
     );
 };
 };
+
+export function removeCountryFromZoneBulkAction(zoneId: string): BulkActionComponent<any> {
+    const RemoveCountryFromZoneBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
+        const { t } = useLingui();
+        const queryClient = useQueryClient();
+
+        const { mutate } = useMutation({
+            mutationFn: api.mutate(removeCountryFromZoneMutation),
+            onSuccess: () => {
+                toast.success(t`Removed ${selection.length} ${selection.length === 1 ? 'country' : 'countries'} from zone`);
+                queryClient.invalidateQueries({ queryKey: ['zone', zoneId] });
+                table.resetRowSelection();
+            },
+            onError: () => {
+                toast.error(t`Failed to remove countries from zone`);
+            },
+        });
+
+        return (
+            <DataTableBulkActionItem
+                requiresPermission={['UpdateZone']}
+                onClick={() => {
+                    mutate({
+                        zoneId,
+                        memberIds: selection.map(s => s.id),
+                    });
+                }}
+                label={<Trans>Remove from zone</Trans>}
+                confirmationText={
+                    <Trans>
+                        Are you sure you want to remove {selection.length} {selection.length === 1 ? 'country' : 'countries'} from this zone?
+                    </Trans>
+                }
+                icon={TrashIcon}
+                className="text-destructive"
+            />
+        );
+    };
+
+    return RemoveCountryFromZoneBulkAction;
+}
+

+ 34 - 16
packages/dashboard/src/app/routes/_authenticated/_zones/components/zone-countries-table.tsx

@@ -1,14 +1,15 @@
 import { DataTable } from '@/vdb/components/data-table/data-table.js';
 import { DataTable } from '@/vdb/components/data-table/data-table.js';
+import { useGeneratedColumns } from '@/vdb/components/data-table/use-generated-columns.js';
 import { CountrySelector } from '@/vdb/components/shared/country-selector.js';
 import { CountrySelector } from '@/vdb/components/shared/country-selector.js';
 import { api } from '@/vdb/graphql/api.js';
 import { api } from '@/vdb/graphql/api.js';
 import { useMutation, useQuery } from '@tanstack/react-query';
 import { useMutation, useQuery } from '@tanstack/react-query';
-import { ColumnDef } from '@tanstack/react-table';
+import { Trans } from '@lingui/react/macro';
 import { useMemo, useState } from 'react';
 import { useMemo, useState } from 'react';
 import {
 import {
     addCountryToZoneMutation,
     addCountryToZoneMutation,
-    removeCountryFromZoneMutation,
     zoneMembersQuery,
     zoneMembersQuery,
 } from '../zones.graphql.js';
 } from '../zones.graphql.js';
+import { removeCountryFromZoneBulkAction } from './zone-bulk-actions.js';
 
 
 interface ZoneCountriesTableProps {
 interface ZoneCountriesTableProps {
     zoneId: string;
     zoneId: string;
@@ -35,31 +36,48 @@ export function ZoneCountriesTable({ zoneId, canAddCountries = false }: Readonly
         return data?.zone?.members?.slice((page - 1) * pageSize, page * pageSize);
         return data?.zone?.members?.slice((page - 1) * pageSize, page * pageSize);
     }, [data, page, pageSize]);
     }, [data, page, pageSize]);
 
 
-    const columns: ColumnDef<any>[] = [
-        {
-            header: 'Country',
-            accessorKey: 'name',
-        },
-        {
-            header: 'Enabled',
-            accessorKey: 'enabled',
-        },
-        {
-            header: 'Code',
-            accessorKey: 'code',
+    const bulkActions = useMemo(
+        () => [
+            {
+                component: removeCountryFromZoneBulkAction(zoneId),
+                order: 500,
+            },
+        ],
+        [zoneId],
+    );
+
+    const { columns } = useGeneratedColumns({
+        fields: [],
+        additionalColumns: {
+            name: {
+                header: () => <Trans>Country</Trans>,
+                accessorKey: 'name',
+            },
+            enabled: {
+                header: () => <Trans>Enabled</Trans>,
+                accessorKey: 'enabled',
+            },
+            code: {
+                header: () => <Trans>Code</Trans>,
+                accessorKey: 'code',
+            },
         },
         },
-    ];
+        bulkActions,
+        includeActionsColumn: false,
+        enableSorting: false,
+    });
 
 
     return (
     return (
         <div>
         <div>
             <DataTable
             <DataTable
-                columns={columns}
+                columns={columns as any}
                 data={paginatedItems ?? []}
                 data={paginatedItems ?? []}
                 onPageChange={(table, page, itemsPerPage) => {
                 onPageChange={(table, page, itemsPerPage) => {
                     setPage(page);
                     setPage(page);
                     setPageSize(itemsPerPage);
                     setPageSize(itemsPerPage);
                 }}
                 }}
                 totalItems={data?.zone?.members?.length ?? 0}
                 totalItems={data?.zone?.members?.length ?? 0}
+                bulkActions={bulkActions}
             />
             />
             {canAddCountries && (
             {canAddCountries && (
                 <CountrySelector
                 <CountrySelector