@vendure/dashboard 3.6.0-minor-202511061555 → 3.6.0-minor-202512161454

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.
Files changed (152) hide show
  1. package/dist/plugin/constants.js +2 -2
  2. package/dist/vite/constants.js +1 -0
  3. package/dist/vite/utils/compiler.d.ts +1 -0
  4. package/dist/vite/utils/compiler.js +5 -4
  5. package/dist/vite/utils/get-dashboard-paths.d.ts +5 -0
  6. package/dist/vite/utils/get-dashboard-paths.js +20 -0
  7. package/dist/vite/vite-plugin-dashboard-metadata.js +2 -1
  8. package/dist/vite/vite-plugin-tailwind-source.js +2 -15
  9. package/dist/vite/vite-plugin-translations.d.ts +10 -1
  10. package/dist/vite/vite-plugin-translations.js +156 -45
  11. package/dist/vite/vite-plugin-vendure-dashboard.d.ts +12 -0
  12. package/dist/vite/vite-plugin-vendure-dashboard.js +1 -0
  13. package/lingui.config.js +1 -0
  14. package/package.json +7 -7
  15. package/src/app/routeTree.gen.ts +1221 -0
  16. package/src/app/routes/_authenticated/_administrators/administrators.tsx +9 -12
  17. package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +9 -12
  18. package/src/app/routes/_authenticated/_assets/assets_.$id.tsx +6 -9
  19. package/src/app/routes/_authenticated/_channels/channels.tsx +9 -12
  20. package/src/app/routes/_authenticated/_channels/channels_.$id.tsx +9 -12
  21. package/src/app/routes/_authenticated/_collections/collections.tsx +9 -12
  22. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +9 -12
  23. package/src/app/routes/_authenticated/_countries/countries.tsx +9 -12
  24. package/src/app/routes/_authenticated/_countries/countries_.$id.tsx +9 -12
  25. package/src/app/routes/_authenticated/_customer-groups/customer-groups.tsx +9 -12
  26. package/src/app/routes/_authenticated/_customer-groups/customer-groups_.$id.tsx +9 -12
  27. package/src/app/routes/_authenticated/_customers/components/customer-history/index.ts +0 -1
  28. package/src/app/routes/_authenticated/_customers/customers.tsx +9 -12
  29. package/src/app/routes/_authenticated/_customers/customers_.$id.tsx +9 -12
  30. package/src/app/routes/_authenticated/_facets/facets.tsx +9 -12
  31. package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +9 -12
  32. package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +9 -12
  33. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +10 -13
  34. package/src/app/routes/_authenticated/_orders/components/add-surcharge-form.tsx +139 -0
  35. package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +3 -0
  36. package/src/app/routes/_authenticated/_orders/components/fulfill-order-dialog.tsx +3 -1
  37. package/src/app/routes/_authenticated/_orders/components/order-address.tsx +3 -3
  38. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +41 -41
  39. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-utils.tsx +1 -1
  40. package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +49 -11
  41. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +4 -1
  42. package/src/app/routes/_authenticated/_orders/components/use-transition-order-to-state.tsx +2 -3
  43. package/src/app/routes/_authenticated/_orders/orders.tsx +3 -3
  44. package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +12 -3
  45. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +27 -30
  46. package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +23 -0
  47. package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +9 -12
  48. package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +9 -12
  49. package/src/app/routes/_authenticated/_product-variants/components/add-currency-dropdown.tsx +3 -3
  50. package/src/app/routes/_authenticated/_product-variants/components/add-stock-location-dropdown.tsx +2 -2
  51. package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +1 -0
  52. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +10 -12
  53. package/src/app/routes/_authenticated/_products/products.graphql.ts +1 -0
  54. package/src/app/routes/_authenticated/_products/products.tsx +15 -18
  55. package/src/app/routes/_authenticated/_products/products_.$id.tsx +9 -12
  56. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$id.tsx +9 -12
  57. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +9 -12
  58. package/src/app/routes/_authenticated/_profile/profile.tsx +3 -3
  59. package/src/app/routes/_authenticated/_promotions/promotions.tsx +9 -12
  60. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +9 -12
  61. package/src/app/routes/_authenticated/_roles/roles.tsx +9 -12
  62. package/src/app/routes/_authenticated/_roles/roles_.$id.tsx +9 -12
  63. package/src/app/routes/_authenticated/_sellers/sellers.tsx +9 -12
  64. package/src/app/routes/_authenticated/_sellers/sellers_.$id.tsx +9 -12
  65. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +11 -12
  66. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +19 -20
  67. package/src/app/routes/_authenticated/_stock-locations/stock-locations.tsx +9 -12
  68. package/src/app/routes/_authenticated/_stock-locations/stock-locations_.$id.tsx +9 -12
  69. package/src/app/routes/_authenticated/_system/healthchecks.tsx +2 -3
  70. package/src/app/routes/_authenticated/_system/job-queue.tsx +3 -3
  71. package/src/app/routes/_authenticated/_tax-categories/tax-categories.tsx +9 -12
  72. package/src/app/routes/_authenticated/_tax-categories/tax-categories_.$id.tsx +9 -12
  73. package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +9 -12
  74. package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +9 -12
  75. package/src/app/routes/_authenticated/_zones/components/zone-bulk-actions.tsx +49 -1
  76. package/src/app/routes/_authenticated/_zones/components/zone-countries-table.tsx +34 -16
  77. package/src/app/routes/_authenticated/_zones/zones.tsx +9 -12
  78. package/src/app/routes/_authenticated/_zones/zones_.$id.tsx +9 -12
  79. package/src/app/routes/_authenticated/index.tsx +5 -3
  80. package/src/i18n/locales/bg.po +3436 -0
  81. package/src/lib/components/data-input/datetime-input.tsx +1 -1
  82. package/src/lib/components/data-input/default-relation-input.tsx +1 -1
  83. package/src/lib/components/data-input/relation-selector.tsx +1 -1
  84. package/src/lib/components/data-input/string-list-input.tsx +188 -26
  85. package/src/lib/components/data-input/struct-form-input.tsx +175 -174
  86. package/src/lib/components/data-table/column-header-wrapper.tsx +1 -1
  87. package/src/lib/components/data-table/data-table-filter-badge.tsx +2 -2
  88. package/src/lib/components/data-table/data-table.tsx +1 -1
  89. package/src/lib/components/data-table/use-generated-columns.tsx +1 -1
  90. package/src/lib/components/layout/channel-switcher.tsx +6 -2
  91. package/src/lib/components/layout/content-language-selector.tsx +6 -7
  92. package/src/lib/components/layout/dev-mode-indicator.tsx +7 -3
  93. package/src/lib/components/layout/language-dialog.tsx +26 -13
  94. package/src/lib/components/layout/manage-languages-dialog.tsx +10 -29
  95. package/src/lib/components/layout/nav-item-wrapper.tsx +1 -1
  96. package/src/lib/components/shared/asset/asset-gallery.tsx +8 -3
  97. package/src/lib/components/shared/configurable-operation-multi-selector.tsx +14 -16
  98. package/src/lib/components/shared/custom-fields-form.tsx +14 -9
  99. package/src/lib/components/shared/language-selector.tsx +14 -6
  100. package/src/lib/components/shared/multi-select.tsx +1 -1
  101. package/src/lib/components/shared/navigation-confirmation.tsx +1 -1
  102. package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +4 -4
  103. package/src/lib/components/ui/carousel.tsx +2 -2
  104. package/src/lib/components/ui/chart.tsx +1 -1
  105. package/src/lib/components/ui/context-menu.tsx +1 -1
  106. package/src/lib/components/ui/drawer.tsx +1 -1
  107. package/src/lib/components/ui/grid-layout.tsx +1 -1
  108. package/src/lib/components/ui/input-group.tsx +1 -0
  109. package/src/lib/components/ui/input-otp.tsx +1 -1
  110. package/src/lib/components/ui/menubar.tsx +1 -1
  111. package/src/lib/components/ui/navigation-menu.tsx +1 -1
  112. package/src/lib/components/ui/progress.tsx +1 -1
  113. package/src/lib/components/ui/radio-group.tsx +1 -1
  114. package/src/lib/components/ui/resizable.tsx +1 -1
  115. package/src/lib/components/ui/select.tsx +1 -1
  116. package/src/lib/components/ui/slider.tsx +1 -1
  117. package/src/lib/components/ui/toggle-group.tsx +2 -2
  118. package/src/lib/components/ui/toggle.tsx +1 -1
  119. package/src/lib/framework/component-registry/component-registry.tsx +2 -6
  120. package/src/lib/framework/document-introspection/add-custom-fields.spec.ts +907 -1
  121. package/src/lib/framework/document-introspection/add-custom-fields.ts +248 -119
  122. package/src/lib/framework/extension-api/display-component-extensions.tsx +4 -3
  123. package/src/lib/framework/extension-api/logic/detail-forms.ts +0 -13
  124. package/src/lib/framework/extension-api/logic/navigation.ts +1 -1
  125. package/src/lib/framework/extension-api/types/data-table.ts +4 -2
  126. package/src/lib/framework/extension-api/types/layout.ts +34 -1
  127. package/src/lib/framework/extension-api/types/navigation.ts +7 -2
  128. package/src/lib/framework/form-engine/use-generated-form.tsx +7 -1
  129. package/src/lib/framework/history-entry/history-entry.tsx +1 -1
  130. package/src/lib/framework/layout-engine/action-bar-item-wrapper.tsx +185 -0
  131. package/src/lib/framework/layout-engine/dev-mode-button.tsx +15 -13
  132. package/src/lib/framework/layout-engine/location-wrapper.tsx +3 -1
  133. package/src/lib/framework/layout-engine/page-layout.spec.tsx +138 -0
  134. package/src/lib/framework/layout-engine/page-layout.tsx +294 -69
  135. package/src/lib/framework/nav-menu/nav-menu-extensions.ts +1 -1
  136. package/src/lib/framework/page/detail-page-route-loader.tsx +1 -1
  137. package/src/lib/framework/page/page-api.ts +1 -1
  138. package/src/lib/framework/page/use-detail-page.ts +4 -2
  139. package/src/lib/framework/page/use-extended-router.tsx +20 -16
  140. package/src/lib/framework/registry/registry-types.ts +2 -1
  141. package/src/lib/graphql/api.ts +3 -8
  142. package/src/lib/graphql/graphql-env.d.ts +29 -10
  143. package/src/lib/hooks/use-permissions.ts +3 -3
  144. package/src/lib/hooks/use-sorted-languages.ts +41 -0
  145. package/src/lib/index.ts +1 -0
  146. package/src/lib/lib/load-i18n-messages.ts +4 -1
  147. package/src/lib/providers/channel-provider.tsx +11 -7
  148. package/src/lib/utils/config-utils.ts +19 -0
  149. package/src/lib/virtual.d.ts +3 -0
  150. package/LICENSE.md +0 -42
  151. package/src/app/routes/_authenticated/_facets/components/edit-facet-value.tsx +0 -129
  152. /package/src/{app/routes/_authenticated/_global-settings → lib}/utils/global-languages.ts +0 -0
