@vendure/dashboard 3.3.6-master-202507010922 → 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 +131 -131
- 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/detail-page-button.tsx +1 -1
- package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +89 -0
- package/src/lib/framework/extension-api/use-dashboard-extensions.ts +2 -1
- package/src/lib/framework/form-engine/use-generated-form.tsx +5 -8
- package/src/lib/framework/page/use-detail-page.ts +4 -4
- package/src/lib/framework/page/use-extended-router.tsx +4 -5
- package/src/lib/hooks/use-channel.ts +2 -1
- package/src/lib/hooks/use-extended-detail-query.ts +2 -1
- package/src/lib/hooks/use-extended-list-query.ts +3 -2
- package/src/lib/hooks/use-grouped-permissions.ts +4 -2
- package/src/lib/hooks/use-page-block.tsx +1 -1
- package/src/lib/hooks/use-page.tsx +2 -2
- package/src/lib/hooks/use-permissions.ts +3 -2
- package/src/lib/hooks/use-server-config.ts +2 -1
- package/src/lib/hooks/use-theme.ts +2 -1
- package/src/lib/providers/auth.tsx +34 -11
- package/src/app/routes/_authenticated/_collections/components/assign-collections-to-channel-dialog.tsx +0 -110
package/src/app/routes/_authenticated/_shipping-methods/components/shipping-method-bulk-actions.tsx
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { AssignToChannelBulkAction } from '@/components/shared/assign-to-channel-bulk-action.js';
|
|
2
|
+
import { RemoveFromChannelBulkAction } from '@/components/shared/remove-from-channel-bulk-action.js';
|
|
3
|
+
import { BulkActionComponent } from '@/framework/data-table/data-table-types.js';
|
|
4
|
+
import { api } from '@/graphql/api.js';
|
|
5
|
+
import { useChannel } from '@/index.js';
|
|
6
|
+
import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
assignShippingMethodsToChannelDocument,
|
|
10
|
+
deleteShippingMethodsDocument,
|
|
11
|
+
removeShippingMethodsFromChannelDocument,
|
|
12
|
+
} from '../shipping-methods.graphql.js';
|
|
13
|
+
|
|
14
|
+
export const DeleteShippingMethodsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
15
|
+
return (
|
|
16
|
+
<DeleteBulkAction
|
|
17
|
+
mutationDocument={deleteShippingMethodsDocument}
|
|
18
|
+
entityName="shipping methods"
|
|
19
|
+
requiredPermissions={['DeleteShippingMethod']}
|
|
20
|
+
selection={selection}
|
|
21
|
+
table={table}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const AssignShippingMethodsToChannelBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
27
|
+
return (
|
|
28
|
+
<AssignToChannelBulkAction
|
|
29
|
+
selection={selection}
|
|
30
|
+
table={table}
|
|
31
|
+
entityType="shipping methods"
|
|
32
|
+
mutationFn={api.mutate(assignShippingMethodsToChannelDocument)}
|
|
33
|
+
requiredPermissions={['UpdateShippingMethod']}
|
|
34
|
+
buildInput={(channelId: string) => ({
|
|
35
|
+
shippingMethodIds: selection.map(s => s.id),
|
|
36
|
+
channelId,
|
|
37
|
+
})}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const RemoveShippingMethodsFromChannelBulkAction: BulkActionComponent<any> = ({
|
|
43
|
+
selection,
|
|
44
|
+
table,
|
|
45
|
+
}) => {
|
|
46
|
+
const { selectedChannel } = useChannel();
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<RemoveFromChannelBulkAction
|
|
50
|
+
selection={selection}
|
|
51
|
+
table={table}
|
|
52
|
+
entityType="shipping methods"
|
|
53
|
+
mutationFn={api.mutate(removeShippingMethodsFromChannelDocument)}
|
|
54
|
+
requiredPermissions={['UpdateShippingMethod']}
|
|
55
|
+
buildInput={() => ({
|
|
56
|
+
shippingMethodIds: selection.map(s => s.id),
|
|
57
|
+
channelId: selectedChannel?.id,
|
|
58
|
+
})}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
@@ -81,3 +81,30 @@ export const deleteShippingMethodDocument = graphql(`
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
`);
|
|
84
|
+
|
|
85
|
+
export const deleteShippingMethodsDocument = graphql(`
|
|
86
|
+
mutation DeleteShippingMethods($ids: [ID!]!) {
|
|
87
|
+
deleteShippingMethods(ids: $ids) {
|
|
88
|
+
result
|
|
89
|
+
message
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
`);
|
|
93
|
+
|
|
94
|
+
export const assignShippingMethodsToChannelDocument = graphql(`
|
|
95
|
+
mutation AssignShippingMethodsToChannel($input: AssignShippingMethodsToChannelInput!) {
|
|
96
|
+
assignShippingMethodsToChannel(input: $input) {
|
|
97
|
+
id
|
|
98
|
+
name
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
`);
|
|
102
|
+
|
|
103
|
+
export const removeShippingMethodsFromChannelDocument = graphql(`
|
|
104
|
+
mutation RemoveShippingMethodsFromChannel($input: RemoveShippingMethodsFromChannelInput!) {
|
|
105
|
+
removeShippingMethodsFromChannel(input: $input) {
|
|
106
|
+
id
|
|
107
|
+
name
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
`);
|
|
@@ -6,6 +6,11 @@ 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 {
|
|
10
|
+
AssignShippingMethodsToChannelBulkAction,
|
|
11
|
+
DeleteShippingMethodsBulkAction,
|
|
12
|
+
RemoveShippingMethodsFromChannelBulkAction,
|
|
13
|
+
} from './components/shipping-method-bulk-actions.js';
|
|
9
14
|
import { TestShippingMethodDialog } from './components/test-shipping-method-dialog.js';
|
|
10
15
|
import { deleteShippingMethodDocument, shippingMethodListQuery } from './shipping-methods.graphql.js';
|
|
11
16
|
|
|
@@ -38,6 +43,20 @@ function ShippingMethodListPage() {
|
|
|
38
43
|
name: { contains: searchTerm },
|
|
39
44
|
};
|
|
40
45
|
}}
|
|
46
|
+
bulkActions={[
|
|
47
|
+
{
|
|
48
|
+
component: AssignShippingMethodsToChannelBulkAction,
|
|
49
|
+
order: 100,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
component: RemoveShippingMethodsFromChannelBulkAction,
|
|
53
|
+
order: 200,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
component: DeleteShippingMethodsBulkAction,
|
|
57
|
+
order: 500,
|
|
58
|
+
},
|
|
59
|
+
]}
|
|
41
60
|
>
|
|
42
61
|
<PageActionBarRight>
|
|
43
62
|
<PermissionGuard requires={['CreateShippingMethod']}>
|
package/src/app/routes/_authenticated/_stock-locations/components/stock-location-bulk-actions.tsx
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { AssignToChannelBulkAction } from '@/components/shared/assign-to-channel-bulk-action.js';
|
|
2
|
+
import { RemoveFromChannelBulkAction } from '@/components/shared/remove-from-channel-bulk-action.js';
|
|
3
|
+
import { BulkActionComponent } from '@/framework/data-table/data-table-types.js';
|
|
4
|
+
import { api } from '@/graphql/api.js';
|
|
5
|
+
import { useChannel } from '@/index.js';
|
|
6
|
+
import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
assignStockLocationsToChannelDocument,
|
|
10
|
+
deleteStockLocationsDocument,
|
|
11
|
+
removeStockLocationsFromChannelDocument,
|
|
12
|
+
} from '../stock-locations.graphql.js';
|
|
13
|
+
|
|
14
|
+
export const DeleteStockLocationsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
15
|
+
return (
|
|
16
|
+
<DeleteBulkAction
|
|
17
|
+
mutationDocument={deleteStockLocationsDocument}
|
|
18
|
+
entityName="stock locations"
|
|
19
|
+
requiredPermissions={['DeleteStockLocation']}
|
|
20
|
+
selection={selection}
|
|
21
|
+
table={table}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const AssignStockLocationsToChannelBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
27
|
+
return (
|
|
28
|
+
<AssignToChannelBulkAction
|
|
29
|
+
selection={selection}
|
|
30
|
+
table={table}
|
|
31
|
+
entityType="stock locations"
|
|
32
|
+
mutationFn={api.mutate(assignStockLocationsToChannelDocument)}
|
|
33
|
+
requiredPermissions={['UpdateStockLocation']}
|
|
34
|
+
buildInput={(channelId: string) => ({
|
|
35
|
+
stockLocationIds: selection.map(s => s.id),
|
|
36
|
+
channelId,
|
|
37
|
+
})}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const RemoveStockLocationsFromChannelBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
43
|
+
const { selectedChannel } = useChannel();
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<RemoveFromChannelBulkAction
|
|
47
|
+
selection={selection}
|
|
48
|
+
table={table}
|
|
49
|
+
entityType="stock locations"
|
|
50
|
+
mutationFn={api.mutate(removeStockLocationsFromChannelDocument)}
|
|
51
|
+
requiredPermissions={['UpdateStockLocation']}
|
|
52
|
+
buildInput={() => ({
|
|
53
|
+
stockLocationIds: selection.map(s => s.id),
|
|
54
|
+
channelId: selectedChannel?.id,
|
|
55
|
+
})}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -60,3 +60,28 @@ export const deleteStockLocationDocument = graphql(`
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
`);
|
|
63
|
+
|
|
64
|
+
export const deleteStockLocationsDocument = graphql(`
|
|
65
|
+
mutation DeleteStockLocations($input: [DeleteStockLocationInput!]!) {
|
|
66
|
+
deleteStockLocations(input: $input) {
|
|
67
|
+
result
|
|
68
|
+
message
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
`);
|
|
72
|
+
|
|
73
|
+
export const assignStockLocationsToChannelDocument = graphql(`
|
|
74
|
+
mutation AssignStockLocationsToChannel($input: AssignStockLocationsToChannelInput!) {
|
|
75
|
+
assignStockLocationsToChannel(input: $input) {
|
|
76
|
+
id
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`);
|
|
80
|
+
|
|
81
|
+
export const removeStockLocationsFromChannelDocument = graphql(`
|
|
82
|
+
mutation RemoveStockLocationsFromChannel($input: RemoveStockLocationsFromChannelInput!) {
|
|
83
|
+
removeStockLocationsFromChannel(input: $input) {
|
|
84
|
+
id
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
`);
|
|
@@ -6,6 +6,11 @@ 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 {
|
|
10
|
+
AssignStockLocationsToChannelBulkAction,
|
|
11
|
+
DeleteStockLocationsBulkAction,
|
|
12
|
+
RemoveStockLocationsFromChannelBulkAction,
|
|
13
|
+
} from './components/stock-location-bulk-actions.js';
|
|
9
14
|
import { deleteStockLocationDocument, stockLocationListQuery } from './stock-locations.graphql.js';
|
|
10
15
|
|
|
11
16
|
export const Route = createFileRoute('/_authenticated/_stock-locations/stock-locations')({
|
|
@@ -32,6 +37,20 @@ function StockLocationListPage() {
|
|
|
32
37
|
name: { contains: searchTerm },
|
|
33
38
|
};
|
|
34
39
|
}}
|
|
40
|
+
bulkActions={[
|
|
41
|
+
{
|
|
42
|
+
component: AssignStockLocationsToChannelBulkAction,
|
|
43
|
+
order: 100,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
component: RemoveStockLocationsFromChannelBulkAction,
|
|
47
|
+
order: 200,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
component: DeleteStockLocationsBulkAction,
|
|
51
|
+
order: 500,
|
|
52
|
+
},
|
|
53
|
+
]}
|
|
35
54
|
>
|
|
36
55
|
<PageActionBarRight>
|
|
37
56
|
<PermissionGuard requires={['CreateStockLocation']}>
|
package/src/app/routes/_authenticated/_tax-categories/components/tax-category-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 { deleteTaxCategoriesDocument } from '../tax-categories.graphql.js';
|
|
4
|
+
|
|
5
|
+
export const DeleteTaxCategoriesBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
6
|
+
return (
|
|
7
|
+
<DeleteBulkAction
|
|
8
|
+
mutationDocument={deleteTaxCategoriesDocument}
|
|
9
|
+
entityName="tax categories"
|
|
10
|
+
requiredPermissions={['DeleteTaxCategory']}
|
|
11
|
+
selection={selection}
|
|
12
|
+
table={table}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -7,6 +7,7 @@ import { ListPage } from '@/framework/page/list-page.js';
|
|
|
7
7
|
import { Trans } from '@/lib/trans.js';
|
|
8
8
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
9
9
|
import { PlusIcon } from 'lucide-react';
|
|
10
|
+
import { DeleteTaxCategoriesBulkAction } from './components/tax-category-bulk-actions.js';
|
|
10
11
|
import { deleteTaxCategoryDocument, taxCategoryListQuery } from './tax-categories.graphql.js';
|
|
11
12
|
|
|
12
13
|
export const Route = createFileRoute('/_authenticated/_tax-categories/tax-categories')({
|
|
@@ -49,6 +50,12 @@ function TaxCategoryListPage() {
|
|
|
49
50
|
),
|
|
50
51
|
},
|
|
51
52
|
}}
|
|
53
|
+
bulkActions={[
|
|
54
|
+
{
|
|
55
|
+
component: DeleteTaxCategoriesBulkAction,
|
|
56
|
+
order: 500,
|
|
57
|
+
},
|
|
58
|
+
]}
|
|
52
59
|
>
|
|
53
60
|
<PageActionBarRight>
|
|
54
61
|
<PermissionGuard requires={['CreateTaxCategory']}>
|
|
@@ -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 { deleteTaxRatesDocument } from '../tax-rates.graphql.js';
|
|
4
|
+
|
|
5
|
+
export const DeleteTaxRatesBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
6
|
+
return (
|
|
7
|
+
<DeleteBulkAction
|
|
8
|
+
mutationDocument={deleteTaxRatesDocument}
|
|
9
|
+
entityName="tax rates"
|
|
10
|
+
requiredPermissions={['DeleteTaxRate']}
|
|
11
|
+
selection={selection}
|
|
12
|
+
table={table}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -10,6 +10,7 @@ import { createFileRoute, Link } from '@tanstack/react-router';
|
|
|
10
10
|
import { PlusIcon } from 'lucide-react';
|
|
11
11
|
import { taxCategoryListQuery } from '../_tax-categories/tax-categories.graphql.js';
|
|
12
12
|
import { zoneListQuery } from '../_zones/zones.graphql.js';
|
|
13
|
+
import { DeleteTaxRatesBulkAction } from './components/tax-rate-bulk-actions.js';
|
|
13
14
|
import { deleteTaxRateDocument, taxRateListQuery } from './tax-rates.graphql.js';
|
|
14
15
|
|
|
15
16
|
export const Route = createFileRoute('/_authenticated/_tax-rates/tax-rates')({
|
|
@@ -92,6 +93,12 @@ function TaxRateListPage() {
|
|
|
92
93
|
cell: ({ row }) => `${row.original.value}%`,
|
|
93
94
|
},
|
|
94
95
|
}}
|
|
96
|
+
bulkActions={[
|
|
97
|
+
{
|
|
98
|
+
component: DeleteTaxRatesBulkAction,
|
|
99
|
+
order: 500,
|
|
100
|
+
},
|
|
101
|
+
]}
|
|
95
102
|
>
|
|
96
103
|
<PageActionBarRight>
|
|
97
104
|
<PermissionGuard requires={['CreateTaxRate']}>
|
|
@@ -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 { deleteZonesDocument } from '../zones.graphql.js';
|
|
4
|
+
|
|
5
|
+
export const DeleteZonesBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
|
|
6
|
+
return (
|
|
7
|
+
<DeleteBulkAction
|
|
8
|
+
mutationDocument={deleteZonesDocument}
|
|
9
|
+
entityName="zones"
|
|
10
|
+
requiredPermissions={['DeleteZone']}
|
|
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 { DeleteZonesBulkAction } from './components/zone-bulk-actions.js';
|
|
9
10
|
import { ZoneCountriesSheet } from './components/zone-countries-sheet.js';
|
|
10
11
|
import { deleteZoneDocument, zoneListQuery } from './zones.graphql.js';
|
|
11
12
|
|
|
@@ -41,6 +42,12 @@ function ZoneListPage() {
|
|
|
41
42
|
),
|
|
42
43
|
},
|
|
43
44
|
}}
|
|
45
|
+
bulkActions={[
|
|
46
|
+
{
|
|
47
|
+
component: DeleteZonesBulkAction,
|
|
48
|
+
order: 500,
|
|
49
|
+
},
|
|
50
|
+
]}
|
|
44
51
|
>
|
|
45
52
|
<PageActionBarRight>
|
|
46
53
|
<PermissionGuard requires={['CreateZone']}>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Button } from '@/components/ui/button.js';
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuContent,
|
|
7
|
+
DropdownMenuItem,
|
|
8
|
+
DropdownMenuTrigger,
|
|
9
|
+
} from '@/components/ui/dropdown-menu.js';
|
|
10
|
+
import { getBulkActions } from '@/framework/data-table/data-table-extensions.js';
|
|
11
|
+
import { usePageBlock } from '@/hooks/use-page-block.js';
|
|
12
|
+
import { usePage } from '@/hooks/use-page.js';
|
|
13
|
+
import { Trans } from '@/lib/trans.js';
|
|
14
|
+
import { ChevronDown } from 'lucide-react';
|
|
15
|
+
import { Asset } from './asset-gallery.js';
|
|
16
|
+
|
|
17
|
+
export type AssetBulkActionContext = {
|
|
18
|
+
selection: Asset[];
|
|
19
|
+
refetch: () => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type AssetBulkActionComponent = React.FunctionComponent<AssetBulkActionContext>;
|
|
23
|
+
|
|
24
|
+
export type AssetBulkAction = {
|
|
25
|
+
order?: number;
|
|
26
|
+
component: AssetBulkActionComponent;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
interface AssetBulkActionsProps {
|
|
30
|
+
selection: Asset[];
|
|
31
|
+
bulkActions?: AssetBulkAction[];
|
|
32
|
+
refetch: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function AssetBulkActions({ selection, bulkActions, refetch }: AssetBulkActionsProps) {
|
|
36
|
+
const { pageId } = usePage();
|
|
37
|
+
const { blockId } = usePageBlock();
|
|
38
|
+
|
|
39
|
+
if (selection.length === 0) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Get extended bulk actions from the registry
|
|
44
|
+
const extendedBulkActions = pageId ? getBulkActions(pageId, blockId) : [];
|
|
45
|
+
|
|
46
|
+
// Convert DataTable bulk actions to Asset bulk actions
|
|
47
|
+
const convertedBulkActions: AssetBulkAction[] = extendedBulkActions.map(action => ({
|
|
48
|
+
order: action.order,
|
|
49
|
+
component: ({ selection }) => {
|
|
50
|
+
// Create a mock table context for compatibility
|
|
51
|
+
const mockTable = {
|
|
52
|
+
getState: () => ({ rowSelection: {} }),
|
|
53
|
+
getRow: () => null,
|
|
54
|
+
} as any;
|
|
55
|
+
|
|
56
|
+
const ActionComponent = action.component;
|
|
57
|
+
return <ActionComponent selection={selection} table={mockTable} />;
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
const allBulkActions = [...convertedBulkActions, ...(bulkActions ?? [])];
|
|
62
|
+
allBulkActions.sort((a, b) => (a.order ?? 10_000) - (b.order ?? 10_000));
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className="flex items-center gap-2 px-2 py-1 mb-2 bg-muted/50 rounded-md border">
|
|
66
|
+
<span className="text-sm text-muted-foreground">
|
|
67
|
+
<Trans>{selection.length} selected</Trans>
|
|
68
|
+
</span>
|
|
69
|
+
<DropdownMenu>
|
|
70
|
+
<DropdownMenuTrigger asChild>
|
|
71
|
+
<Button variant="outline" size="sm" className="h-8">
|
|
72
|
+
<Trans>With selected...</Trans>
|
|
73
|
+
<ChevronDown className="ml-2 h-4 w-4" />
|
|
74
|
+
</Button>
|
|
75
|
+
</DropdownMenuTrigger>
|
|
76
|
+
<DropdownMenuContent align="start">
|
|
77
|
+
{allBulkActions.length > 0 ? (
|
|
78
|
+
allBulkActions.map((action, index) => (
|
|
79
|
+
<action.component key={`asset-bulk-action-${index}`} selection={selection} refetch={refetch} />
|
|
80
|
+
))
|
|
81
|
+
) : (
|
|
82
|
+
<DropdownMenuItem className="text-muted-foreground" disabled>
|
|
83
|
+
<Trans>No actions available</Trans>
|
|
84
|
+
</DropdownMenuItem>
|
|
85
|
+
)}
|
|
86
|
+
</DropdownMenuContent>
|
|
87
|
+
</DropdownMenu>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -16,14 +16,15 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
|
|
|
16
16
|
import { api } from '@/graphql/api.js';
|
|
17
17
|
import { assetFragment, AssetFragment } from '@/graphql/fragments.js';
|
|
18
18
|
import { graphql } from '@/graphql/graphql.js';
|
|
19
|
-
import { formatFileSize } from '@/lib/utils.js';
|
|
20
19
|
import { Trans } from '@/lib/trans.js';
|
|
20
|
+
import { formatFileSize } from '@/lib/utils.js';
|
|
21
21
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
22
|
+
import { useDebounce } from '@uidotdev/usehooks';
|
|
22
23
|
import { Loader2, Search, Upload, X } from 'lucide-react';
|
|
23
24
|
import { useCallback, useState } from 'react';
|
|
24
25
|
import { useDropzone } from 'react-dropzone';
|
|
25
|
-
import { useDebounce } from '@uidotdev/usehooks';
|
|
26
26
|
import { DetailPageButton } from '../detail-page-button.js';
|
|
27
|
+
import { AssetBulkAction, AssetBulkActions } from './asset-bulk-actions.js';
|
|
27
28
|
|
|
28
29
|
const getAssetListDocument = graphql(
|
|
29
30
|
`
|
|
@@ -76,7 +77,7 @@ export interface AssetGalleryProps {
|
|
|
76
77
|
/**
|
|
77
78
|
* @description
|
|
78
79
|
* Defines whether multiple assets can be selected.
|
|
79
|
-
*
|
|
80
|
+
*
|
|
80
81
|
* If set to 'auto', the asset selection will be toggled when the user clicks on an asset.
|
|
81
82
|
* If set to 'manual', multiple selection will occur only if the user holds down the control/cmd key.
|
|
82
83
|
*/
|
|
@@ -87,6 +88,7 @@ export interface AssetGalleryProps {
|
|
|
87
88
|
showHeader?: boolean;
|
|
88
89
|
className?: string;
|
|
89
90
|
onFilesDropped?: (files: File[]) => void;
|
|
91
|
+
bulkActions?: AssetBulkAction[];
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
export function AssetGallery({
|
|
@@ -99,6 +101,7 @@ export function AssetGallery({
|
|
|
99
101
|
showHeader = true,
|
|
100
102
|
className = '',
|
|
101
103
|
onFilesDropped,
|
|
104
|
+
bulkActions,
|
|
102
105
|
}: AssetGalleryProps) {
|
|
103
106
|
// State
|
|
104
107
|
const [page, setPage] = useState(1);
|
|
@@ -111,7 +114,7 @@ export function AssetGallery({
|
|
|
111
114
|
const queryKey = ['AssetGallery', page, pageSize, debouncedSearch, assetType];
|
|
112
115
|
|
|
113
116
|
// Query for assets
|
|
114
|
-
const { data, isLoading } = useQuery({
|
|
117
|
+
const { data, isLoading, refetch } = useQuery({
|
|
115
118
|
queryKey,
|
|
116
119
|
queryFn: () => {
|
|
117
120
|
const filter: Record<string, any> = {};
|
|
@@ -173,7 +176,6 @@ export function AssetGallery({
|
|
|
173
176
|
return;
|
|
174
177
|
}
|
|
175
178
|
|
|
176
|
-
|
|
177
179
|
// Manual mode - check for modifier key
|
|
178
180
|
const isModifierKeyPressed = event.metaKey || event.ctrlKey;
|
|
179
181
|
|
|
@@ -269,6 +271,9 @@ export function AssetGallery({
|
|
|
269
271
|
</div>
|
|
270
272
|
)}
|
|
271
273
|
|
|
274
|
+
{/* Bulk actions bar */}
|
|
275
|
+
<AssetBulkActions selection={selected} bulkActions={bulkActions} refetch={refetch} />
|
|
276
|
+
|
|
272
277
|
<div
|
|
273
278
|
{...getRootProps()}
|
|
274
279
|
className={`
|
|
@@ -300,7 +305,7 @@ export function AssetGallery({
|
|
|
300
305
|
${isSelected(asset as Asset) ? 'ring-2 ring-primary' : ''}
|
|
301
306
|
flex flex-col min-w-[120px]
|
|
302
307
|
`}
|
|
303
|
-
onClick={
|
|
308
|
+
onClick={e => handleSelect(asset as Asset, e)}
|
|
304
309
|
>
|
|
305
310
|
<div
|
|
306
311
|
className="relative w-full bg-muted/30"
|
|
@@ -324,7 +329,7 @@ export function AssetGallery({
|
|
|
324
329
|
<p className="text-xs line-clamp-2 min-h-[2.5rem]" title={asset.name}>
|
|
325
330
|
{asset.name}
|
|
326
331
|
</p>
|
|
327
|
-
<div className=
|
|
332
|
+
<div className="flex justify-between items-center">
|
|
328
333
|
{asset.fileSize && (
|
|
329
334
|
<p className="text-xs text-muted-foreground mt-1">
|
|
330
335
|
{formatFileSize(asset.fileSize)}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { LayersIcon } from 'lucide-react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { DataTableBulkActionItem } from '@/components/data-table/data-table-bulk-action-item.js';
|
|
5
|
+
import { AssignToChannelDialog } from '@/components/shared/assign-to-channel-dialog.js';
|
|
6
|
+
import { useChannel, usePaginatedList } from '@/index.js';
|
|
7
|
+
import { Trans } from '@/lib/trans.js';
|
|
8
|
+
|
|
9
|
+
interface AssignToChannelBulkActionProps {
|
|
10
|
+
selection: any[];
|
|
11
|
+
table: any;
|
|
12
|
+
entityType: string;
|
|
13
|
+
mutationFn: (variables: any) => Promise<any>;
|
|
14
|
+
requiredPermissions: string[];
|
|
15
|
+
buildInput: (channelId: string, additionalData?: Record<string, any>) => Record<string, any>;
|
|
16
|
+
additionalFields?: React.ReactNode;
|
|
17
|
+
additionalData?: Record<string, any>;
|
|
18
|
+
/**
|
|
19
|
+
* Additional callback to run on success, after the standard refetch and reset
|
|
20
|
+
*/
|
|
21
|
+
onSuccess?: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function AssignToChannelBulkAction({
|
|
25
|
+
selection,
|
|
26
|
+
table,
|
|
27
|
+
entityType,
|
|
28
|
+
mutationFn,
|
|
29
|
+
requiredPermissions,
|
|
30
|
+
buildInput,
|
|
31
|
+
additionalFields,
|
|
32
|
+
additionalData = {},
|
|
33
|
+
onSuccess,
|
|
34
|
+
}: Readonly<AssignToChannelBulkActionProps>) {
|
|
35
|
+
const { refetchPaginatedList } = usePaginatedList();
|
|
36
|
+
const { channels } = useChannel();
|
|
37
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
38
|
+
|
|
39
|
+
if (channels.length < 2) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const handleSuccess = () => {
|
|
44
|
+
refetchPaginatedList();
|
|
45
|
+
table.resetRowSelection();
|
|
46
|
+
onSuccess?.();
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
<DataTableBulkActionItem
|
|
52
|
+
requiresPermission={requiredPermissions}
|
|
53
|
+
onClick={() => setDialogOpen(true)}
|
|
54
|
+
label={<Trans>Assign to channel</Trans>}
|
|
55
|
+
icon={LayersIcon}
|
|
56
|
+
/>
|
|
57
|
+
<AssignToChannelDialog
|
|
58
|
+
open={dialogOpen}
|
|
59
|
+
onOpenChange={setDialogOpen}
|
|
60
|
+
entityIds={selection.map(s => s.id)}
|
|
61
|
+
entityType={entityType}
|
|
62
|
+
mutationFn={mutationFn}
|
|
63
|
+
onSuccess={handleSuccess}
|
|
64
|
+
buildInput={buildInput}
|
|
65
|
+
additionalFields={additionalFields}
|
|
66
|
+
additionalData={additionalData}
|
|
67
|
+
/>
|
|
68
|
+
</>
|
|
69
|
+
);
|
|
70
|
+
}
|