@vendure/dashboard 3.3.6-master-202507011151 → 3.3.6-master-202507020234
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/app/common/delete-bulk-action.tsx +147 -0
- package/src/app/common/duplicate-bulk-action.tsx +1 -1
- package/src/app/routes/_authenticated/_administrators/administrators.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_administrators/administrators.tsx +7 -0
- package/src/app/routes/_authenticated/_administrators/components/administrator-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_assets/assets.graphql.ts +11 -0
- package/src/app/routes/_authenticated/_assets/assets.tsx +10 -2
- package/src/app/routes/_authenticated/_assets/components/asset-bulk-actions.tsx +45 -0
- package/src/app/routes/_authenticated/_channels/channels.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_channels/channels.tsx +7 -0
- package/src/app/routes/_authenticated/_channels/components/channel-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +39 -110
- package/src/app/routes/_authenticated/_countries/components/country-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_countries/countries.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_countries/countries.tsx +7 -0
- package/src/app/routes/_authenticated/_customer-groups/components/customer-group-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_customer-groups/customer-groups.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_customer-groups/customer-groups.tsx +7 -0
- package/src/app/routes/_authenticated/_customers/components/customer-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_customers/customers.graphql.ts +9 -1
- package/src/app/routes/_authenticated/_customers/customers.tsx +7 -0
- package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +104 -0
- package/src/app/routes/_authenticated/_facets/facets.graphql.ts +30 -0
- package/src/app/routes/_authenticated/_facets/facets.tsx +24 -0
- package/src/app/routes/_authenticated/_payment-methods/components/payment-method-bulk-actions.tsx +58 -0
- package/src/app/routes/_authenticated/_payment-methods/payment-methods.graphql.ts +27 -0
- package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +30 -8
- package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +4 -1
- package/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx +36 -110
- package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +36 -105
- package/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx +82 -0
- package/src/app/routes/_authenticated/_promotions/promotions.graphql.ts +25 -0
- package/src/app/routes/_authenticated/_promotions/promotions.tsx +24 -0
- package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +1 -1
- package/src/app/routes/_authenticated/_roles/components/role-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_roles/roles.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_roles/roles.tsx +7 -0
- package/src/app/routes/_authenticated/_sellers/components/seller-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_sellers/sellers.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_sellers/sellers.tsx +7 -0
- package/src/app/routes/_authenticated/_sellers/sellers_.$id.tsx +1 -1
- package/src/app/routes/_authenticated/_shipping-methods/components/shipping-method-bulk-actions.tsx +61 -0
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.graphql.ts +27 -0
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +19 -0
- package/src/app/routes/_authenticated/_stock-locations/components/stock-location-bulk-actions.tsx +58 -0
- package/src/app/routes/_authenticated/_stock-locations/stock-locations.graphql.ts +25 -0
- package/src/app/routes/_authenticated/_stock-locations/stock-locations.tsx +19 -0
- package/src/app/routes/_authenticated/_tax-categories/components/tax-category-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_tax-categories/tax-categories.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_tax-categories/tax-categories.tsx +7 -0
- package/src/app/routes/_authenticated/_tax-rates/components/tax-rate-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_tax-rates/tax-rates.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +7 -0
- package/src/app/routes/_authenticated/_zones/components/zone-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_zones/zones.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_zones/zones.tsx +7 -0
- package/src/lib/components/shared/asset/asset-bulk-actions.tsx +90 -0
- package/src/lib/components/shared/asset/asset-gallery.tsx +12 -7
- package/src/lib/components/shared/assign-to-channel-bulk-action.tsx +70 -0
- package/src/{app/routes/_authenticated/_products/components → lib/components/shared}/assign-to-channel-dialog.tsx +48 -30
- package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +89 -0
- package/src/app/routes/_authenticated/_collections/components/assign-collections-to-channel-dialog.tsx +0 -110
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vendure/dashboard",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "3.3.6-master-
|
|
4
|
+
"version": "3.3.6-master-202507020234",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"@types/react-dom": "^19.0.4",
|
|
87
87
|
"@types/react-grid-layout": "^1.3.5",
|
|
88
88
|
"@uidotdev/usehooks": "^2.4.1",
|
|
89
|
-
"@vendure/common": "^3.3.6-master-
|
|
90
|
-
"@vendure/core": "^3.3.6-master-
|
|
89
|
+
"@vendure/common": "^3.3.6-master-202507020234",
|
|
90
|
+
"@vendure/core": "^3.3.6-master-202507020234",
|
|
91
91
|
"@vitejs/plugin-react": "^4.3.4",
|
|
92
92
|
"awesome-graphql-client": "^2.1.0",
|
|
93
93
|
"class-variance-authority": "^0.7.1",
|
|
@@ -130,5 +130,5 @@
|
|
|
130
130
|
"lightningcss-linux-arm64-musl": "^1.29.3",
|
|
131
131
|
"lightningcss-linux-x64-musl": "^1.29.1"
|
|
132
132
|
},
|
|
133
|
-
"gitHead": "
|
|
133
|
+
"gitHead": "1ebfbfe0c8cc2a8f545987f52fd06b7f9a1f3089"
|
|
134
134
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { TrashIcon } from 'lucide-react';
|
|
3
|
+
import { toast } from 'sonner';
|
|
4
|
+
|
|
5
|
+
import { DataTableBulkActionItem } from '@/components/data-table/data-table-bulk-action-item.js';
|
|
6
|
+
import { api } from '@/graphql/api.js';
|
|
7
|
+
import { getMutationName, usePaginatedList } from '@/index.js';
|
|
8
|
+
import { Trans, useLingui } from '@/lib/trans.js';
|
|
9
|
+
|
|
10
|
+
interface DeleteBulkActionProps {
|
|
11
|
+
/** The GraphQL mutation document to execute */
|
|
12
|
+
mutationDocument: any;
|
|
13
|
+
/** The entity name for localization (e.g., "products", "administrators") */
|
|
14
|
+
entityName: string;
|
|
15
|
+
/** The required permissions for this action */
|
|
16
|
+
requiredPermissions: string[];
|
|
17
|
+
/** Optional callback for additional cleanup after successful deletion */
|
|
18
|
+
onSuccess?: () => void;
|
|
19
|
+
/** Optional query keys to invalidate after successful deletion */
|
|
20
|
+
invalidateQueries?: string[];
|
|
21
|
+
/** The selected items to delete */
|
|
22
|
+
selection: any[];
|
|
23
|
+
/** The table instance */
|
|
24
|
+
table: any;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A reusable delete bulk action component that can be used across all bulk action files.
|
|
29
|
+
*
|
|
30
|
+
* This component handles the common pattern of deleting multiple entities:
|
|
31
|
+
* - Executes the provided GraphQL mutation
|
|
32
|
+
* - Shows success/error toasts with localized messages
|
|
33
|
+
* - Refetches the paginated list
|
|
34
|
+
* - Resets table selection
|
|
35
|
+
* - Optionally invalidates additional queries
|
|
36
|
+
* - Optionally calls additional success callbacks
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* // Basic usage
|
|
41
|
+
* export const DeleteProductsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
42
|
+
* return (
|
|
43
|
+
* <DeleteBulkAction
|
|
44
|
+
* mutationDocument={deleteProductsDocument}
|
|
45
|
+
* entityName="products"
|
|
46
|
+
* requiredPermissions={['DeleteCatalog', 'DeleteProduct']}
|
|
47
|
+
* selection={selection}
|
|
48
|
+
* table={table}
|
|
49
|
+
* />
|
|
50
|
+
* );
|
|
51
|
+
* };
|
|
52
|
+
*
|
|
53
|
+
* // With additional cleanup
|
|
54
|
+
* export const DeleteCollectionsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
55
|
+
* return (
|
|
56
|
+
* <DeleteBulkAction
|
|
57
|
+
* mutationDocument={deleteCollectionsDocument}
|
|
58
|
+
* entityName="collections"
|
|
59
|
+
* requiredPermissions={['DeleteCatalog', 'DeleteCollection']}
|
|
60
|
+
* invalidateQueries={['childCollections']}
|
|
61
|
+
* onSuccess={() => {
|
|
62
|
+
* // Additional cleanup logic
|
|
63
|
+
* }}
|
|
64
|
+
* selection={selection}
|
|
65
|
+
* table={table}
|
|
66
|
+
* />
|
|
67
|
+
* );
|
|
68
|
+
* };
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function DeleteBulkAction({
|
|
72
|
+
mutationDocument,
|
|
73
|
+
entityName,
|
|
74
|
+
requiredPermissions,
|
|
75
|
+
onSuccess,
|
|
76
|
+
invalidateQueries = [],
|
|
77
|
+
selection,
|
|
78
|
+
table,
|
|
79
|
+
}: Readonly<DeleteBulkActionProps>) {
|
|
80
|
+
const { refetchPaginatedList } = usePaginatedList();
|
|
81
|
+
const { i18n } = useLingui();
|
|
82
|
+
const queryClient = useQueryClient();
|
|
83
|
+
|
|
84
|
+
const { mutate } = useMutation({
|
|
85
|
+
mutationFn: api.mutate(mutationDocument),
|
|
86
|
+
onSuccess: (result: any) => {
|
|
87
|
+
let deleted = 0;
|
|
88
|
+
let failed = 0;
|
|
89
|
+
const errors: string[] = [];
|
|
90
|
+
|
|
91
|
+
// Get the mutation result field name from the document
|
|
92
|
+
const mutationResultFieldName = getMutationName(mutationDocument);
|
|
93
|
+
const deleteResults = result[mutationResultFieldName];
|
|
94
|
+
|
|
95
|
+
for (const item of deleteResults) {
|
|
96
|
+
if (item.result === 'DELETED') {
|
|
97
|
+
deleted++;
|
|
98
|
+
} else {
|
|
99
|
+
failed++;
|
|
100
|
+
if (item.message) {
|
|
101
|
+
errors.push(item.message);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (0 < deleted) {
|
|
107
|
+
toast.success(i18n.t(`Deleted ${deleted} ${entityName}`));
|
|
108
|
+
}
|
|
109
|
+
if (0 < failed) {
|
|
110
|
+
const errorMessage =
|
|
111
|
+
errors.length > 0
|
|
112
|
+
? i18n.t(`Failed to delete ${failed} ${entityName}: ${errors.join(', ')}`)
|
|
113
|
+
: i18n.t(`Failed to delete ${failed} ${entityName}`);
|
|
114
|
+
toast.error(errorMessage);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
refetchPaginatedList();
|
|
118
|
+
table.resetRowSelection();
|
|
119
|
+
|
|
120
|
+
// Invalidate additional queries if specified
|
|
121
|
+
invalidateQueries.forEach(queryKey => {
|
|
122
|
+
queryClient.invalidateQueries({ queryKey: [queryKey] });
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Call additional success callback if provided
|
|
126
|
+
onSuccess?.();
|
|
127
|
+
},
|
|
128
|
+
onError: () => {
|
|
129
|
+
toast.error(`Failed to delete ${selection.length} ${entityName}`);
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<DataTableBulkActionItem
|
|
135
|
+
requiresPermission={requiredPermissions}
|
|
136
|
+
onClick={() => mutate({ ids: selection.map(s => s.id) })}
|
|
137
|
+
label={<Trans>Delete</Trans>}
|
|
138
|
+
confirmationText={
|
|
139
|
+
<Trans>
|
|
140
|
+
Are you sure you want to delete {selection.length} {entityName}?
|
|
141
|
+
</Trans>
|
|
142
|
+
}
|
|
143
|
+
icon={TrashIcon}
|
|
144
|
+
className="text-destructive"
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
@@ -10,7 +10,7 @@ import { usePaginatedList } from '@/index.js';
|
|
|
10
10
|
import { Trans, useLingui } from '@/lib/trans.js';
|
|
11
11
|
|
|
12
12
|
interface DuplicateBulkActionProps {
|
|
13
|
-
entityType: 'Product' | 'Collection';
|
|
13
|
+
entityType: 'Product' | 'Collection' | 'Facet' | 'Promotion';
|
|
14
14
|
duplicatorCode: string;
|
|
15
15
|
duplicatorArguments?: Array<{ name: string; value: string }>;
|
|
16
16
|
requiredPermissions: string[];
|
|
@@ -9,6 +9,7 @@ import { Trans } from '@/lib/trans.js';
|
|
|
9
9
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
10
10
|
import { PlusIcon } from 'lucide-react';
|
|
11
11
|
import { administratorListDocument, deleteAdministratorDocument } from './administrators.graphql.js';
|
|
12
|
+
import { DeleteAdministratorsBulkAction } from './components/administrator-bulk-actions.js';
|
|
12
13
|
|
|
13
14
|
export const Route = createFileRoute('/_authenticated/_administrators/administrators')({
|
|
14
15
|
component: AdministratorListPage,
|
|
@@ -70,6 +71,12 @@ function AdministratorListPage() {
|
|
|
70
71
|
emailAddress: true,
|
|
71
72
|
}}
|
|
72
73
|
defaultColumnOrder={['name', 'emailAddress', 'roles']}
|
|
74
|
+
bulkActions={[
|
|
75
|
+
{
|
|
76
|
+
component: DeleteAdministratorsBulkAction,
|
|
77
|
+
order: 500,
|
|
78
|
+
},
|
|
79
|
+
]}
|
|
73
80
|
>
|
|
74
81
|
<PageActionBarRight>
|
|
75
82
|
<PermissionGuard requires={['CreateAdministrator']}>
|
package/src/app/routes/_authenticated/_administrators/components/administrator-bulk-actions.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BulkActionComponent } from '@/framework/data-table/data-table-types.js';
|
|
2
|
+
import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
|
|
3
|
+
import { deleteAdministratorsDocument } from '../administrators.graphql.js';
|
|
4
|
+
|
|
5
|
+
export const DeleteAdministratorsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
6
|
+
return (
|
|
7
|
+
<DeleteBulkAction
|
|
8
|
+
mutationDocument={deleteAdministratorsDocument}
|
|
9
|
+
entityName="administrators"
|
|
10
|
+
requiredPermissions={['DeleteAdministrator']}
|
|
11
|
+
selection={selection}
|
|
12
|
+
table={table}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -24,3 +24,14 @@ export const assetUpdateDocument = graphql(`
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
`);
|
|
27
|
+
|
|
28
|
+
export const deleteAssetsDocument = graphql(`
|
|
29
|
+
mutation DeleteAssets($input: DeleteAssetsInput!) {
|
|
30
|
+
deleteAssets(input: $input) {
|
|
31
|
+
... on DeletionResponse {
|
|
32
|
+
result
|
|
33
|
+
message
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
`);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AssetGallery } from '@/components/shared/asset/asset-gallery.js';
|
|
2
|
-
import { Page,
|
|
2
|
+
import { Page, PageBlock, PageTitle } from '@/framework/layout-engine/page-layout.js';
|
|
3
3
|
import { Trans } from '@/lib/trans.js';
|
|
4
4
|
import { createFileRoute } from '@tanstack/react-router';
|
|
5
|
+
import { DeleteAssetsBulkAction } from './components/asset-bulk-actions.js';
|
|
5
6
|
|
|
6
7
|
export const Route = createFileRoute('/_authenticated/_assets/assets')({
|
|
7
8
|
component: RouteComponent,
|
|
@@ -13,7 +14,14 @@ function RouteComponent() {
|
|
|
13
14
|
<PageTitle>
|
|
14
15
|
<Trans>Assets</Trans>
|
|
15
16
|
</PageTitle>
|
|
16
|
-
<
|
|
17
|
+
<PageBlock blockId="asset-gallery" column="main">
|
|
18
|
+
<AssetGallery selectable={true} multiSelect="manual" bulkActions={[{
|
|
19
|
+
order: 10,
|
|
20
|
+
component: DeleteAssetsBulkAction,
|
|
21
|
+
},
|
|
22
|
+
]}
|
|
23
|
+
/>
|
|
24
|
+
</PageBlock>
|
|
17
25
|
</Page>
|
|
18
26
|
);
|
|
19
27
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useMutation } from '@tanstack/react-query';
|
|
2
|
+
import { TrashIcon } from 'lucide-react';
|
|
3
|
+
import { toast } from 'sonner';
|
|
4
|
+
|
|
5
|
+
import { DataTableBulkActionItem } from '@/components/data-table/data-table-bulk-action-item.js';
|
|
6
|
+
import { api } from '@/graphql/api.js';
|
|
7
|
+
import { AssetFragment } from '@/graphql/fragments.js';
|
|
8
|
+
import { ResultOf } from '@/graphql/graphql.js';
|
|
9
|
+
import { Trans, useLingui } from '@/lib/trans.js';
|
|
10
|
+
import { deleteAssetsDocument } from '../assets.graphql.js';
|
|
11
|
+
|
|
12
|
+
export const DeleteAssetsBulkAction = ({
|
|
13
|
+
selection,
|
|
14
|
+
refetch,
|
|
15
|
+
}: {
|
|
16
|
+
selection: AssetFragment[];
|
|
17
|
+
refetch: () => void;
|
|
18
|
+
}) => {
|
|
19
|
+
const { i18n } = useLingui();
|
|
20
|
+
const { mutate } = useMutation({
|
|
21
|
+
mutationFn: api.mutate(deleteAssetsDocument),
|
|
22
|
+
onSuccess: (result: ResultOf<typeof deleteAssetsDocument>) => {
|
|
23
|
+
if (result.deleteAssets.result === 'DELETED') {
|
|
24
|
+
toast.success(i18n.t(`Deleted ${selection.length} assets`));
|
|
25
|
+
} else {
|
|
26
|
+
toast.error(i18n.t(`Failed to delete assets: ${result.deleteAssets.message}`));
|
|
27
|
+
}
|
|
28
|
+
refetch();
|
|
29
|
+
},
|
|
30
|
+
onError: () => {
|
|
31
|
+
toast.error(`Failed to delete ${selection.length} assets`);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<DataTableBulkActionItem
|
|
37
|
+
requiresPermission={['DeleteCatalog', 'DeleteAsset']}
|
|
38
|
+
onClick={() => mutate({ input: { assetIds: selection.map(s => s.id) } })}
|
|
39
|
+
label={<Trans>Delete</Trans>}
|
|
40
|
+
confirmationText={<Trans>Are you sure you want to delete {selection.length} assets?</Trans>}
|
|
41
|
+
icon={TrashIcon}
|
|
42
|
+
className="text-destructive"
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
@@ -9,6 +9,7 @@ import { createFileRoute, Link } from '@tanstack/react-router';
|
|
|
9
9
|
import { PlusIcon } from 'lucide-react';
|
|
10
10
|
import { channelListQuery, deleteChannelDocument } from './channels.graphql.js';
|
|
11
11
|
import { useLocalFormat } from '@/hooks/use-local-format.js';
|
|
12
|
+
import { DeleteChannelsBulkAction } from './components/channel-bulk-actions.js';
|
|
12
13
|
|
|
13
14
|
export const Route = createFileRoute('/_authenticated/_channels/channels')({
|
|
14
15
|
component: ChannelListPage,
|
|
@@ -62,6 +63,12 @@ function ChannelListPage() {
|
|
|
62
63
|
}
|
|
63
64
|
},
|
|
64
65
|
}}
|
|
66
|
+
bulkActions={[
|
|
67
|
+
{
|
|
68
|
+
component: DeleteChannelsBulkAction,
|
|
69
|
+
order: 500,
|
|
70
|
+
},
|
|
71
|
+
]}
|
|
65
72
|
>
|
|
66
73
|
<PageActionBarRight>
|
|
67
74
|
<PermissionGuard requires={['CreateChannel']}>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BulkActionComponent } from '@/framework/data-table/data-table-types.js';
|
|
2
|
+
import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
|
|
3
|
+
import { deleteChannelsDocument } from '../channels.graphql.js';
|
|
4
|
+
|
|
5
|
+
export const DeleteChannelsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
6
|
+
return (
|
|
7
|
+
<DeleteBulkAction
|
|
8
|
+
mutationDocument={deleteChannelsDocument}
|
|
9
|
+
entityName="channels"
|
|
10
|
+
requiredPermissions={['DeleteChannel']}
|
|
11
|
+
selection={selection}
|
|
12
|
+
table={table}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -1,99 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LayersIcon, TrashIcon } from 'lucide-react';
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
import { toast } from 'sonner';
|
|
1
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
5
2
|
|
|
6
|
-
import {
|
|
3
|
+
import { AssignToChannelBulkAction } from '@/components/shared/assign-to-channel-bulk-action.js';
|
|
4
|
+
import { RemoveFromChannelBulkAction } from '@/components/shared/remove-from-channel-bulk-action.js';
|
|
7
5
|
import { BulkActionComponent } from '@/framework/data-table/data-table-types.js';
|
|
8
6
|
import { api } from '@/graphql/api.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
7
|
+
import { useChannel } from '@/index.js';
|
|
8
|
+
import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
|
|
11
9
|
import { DuplicateBulkAction } from '../../../../common/duplicate-bulk-action.js';
|
|
12
10
|
import {
|
|
13
11
|
assignCollectionToChannelDocument,
|
|
14
12
|
deleteCollectionsDocument,
|
|
15
13
|
removeCollectionFromChannelDocument,
|
|
16
14
|
} from '../collections.graphql.js';
|
|
17
|
-
import { AssignCollectionsToChannelDialog } from './assign-collections-to-channel-dialog.js';
|
|
18
15
|
|
|
19
16
|
export const AssignCollectionsToChannelBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
20
|
-
const { refetchPaginatedList } = usePaginatedList();
|
|
21
|
-
const { channels } = useChannel();
|
|
22
|
-
const [dialogOpen, setDialogOpen] = useState(false);
|
|
23
17
|
const queryClient = useQueryClient();
|
|
24
18
|
|
|
25
|
-
if (channels.length < 2) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const handleSuccess = () => {
|
|
30
|
-
refetchPaginatedList();
|
|
31
|
-
table.resetRowSelection();
|
|
32
|
-
queryClient.invalidateQueries({ queryKey: ['childCollections'] });
|
|
33
|
-
};
|
|
34
|
-
|
|
35
19
|
return (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
</>
|
|
20
|
+
<AssignToChannelBulkAction
|
|
21
|
+
selection={selection}
|
|
22
|
+
table={table}
|
|
23
|
+
entityType="collections"
|
|
24
|
+
mutationFn={api.mutate(assignCollectionToChannelDocument)}
|
|
25
|
+
requiredPermissions={['UpdateCatalog', 'UpdateCollection']}
|
|
26
|
+
buildInput={(channelId: string) => ({
|
|
27
|
+
collectionIds: selection.map(s => s.id),
|
|
28
|
+
channelId,
|
|
29
|
+
})}
|
|
30
|
+
onSuccess={() => {
|
|
31
|
+
queryClient.invalidateQueries({ queryKey: ['childCollections'] });
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
51
34
|
);
|
|
52
35
|
};
|
|
53
36
|
|
|
54
37
|
export const RemoveCollectionsFromChannelBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
55
|
-
const { refetchPaginatedList } = usePaginatedList();
|
|
56
38
|
const { selectedChannel } = useChannel();
|
|
57
|
-
const { i18n } = useLingui();
|
|
58
39
|
const queryClient = useQueryClient();
|
|
59
|
-
const { mutate } = useMutation({
|
|
60
|
-
mutationFn: api.mutate(removeCollectionFromChannelDocument),
|
|
61
|
-
onSuccess: () => {
|
|
62
|
-
toast.success(i18n.t(`Successfully removed ${selection.length} collections from channel`));
|
|
63
|
-
refetchPaginatedList();
|
|
64
|
-
table.resetRowSelection();
|
|
65
|
-
queryClient.invalidateQueries({ queryKey: ['childCollections'] });
|
|
66
|
-
},
|
|
67
|
-
onError: error => {
|
|
68
|
-
toast.error(`Failed to remove ${selection.length} collections from channel: ${error.message}`);
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
if (!selectedChannel) {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const handleRemove = () => {
|
|
77
|
-
mutate({
|
|
78
|
-
input: {
|
|
79
|
-
collectionIds: selection.map(s => s.id),
|
|
80
|
-
channelId: selectedChannel.id,
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
};
|
|
84
40
|
|
|
85
41
|
return (
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
42
|
+
<RemoveFromChannelBulkAction
|
|
43
|
+
selection={selection}
|
|
44
|
+
table={table}
|
|
45
|
+
entityType="collections"
|
|
46
|
+
mutationFn={api.mutate(removeCollectionFromChannelDocument)}
|
|
47
|
+
requiredPermissions={['UpdateCatalog', 'UpdateCollection']}
|
|
48
|
+
buildInput={() => ({
|
|
49
|
+
collectionIds: selection.map(s => s.id),
|
|
50
|
+
channelId: selectedChannel?.id,
|
|
51
|
+
})}
|
|
52
|
+
onSuccess={() => {
|
|
53
|
+
queryClient.invalidateQueries({ queryKey: ['childCollections'] });
|
|
54
|
+
}}
|
|
97
55
|
/>
|
|
98
56
|
);
|
|
99
57
|
};
|
|
@@ -117,43 +75,14 @@ export const DuplicateCollectionsBulkAction: BulkActionComponent<any> = ({ selec
|
|
|
117
75
|
};
|
|
118
76
|
|
|
119
77
|
export const DeleteCollectionsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
120
|
-
const { refetchPaginatedList } = usePaginatedList();
|
|
121
|
-
const { i18n } = useLingui();
|
|
122
|
-
const queryClient = useQueryClient();
|
|
123
|
-
const { mutate } = useMutation({
|
|
124
|
-
mutationFn: api.mutate(deleteCollectionsDocument),
|
|
125
|
-
onSuccess: (result: ResultOf<typeof deleteCollectionsDocument>) => {
|
|
126
|
-
let deleted = 0;
|
|
127
|
-
const errors: string[] = [];
|
|
128
|
-
for (const item of result.deleteCollections) {
|
|
129
|
-
if (item.result === 'DELETED') {
|
|
130
|
-
deleted++;
|
|
131
|
-
} else if (item.message) {
|
|
132
|
-
errors.push(item.message);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (0 < deleted) {
|
|
136
|
-
toast.success(i18n.t(`Deleted ${deleted} collections`));
|
|
137
|
-
}
|
|
138
|
-
if (0 < errors.length) {
|
|
139
|
-
toast.error(i18n.t(`Failed to delete ${errors.length} collections`));
|
|
140
|
-
}
|
|
141
|
-
refetchPaginatedList();
|
|
142
|
-
table.resetRowSelection();
|
|
143
|
-
queryClient.invalidateQueries({ queryKey: ['childCollections'] });
|
|
144
|
-
},
|
|
145
|
-
onError: () => {
|
|
146
|
-
toast.error(`Failed to delete ${selection.length} collections`);
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
78
|
return (
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
79
|
+
<DeleteBulkAction
|
|
80
|
+
mutationDocument={deleteCollectionsDocument}
|
|
81
|
+
entityName="collections"
|
|
82
|
+
requiredPermissions={['DeleteCatalog', 'DeleteCollection']}
|
|
83
|
+
invalidateQueries={['childCollections']}
|
|
84
|
+
selection={selection}
|
|
85
|
+
table={table}
|
|
157
86
|
/>
|
|
158
87
|
);
|
|
159
88
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BulkActionComponent } from '@/framework/data-table/data-table-types.js';
|
|
2
|
+
import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
|
|
3
|
+
import { deleteCountriesDocument } from '../countries.graphql.js';
|
|
4
|
+
|
|
5
|
+
export const DeleteCountriesBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
6
|
+
return (
|
|
7
|
+
<DeleteBulkAction
|
|
8
|
+
mutationDocument={deleteCountriesDocument}
|
|
9
|
+
entityName="countries"
|
|
10
|
+
requiredPermissions={['DeleteCountry']}
|
|
11
|
+
selection={selection}
|
|
12
|
+
table={table}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -6,6 +6,7 @@ import { ListPage } from '@/framework/page/list-page.js';
|
|
|
6
6
|
import { Trans } from '@/lib/trans.js';
|
|
7
7
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
8
8
|
import { PlusIcon } from 'lucide-react';
|
|
9
|
+
import { DeleteCountriesBulkAction } from './components/country-bulk-actions.js';
|
|
9
10
|
import { countriesListQuery, deleteCountryDocument } from './countries.graphql.js';
|
|
10
11
|
|
|
11
12
|
export const Route = createFileRoute('/_authenticated/_countries/countries')({
|
|
@@ -51,6 +52,12 @@ function CountryListPage() {
|
|
|
51
52
|
cell: ({ row }) => <DetailPageButton id={row.original.id} label={row.original.name} />,
|
|
52
53
|
},
|
|
53
54
|
}}
|
|
55
|
+
bulkActions={[
|
|
56
|
+
{
|
|
57
|
+
component: DeleteCountriesBulkAction,
|
|
58
|
+
order: 500,
|
|
59
|
+
},
|
|
60
|
+
]}
|
|
54
61
|
>
|
|
55
62
|
<PageActionBarRight>
|
|
56
63
|
<PermissionGuard requires={['CreateCountry']}>
|
package/src/app/routes/_authenticated/_customer-groups/components/customer-group-bulk-actions.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BulkActionComponent } from '@/framework/data-table/data-table-types.js';
|
|
2
|
+
import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
|
|
3
|
+
import { deleteCustomerGroupsDocument } from '../customer-groups.graphql.js';
|
|
4
|
+
|
|
5
|
+
export const DeleteCustomerGroupsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
6
|
+
return (
|
|
7
|
+
<DeleteBulkAction
|
|
8
|
+
mutationDocument={deleteCustomerGroupsDocument}
|
|
9
|
+
entityName="customer groups"
|
|
10
|
+
requiredPermissions={['DeleteCustomerGroup']}
|
|
11
|
+
selection={selection}
|
|
12
|
+
table={table}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -6,6 +6,7 @@ import { ListPage } from '@/framework/page/list-page.js';
|
|
|
6
6
|
import { Trans } from '@/lib/trans.js';
|
|
7
7
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
8
8
|
import { PlusIcon } from 'lucide-react';
|
|
9
|
+
import { DeleteCustomerGroupsBulkAction } from './components/customer-group-bulk-actions.js';
|
|
9
10
|
import { CustomerGroupMembersSheet } from './components/customer-group-members-sheet.js';
|
|
10
11
|
import { customerGroupListDocument, deleteCustomerGroupDocument } from './customer-groups.graphql.js';
|
|
11
12
|
|
|
@@ -52,6 +53,12 @@ function CustomerGroupListPage() {
|
|
|
52
53
|
name: { contains: searchTerm },
|
|
53
54
|
};
|
|
54
55
|
}}
|
|
56
|
+
bulkActions={[
|
|
57
|
+
{
|
|
58
|
+
component: DeleteCustomerGroupsBulkAction,
|
|
59
|
+
order: 500,
|
|
60
|
+
},
|
|
61
|
+
]}
|
|
55
62
|
>
|
|
56
63
|
<PageActionBarRight>
|
|
57
64
|
<PermissionGuard requires={['CreateCustomerGroup']}>
|