@@ -2,15 +2,14 @@ import { ConfirmationDialog } from '@/vdb/components/shared/confirmation-dialog.
2
2
  import { CustomFieldsForm } from '@/vdb/components/shared/custom-fields-form.js';
3
3
  import { CustomerSelector } from '@/vdb/components/shared/customer-selector.js';
4
4
  import { ErrorPage } from '@/vdb/components/shared/error-page.js';
5
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
6
5
  import { Button } from '@/vdb/components/ui/button.js';
7
6
  import { Form } from '@/vdb/components/ui/form.js';
8
7
  import { addCustomFields } from '@/vdb/framework/document-introspection/add-custom-fields.js';
9
8
  import { useGeneratedForm } from '@/vdb/framework/form-engine/use-generated-form.js';
10
9
  import {
10
+ ActionBarItem,
11
11
  Page,
12
12
  PageActionBar,
13
- PageActionBarRight,
14
13
  PageBlock,
15
14
  PageLayout,
16
15
  PageTitle,
@@ -295,35 +294,33 @@ function DraftOrderPage() {
295
294
  <Trans>Draft order</Trans>: {entity?.code ?? ''}
296
295
  </PageTitle>
297
296
  <PageActionBar>
298
- <PageActionBarRight>
299
- <PermissionGuard requires={['DeleteOrder']}>
300
- <ConfirmationDialog
301
- title={t`Delete draft order`}
302
- description={t`Are you sure you want to delete this draft order?`}
303
- onConfirm={() => {
304
- deleteDraftOrder({ orderId: entity.id });
305
- }}
306
- >
307
- <Button variant="destructive" type="button">
308
- <Trans>Delete draft</Trans>
309
- </Button>
310
- </ConfirmationDialog>
311
- </PermissionGuard>
312
- <PermissionGuard requires={['UpdateOrder']}>
313
- <Button
314
- type="button"
315
- disabled={
316
- !entity.customer ||
317
- entity.lines.length === 0 ||
318
- entity.shippingLines.length === 0 ||
319
- entity.state !== 'Draft'
320
- }
321
- onClick={() => completeDraftOrder({ id: entity.id, state: 'ArrangingPayment' })}
322
- >
323
- <Trans>Complete draft</Trans>
297
+ <ActionBarItem itemId="delete-button" requiresPermission={['DeleteOrder']}>
298
+ <ConfirmationDialog
299
+ title={t`Delete draft order`}
300
+ description={t`Are you sure you want to delete this draft order?`}
301
+ onConfirm={() => {
302
+ deleteDraftOrder({ orderId: entity.id });
303
+ }}
304
+ >
305
+ <Button variant="destructive" type="button">
306
+ <Trans>Delete draft</Trans>
324
307
  </Button>
325
- </PermissionGuard>
326
- </PageActionBarRight>
308
+ </ConfirmationDialog>
309
+ </ActionBarItem>
310
+ <ActionBarItem itemId="complete-draft-button" requiresPermission={['UpdateOrder']}>
311
+ <Button
312
+ type="button"
313
+ disabled={
314
+ !entity.customer ||
315
+ entity.lines.length === 0 ||
316
+ entity.shippingLines.length === 0 ||
317
+ entity.state !== 'Draft'
318
+ }
319
+ onClick={() => completeDraftOrder({ id: entity.id, state: 'ArrangingPayment' })}
320
+ >
321
+ <Trans>Complete draft</Trans>
322
+ </Button>
323
+ </ActionBarItem>
327
324
  </PageActionBar>
328
325
  <PageLayout>
329
326
  <PageBlock column="main" blockId="order-table">
@@ -18,6 +18,8 @@ export type ProductVariantInfo = {
18
18
  priceWithTax?: number;
19
19
  };
20
20
 
21
+ type SurchargeInput = NonNullable<ModifyOrderInput['surcharges']>[number];
22
+
21
23
  export interface UseModifyOrderReturn {
22
24
  modifyOrderInput: ModifyOrderInput;
23
25
  addedVariants: Map<string, ProductVariantInfo>;
@@ -33,6 +35,8 @@ export interface UseModifyOrderReturn {
33
35
  removeCouponCode: (params: { couponCode: string }) => void;
34
36
  updateShippingAddress: (address: AddressFragment) => void;
35
37
  updateBillingAddress: (address: AddressFragment) => void;
38
+ addSurcharge: (surcharge: SurchargeInput) => void;
39
+ setNote: (note: string) => void;
36
40
  hasModifications: boolean;
37
41
  }
38
42
 
@@ -284,6 +288,22 @@ export function useModifyOrder(order: Order | null | undefined): UseModifyOrderR
284
288
  }));
285
289
  }, []);
286
290
 
291
+ // Add surcharge
292
+ const addSurcharge = useCallback((surcharge: SurchargeInput) => {
293
+ setModifyOrderInput(prev => ({
294
+ ...prev,
295
+ surcharges: [...(prev.surcharges ?? []), surcharge],
296
+ }));
297
+ }, []);
298
+
299
+ // Set note
300
+ const setNote = useCallback((note: string) => {
301
+ setModifyOrderInput(prev => ({
302
+ ...prev,
303
+ note: note || '',
304
+ }));
305
+ }, []);
306
+
287
307
  // Check if there are modifications
288
308
  const hasModifications = useMemo(() => {
289
309
  return (
@@ -291,6 +311,7 @@ export function useModifyOrder(order: Order | null | undefined): UseModifyOrderR
291
311
  (modifyOrderInput.adjustOrderLines?.length ?? 0) > 0 ||
292
312
  (modifyOrderInput.couponCodes?.length ?? 0) > 0 ||
293
313
  (modifyOrderInput.shippingMethodIds?.length ?? 0) > 0 ||
314
+ (modifyOrderInput.surcharges?.length ?? 0) > 0 ||
294
315
  !!modifyOrderInput.updateShippingAddress ||
295
316
  !!modifyOrderInput.updateBillingAddress
296
317
  );
@@ -307,6 +328,8 @@ export function useModifyOrder(order: Order | null | undefined): UseModifyOrderR
307
328
  removeCouponCode,
308
329
  updateShippingAddress,
309
330
  updateBillingAddress,
331
+ addSurcharge,
332
+ setNote,
310
333
  hasModifications,
311
334
  };
312
335
  }
@@ -1,9 +1,8 @@
1
1
  import { BooleanDisplayBadge } from '@/vdb/components/data-display/boolean.js';
2
2
  import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
3
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
4
3
  import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
5
4
  import { Button } from '@/vdb/components/ui/button.js';
6
- import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
5
+ import { ActionBarItem } from '@/vdb/framework/layout-engine/page-layout.js';
7
6
  import { ListPage } from '@/vdb/framework/page/list-page.js';
8
7
  import { Trans, useLingui } from '@lingui/react/macro';
9
8
  import { createFileRoute, Link } from '@tanstack/react-router';
@@ -73,16 +72,14 @@ function PaymentMethodListPage() {
73
72
  },
74
73
  ]}
75
74
  >
76
- <PageActionBarRight>
77
- <PermissionGuard requires={['CreatePaymentMethod']}>
78
- <Button asChild>
79
- <Link to="./new">
80
- <PlusIcon className="mr-2 h-4 w-4" />
81
- <Trans>New Payment Method</Trans>
82
- </Link>
83
- </Button>
84
- </PermissionGuard>
85
- </PageActionBarRight>
75
+ <ActionBarItem itemId="create-button" requiresPermission={['CreatePaymentMethod']}>
76
+ <Button asChild>
77
+ <Link to="./new">
78
+ <PlusIcon className="mr-2 h-4 w-4" />
79
+ <Trans>New Payment Method</Trans>
80
+ </Link>
81
+ </Button>
82
+ </ActionBarItem>
86
83
  </ListPage>
87
84
  );
88
85
  }
@@ -1,18 +1,17 @@
1
1
  import { RichTextInput } from '@/vdb/components/data-input/rich-text-input.js';
2
2
  import { ErrorPage } from '@/vdb/components/shared/error-page.js';
3
3
  import { FormFieldWrapper } from '@/vdb/components/shared/form-field-wrapper.js';
4
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
5
4
  import { TranslatableFormFieldWrapper } from '@/vdb/components/shared/translatable-form-field.js';
6
5
  import { Button } from '@/vdb/components/ui/button.js';
7
6
  import { Input } from '@/vdb/components/ui/input.js';
8
7
  import { Switch } from '@/vdb/components/ui/switch.js';
9
8
  import { NEW_ENTITY_PATH } from '@/vdb/constants.js';
10
9
  import {
10
+ ActionBarItem,
11
11
  CustomFieldsPageBlock,
12
12
  DetailFormGrid,
13
13
  Page,
14
14
  PageActionBar,
15
- PageActionBarRight,
16
15
  PageBlock,
17
16
  PageLayout,
18
17
  PageTitle,
@@ -121,16 +120,14 @@ function PaymentMethodDetailPage() {
121
120
  {creatingNewEntity ? <Trans>New payment method</Trans> : (entity?.name ?? '')}
122
121
  </PageTitle>
123
122
  <PageActionBar>
124
- <PageActionBarRight>
125
- <PermissionGuard requires={['UpdatePaymentMethod']}>
126
- <Button
127
- type="submit"
128
- disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
129
- >
130
- {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
131
- </Button>
132
- </PermissionGuard>
133
- </PageActionBarRight>
123
+ <ActionBarItem itemId="save-button" requiresPermission={['UpdatePaymentMethod']}>
124
+ <Button
125
+ type="submit"
126
+ disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
127
+ >
128
+ {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
129
+ </Button>
130
+ </ActionBarItem>
134
131
  </PageActionBar>
135
132
  <PageLayout>
136
133
  <PageBlock column="side" blockId="enabled">
@@ -1,14 +1,14 @@
1
1
  import { useLingui } from '@lingui/react/macro';
2
2
  import { PlusIcon } from 'lucide-react';
3
3
 
4
- import { Button } from '@/vdb/components/ui/button';
4
+ import { Button } from '@/vdb/components/ui/button.js';
5
5
  import {
6
6
  DropdownMenu,
7
7
  DropdownMenuContent,
8
8
  DropdownMenuItem,
9
9
  DropdownMenuTrigger,
10
- } from '@/vdb/components/ui/dropdown-menu';
11
- import { useLocalFormat } from '@/vdb/hooks/use-local-format';
10
+ } from '@/vdb/components/ui/dropdown-menu.js';
11
+ import { useLocalFormat } from '@/vdb/hooks/use-local-format.js';
12
12
 
13
13
  interface AddCurrencyDropdownProps {
14
14
  unusedCurrencies: string[];
@@ -1,13 +1,13 @@
1
1
  import { useLingui } from '@lingui/react/macro';
2
2
  import { PlusIcon } from 'lucide-react';
3
3
 
4
- import { Button } from '@/vdb/components/ui/button';
4
+ import { Button } from '@/vdb/components/ui/button.js';
5
5
  import {
6
6
  DropdownMenu,
7
7
  DropdownMenuContent,
8
8
  DropdownMenuItem,
9
9
  DropdownMenuTrigger,
10
- } from '@/vdb/components/ui/dropdown-menu';
10
+ } from '@/vdb/components/ui/dropdown-menu.js';
11
11
  import { ResultOf } from 'gql.tada';
12
12
 
13
13
  import { stockLocationsQueryDocument } from '../product-variants.graphql.js';
@@ -92,6 +92,7 @@ export const productVariantDetailDocument = graphql(
92
92
  }
93
93
  trackInventory
94
94
  outOfStockThreshold
95
+ useGlobalOutOfStockThreshold
95
96
  stockLevels {
96
97
  id
97
98
  stockOnHand
@@ -5,7 +5,6 @@ import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js'
5
5
  import { EntityAssets } from '@/vdb/components/shared/entity-assets.js';
6
6
  import { ErrorPage } from '@/vdb/components/shared/error-page.js';
7
7
  import { FormFieldWrapper } from '@/vdb/components/shared/form-field-wrapper.js';
8
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
9
8
  import { TaxCategorySelector } from '@/vdb/components/shared/tax-category-selector.js';
10
9
  import { TranslatableFormFieldWrapper } from '@/vdb/components/shared/translatable-form-field.js';
11
10
  import { Button } from '@/vdb/components/ui/button.js';
@@ -15,11 +14,11 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
15
14
  import { Switch } from '@/vdb/components/ui/switch.js';
16
15
  import { NEW_ENTITY_PATH } from '@/vdb/constants.js';
17
16
  import {
17
+ ActionBarItem,
18
18
  CustomFieldsPageBlock,
19
19
  DetailFormGrid,
20
20
  Page,
21
21
  PageActionBar,
22
- PageActionBarRight,
23
22
  PageBlock,
24
23
  PageLayout,
25
24
  PageTitle,
@@ -97,6 +96,7 @@ function ProductVariantDetailPage() {
97
96
  prices: entity.prices,
98
97
  trackInventory: entity.trackInventory,
99
98
  outOfStockThreshold: entity.outOfStockThreshold,
99
+ useGlobalOutOfStockThreshold : entity.useGlobalOutOfStockThreshold,
100
100
  stockLevels: entity.stockLevels.map(stockLevel => ({
101
101
  stockOnHand: stockLevel.stockOnHand,
102
102
  stockLocationId: stockLevel.stockLocation.id,
@@ -207,16 +207,14 @@ function ProductVariantDetailPage() {
207
207
  {creatingNewEntity ? <Trans>New product variant</Trans> : (entity?.name ?? '')}
208
208
  </PageTitle>
209
209
  <PageActionBar>
210
- <PageActionBarRight>
211
- <PermissionGuard requires={['UpdateProduct', 'UpdateCatalog']}>
212
- <Button
213
- type="submit"
214
- disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
215
- >
216
- {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
217
- </Button>
218
- </PermissionGuard>
219
- </PageActionBarRight>
210
+ <ActionBarItem itemId="save-button" requiresPermission={['UpdateProduct', 'UpdateCatalog']}>
211
+ <Button
212
+ type="submit"
213
+ disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
214
+ >
215
+ {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
216
+ </Button>
217
+ </ActionBarItem>
220
218
  </PageActionBar>
221
219
  <PageLayout>
222
220
  <PageBlock column="side" blockId="enabled">
@@ -60,6 +60,7 @@ export const productDetailFragment = graphql(
60
60
  code
61
61
  }
62
62
  }
63
+ customFields
63
64
  }
64
65
  `,
65
66
  [assetFragment],
@@ -1,8 +1,7 @@
1
1
  import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
2
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
3
2
  import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
4
3
  import { Button } from '@/vdb/components/ui/button.js';
5
- import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
4
+ import { ActionBarItem } from '@/vdb/framework/layout-engine/page-layout.js';
6
5
  import { ListPage } from '@/vdb/framework/page/list-page.js';
7
6
  import { api } from '@/vdb/graphql/api.js';
8
7
  import { Trans, useLingui } from '@lingui/react/macro';
@@ -100,22 +99,20 @@ function ProductListPage() {
100
99
  },
101
100
  ]}
102
101
  >
103
- <PageActionBarRight>
104
- <PermissionGuard requires={['UpdateCatalog']}>
105
- <Button variant="outline" onClick={handleRebuildSearchIndex}>
106
- <ListRestart />
107
- <Trans>Rebuild search index</Trans>
108
- </Button>
109
- </PermissionGuard>
110
- <PermissionGuard requires={['CreateProduct', 'CreateCatalog']}>
111
- <Button asChild>
112
- <Link to="./new">
113
- <PlusIcon className="mr-2 h-4 w-4" />
114
- <Trans>New Product</Trans>
115
- </Link>
116
- </Button>
117
- </PermissionGuard>
118
- </PageActionBarRight>
102
+ <ActionBarItem itemId="rebuild-index-button" requiresPermission={['UpdateCatalog']}>
103
+ <Button variant="outline" onClick={handleRebuildSearchIndex}>
104
+ <ListRestart />
105
+ <Trans>Rebuild search index</Trans>
106
+ </Button>
107
+ </ActionBarItem>
108
+ <ActionBarItem itemId="create-button" requiresPermission={['CreateProduct', 'CreateCatalog']}>
109
+ <Button asChild>
110
+ <Link to="./new">
111
+ <PlusIcon className="mr-2 h-4 w-4" />
112
+ <Trans>New Product</Trans>
113
+ </Link>
114
+ </Button>
115
+ </ActionBarItem>
119
116
  </ListPage>
120
117
  );
121
118
  }
@@ -4,7 +4,6 @@ import { AssignedFacetValues } from '@/vdb/components/shared/assigned-facet-valu
4
4
  import { EntityAssets } from '@/vdb/components/shared/entity-assets.js';
5
5
  import { ErrorPage } from '@/vdb/components/shared/error-page.js';
6
6
  import { FormFieldWrapper } from '@/vdb/components/shared/form-field-wrapper.js';
7
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
8
7
  import { TranslatableFormFieldWrapper } from '@/vdb/components/shared/translatable-form-field.js';
9
8
  import { Button } from '@/vdb/components/ui/button.js';
10
9
  import { FormControl, FormDescription, FormItem, FormMessage } from '@/vdb/components/ui/form.js';
@@ -12,11 +11,11 @@ import { Input } from '@/vdb/components/ui/input.js';
12
11
  import { Switch } from '@/vdb/components/ui/switch.js';
13
12
  import { NEW_ENTITY_PATH } from '@/vdb/constants.js';
14
13
  import {
14
+ ActionBarItem,
15
15
  CustomFieldsPageBlock,
16
16
  DetailFormGrid,
17
17
  Page,
18
18
  PageActionBar,
19
- PageActionBarRight,
20
19
  PageBlock,
21
20
  PageLayout,
22
21
  PageTitle,
@@ -102,16 +101,14 @@ function ProductDetailPage() {
102
101
  <Page pageId={pageId} form={form} submitHandler={submitHandler} entity={entity}>
103
102
  <PageTitle>{creatingNewEntity ? <Trans>New product</Trans> : (entity?.name ?? '')}</PageTitle>
104
103
  <PageActionBar>
105
- <PageActionBarRight>
106
- <PermissionGuard requires={['UpdateProduct', 'UpdateCatalog']}>
107
- <Button
108
- type="submit"
109
- disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
110
- >
111
- {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
112
- </Button>
113
- </PermissionGuard>
114
- </PageActionBarRight>
104
+ <ActionBarItem itemId="save-button" requiresPermission={['UpdateProduct', 'UpdateCatalog']}>
105
+ <Button
106
+ type="submit"
107
+ disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
108
+ >
109
+ {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
110
+ </Button>
111
+ </ActionBarItem>
115
112
  </PageActionBar>
116
113
  <PageLayout>
117
114
  <PageBlock column="side" blockId="enabled-toggle">
@@ -1,7 +1,6 @@
1
1
  import { SlugInput } from '@/vdb/components/data-input/index.js';
2
2
  import { ErrorPage } from '@/vdb/components/shared/error-page.js';
3
3
  import { FormFieldWrapper } from '@/vdb/components/shared/form-field-wrapper.js';
4
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
5
4
  import { TranslatableFormFieldWrapper } from '@/vdb/components/shared/translatable-form-field.js';
6
5
  import { Button } from '@/vdb/components/ui/button.js';
7
6
  import { Input } from '@/vdb/components/ui/input.js';
@@ -9,11 +8,11 @@ import { NEW_ENTITY_PATH } from '@/vdb/constants.js';
9
8
  import { extendDetailFormQuery } from '@/vdb/framework/document-extension/extend-detail-form-query.js';
10
9
  import { addCustomFields } from '@/vdb/framework/document-introspection/add-custom-fields.js';
11
10
  import {
11
+ ActionBarItem,
12
12
  CustomFieldsPageBlock,
13
13
  DetailFormGrid,
14
14
  Page,
15
15
  PageActionBar,
16
- PageActionBarRight,
17
16
  PageBlock,
18
17
  PageLayout,
19
18
  PageTitle,
@@ -129,16 +128,14 @@ function ProductOptionGroupDetailPage() {
129
128
  {creatingNewEntity ? <Trans>New product option group</Trans> : (entity?.name ?? '')}
130
129
  </PageTitle>
131
130
  <PageActionBar>
132
- <PageActionBarRight>
133
- <PermissionGuard requires={['UpdateProduct', 'UpdateCatalog']}>
134
- <Button
135
- type="submit"
136
- disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
137
- >
138
- {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
139
- </Button>
140
- </PermissionGuard>
141
- </PageActionBarRight>
131
+ <ActionBarItem itemId="save-button" requiresPermission={['UpdateProduct', 'UpdateCatalog']}>
132
+ <Button
133
+ type="submit"
134
+ disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
135
+ >
136
+ {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
137
+ </Button>
138
+ </ActionBarItem>
142
139
  </PageActionBar>
143
140
  <PageLayout>
144
141
  <PageBlock column="main" blockId="main-form">
@@ -1,7 +1,6 @@
1
1
  import { SlugInput } from '@/vdb/components/data-input/index.js';
2
2
  import { ErrorPage } from '@/vdb/components/shared/error-page.js';
3
3
  import { FormFieldWrapper } from '@/vdb/components/shared/form-field-wrapper.js';
4
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
5
4
  import { TranslatableFormFieldWrapper } from '@/vdb/components/shared/translatable-form-field.js';
6
5
  import { Button } from '@/vdb/components/ui/button.js';
7
6
  import { Input } from '@/vdb/components/ui/input.js';
@@ -9,11 +8,11 @@ import { NEW_ENTITY_PATH } from '@/vdb/constants.js';
9
8
  import { extendDetailFormQuery } from '@/vdb/framework/document-extension/extend-detail-form-query.js';
10
9
  import { addCustomFields } from '@/vdb/framework/document-introspection/add-custom-fields.js';
11
10
  import {
11
+ ActionBarItem,
12
12
  CustomFieldsPageBlock,
13
13
  DetailFormGrid,
14
14
  Page,
15
15
  PageActionBar,
16
- PageActionBarRight,
17
16
  PageBlock,
18
17
  PageLayout,
19
18
  PageTitle,
@@ -150,16 +149,14 @@ function ProductOptionDetailPage() {
150
149
  {creatingNewEntity ? <Trans>New product option</Trans> : ((entity as any)?.name ?? '')}
151
150
  </PageTitle>
152
151
  <PageActionBar>
153
- <PageActionBarRight>
154
- <PermissionGuard requires={['UpdateProduct', 'UpdateCatalog']}>
155
- <Button
156
- type="submit"
157
- disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
158
- >
159
- {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
160
- </Button>
161
- </PermissionGuard>
162
- </PageActionBarRight>
152
+ <ActionBarItem itemId="save-button" requiresPermission={['UpdateProduct', 'UpdateCatalog']}>
153
+ <Button
154
+ type="submit"
155
+ disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
156
+ >
157
+ {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
158
+ </Button>
159
+ </ActionBarItem>
163
160
  </PageActionBar>
164
161
  <PageLayout>
165
162
  <PageBlock column="side" blockId="option-group-info">
@@ -3,11 +3,11 @@ import { FormFieldWrapper } from '@/vdb/components/shared/form-field-wrapper.js'
3
3
  import { Button } from '@/vdb/components/ui/button.js';
4
4
  import { Input } from '@/vdb/components/ui/input.js';
5
5
  import {
6
+ ActionBarItem,
6
7
  CustomFieldsPageBlock,
7
8
  DetailFormGrid,
8
9
  Page,
9
10
  PageActionBar,
10
- PageActionBarRight,
11
11
  PageBlock,
12
12
  PageLayout,
13
13
  PageTitle,
@@ -74,14 +74,14 @@ function ProfilePage() {
74
74
  <Trans>Profile</Trans>
75
75
  </PageTitle>
76
76
  <PageActionBar>
77
- <PageActionBarRight>
77
+ <ActionBarItem itemId="save-button">
78
78
  <Button
79
79
  type="submit"
80
80
  disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
81
81
  >
82
82
  <Trans>Update</Trans>
83
83
  </Button>
84
- </PageActionBarRight>
84
+ </ActionBarItem>
85
85
  </PageActionBar>
86
86
  <PageLayout>
87
87
  <PageBlock column="main" blockId="main-form">
@@ -1,9 +1,8 @@
1
1
  import { BooleanDisplayBadge } from '@/vdb/components/data-display/boolean.js';
2
2
  import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
3
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
4
3
  import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
5
4
  import { Button } from '@/vdb/components/ui/button.js';
6
- import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
5
+ import { ActionBarItem } from '@/vdb/framework/layout-engine/page-layout.js';
7
6
  import { ListPage } from '@/vdb/framework/page/list-page.js';
8
7
  import { Trans } from '@lingui/react/macro';
9
8
  import { createFileRoute, Link } from '@tanstack/react-router';
@@ -79,16 +78,14 @@ function PromotionListPage() {
79
78
  },
80
79
  ]}
81
80
  >
82
- <PageActionBarRight>
83
- <PermissionGuard requires={['CreatePromotion']}>
84
- <Button asChild>
85
- <Link to="./new">
86
- <PlusIcon className="mr-2 h-4 w-4" />
87
- <Trans>New Promotion</Trans>
88
- </Link>
89
- </Button>
90
- </PermissionGuard>
91
- </PageActionBarRight>
81
+ <ActionBarItem itemId="create-button" requiresPermission={['CreatePromotion']}>
82
+ <Button asChild>
83
+ <Link to="./new">
84
+ <PlusIcon className="mr-2 h-4 w-4" />
85
+ <Trans>New Promotion</Trans>
86
+ </Link>
87
+ </Button>
88
+ </ActionBarItem>
92
89
  </ListPage>
93
90
  );
94
91
  }
@@ -3,18 +3,17 @@ import { NumberInput } from '@/vdb/components/data-input/number-input.js';
3
3
  import { RichTextInput } from '@/vdb/components/data-input/rich-text-input.js';
4
4
  import { ErrorPage } from '@/vdb/components/shared/error-page.js';
5
5
  import { FormFieldWrapper } from '@/vdb/components/shared/form-field-wrapper.js';
6
- import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
7
6
  import { TranslatableFormFieldWrapper } from '@/vdb/components/shared/translatable-form-field.js';
8
7
  import { Button } from '@/vdb/components/ui/button.js';
9
8
  import { Input } from '@/vdb/components/ui/input.js';
10
9
  import { Switch } from '@/vdb/components/ui/switch.js';
11
10
  import { NEW_ENTITY_PATH } from '@/vdb/constants.js';
12
11
  import {
12
+ ActionBarItem,
13
13
  CustomFieldsPageBlock,
14
14
  DetailFormGrid,
15
15
  Page,
16
16
  PageActionBar,
17
- PageActionBarRight,
18
17
  PageBlock,
19
18
  PageLayout,
20
19
  PageTitle,
@@ -127,16 +126,14 @@ function PromotionDetailPage() {
127
126
  <Page pageId={pageId} form={form} submitHandler={submitHandler} entity={entity}>
128
127
  <PageTitle>{creatingNewEntity ? <Trans>New promotion</Trans> : (entity?.name ?? '')}</PageTitle>
129
128
  <PageActionBar>
130
- <PageActionBarRight>
131
- <PermissionGuard requires={['UpdatePromotion']}>
132
- <Button
133
- type="submit"
134
- disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
135
- >
136
- {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
137
- </Button>
138
- </PermissionGuard>
139
- </PageActionBarRight>
129
+ <ActionBarItem itemId="save-button" requiresPermission={['UpdatePromotion']}>
130
+ <Button
131
+ type="submit"
132
+ disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
133
+ >
134
+ {creatingNewEntity ? <Trans>Create</Trans> : <Trans>Update</Trans>}
135
+ </Button>
136
+ </ActionBarItem>
140
137
  </PageActionBar>
141
138
  <PageLayout>
142
139
  <PageBlock column="side" blockId="enabled">