@vendure/dashboard 3.5.0-minor-202510031341 → 3.5.0-minor-202510161257
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/dist/plugin/dashboard.plugin.js +1 -1
- package/dist/plugin/default-page.html +1 -1
- package/dist/vite/utils/ast-utils.spec.js +3 -3
- package/dist/vite/utils/tsconfig-utils.js +2 -1
- package/dist/vite/vite-plugin-hmr.d.ts +8 -0
- package/dist/vite/vite-plugin-hmr.js +34 -0
- package/dist/vite/vite-plugin-theme.js +6 -6
- package/dist/vite/vite-plugin-transform-index.js +6 -1
- package/dist/vite/vite-plugin-vendure-dashboard.d.ts +31 -4
- package/dist/vite/vite-plugin-vendure-dashboard.js +89 -34
- package/package.json +18 -5
- package/src/app/app-providers.tsx +4 -1
- package/src/app/common/map-faceted-filter-fields.ts +21 -0
- package/src/app/main.tsx +3 -1
- package/src/app/routes/_authenticated/_administrators/administrators.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_administrators/administrators.tsx +13 -3
- package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +6 -13
- package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +1 -1
- package/src/app/routes/_authenticated/_assets/assets.tsx +17 -1
- package/src/app/routes/_authenticated/_collections/collections.graphql.ts +1 -0
- package/src/app/routes/_authenticated/_collections/collections.tsx +5 -0
- package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +0 -1
- package/src/app/routes/_authenticated/_customers/customers.tsx +9 -5
- package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +0 -6
- package/src/app/routes/_authenticated/_facets/components/facet-value-bulk-actions.tsx +16 -0
- package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +43 -12
- package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +14 -5
- package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +4 -8
- package/src/app/routes/_authenticated/_global-settings/utils/global-languages.ts +268 -0
- package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +117 -92
- package/src/app/routes/_authenticated/_orders/components/order-address.tsx +15 -15
- package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +5 -5
- package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +2 -1
- package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +26 -27
- package/src/app/routes/_authenticated/_orders/components/order-table.tsx +5 -3
- package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +6 -9
- package/src/app/routes/_authenticated/_orders/orders.graphql.ts +17 -1
- package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +48 -281
- package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +59 -40
- package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +73 -0
- package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +312 -0
- package/src/app/routes/_authenticated/_payment-methods/payment-methods.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +4 -0
- package/src/app/routes/_authenticated/_product-variants/components/add-currency-dropdown.tsx +49 -0
- package/src/app/routes/_authenticated/_product-variants/components/add-stock-location-dropdown.tsx +56 -0
- package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +12 -0
- package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +178 -50
- package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +0 -6
- package/src/app/routes/_authenticated/_products/components/product-variants-table.tsx +0 -11
- package/src/app/routes/_authenticated/_products/products.tsx +6 -2
- package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +4 -8
- package/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx +0 -10
- package/src/app/routes/_authenticated/_promotions/promotions.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_promotions/promotions.tsx +12 -0
- package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +3 -10
- package/src/app/routes/_authenticated/_sellers/sellers.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +4 -0
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +4 -10
- package/src/app/routes/_authenticated/_stock-locations/stock-locations.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_tax-categories/tax-categories.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +9 -0
- package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +1 -0
- package/src/app/routes/_authenticated/_zones/zones.graphql.ts +2 -2
- package/src/app/routes/login.tsx +2 -2
- package/src/i18n/locales/ar.po +420 -289
- package/src/i18n/locales/cs.po +420 -289
- package/src/i18n/locales/de.po +420 -289
- package/src/i18n/locales/en.po +420 -289
- package/src/i18n/locales/es.po +420 -289
- package/src/i18n/locales/fa.po +420 -289
- package/src/i18n/locales/fr.po +468 -337
- package/src/i18n/locales/he.po +420 -289
- package/src/i18n/locales/hr.po +420 -289
- package/src/i18n/locales/it.po +420 -289
- package/src/i18n/locales/ja.po +420 -289
- package/src/i18n/locales/nb.po +420 -289
- package/src/i18n/locales/ne.po +420 -289
- package/src/i18n/locales/pl.po +420 -289
- package/src/i18n/locales/pt_BR.po +420 -289
- package/src/i18n/locales/pt_PT.po +420 -289
- package/src/i18n/locales/ru.po +420 -289
- package/src/i18n/locales/sv.po +420 -289
- package/src/i18n/locales/tr.po +420 -289
- package/src/i18n/locales/uk.po +420 -289
- package/src/i18n/locales/zh_Hans.po +420 -289
- package/src/i18n/locales/zh_Hant.po +420 -289
- package/src/lib/components/data-input/affixed-input.stories.tsx +93 -0
- package/src/lib/components/data-input/affixed-input.tsx +5 -2
- package/src/lib/components/data-input/boolean-input.stories.tsx +102 -0
- package/src/lib/components/data-input/checkbox-input.stories.tsx +61 -0
- package/src/lib/components/data-input/customer-group-input.tsx +0 -1
- package/src/lib/components/data-input/datetime-input.stories.tsx +62 -0
- package/src/lib/components/data-input/datetime-input.tsx +27 -13
- package/src/lib/components/data-input/default-relation-input.tsx +18 -12
- package/src/lib/components/data-input/money-input.stories.tsx +88 -0
- package/src/lib/components/data-input/money-input.tsx +7 -11
- package/src/lib/components/data-input/number-input.stories.tsx +103 -0
- package/src/lib/components/data-input/number-input.tsx +16 -5
- package/src/lib/components/data-input/password-input.stories.tsx +65 -0
- package/src/lib/components/data-input/rich-text-input.stories.tsx +92 -0
- package/src/lib/components/data-input/slug-input.stories.tsx +232 -0
- package/src/lib/components/data-input/slug-input.tsx +9 -10
- package/src/lib/components/data-input/text-input.stories.tsx +52 -0
- package/src/lib/components/data-input/textarea-input.stories.tsx +55 -0
- package/src/lib/components/data-table/add-filter-menu.tsx +6 -1
- package/src/lib/components/data-table/column-header-wrapper.tsx +106 -0
- package/src/lib/components/data-table/data-table-bulk-action-item.tsx +11 -9
- package/src/lib/components/data-table/data-table-bulk-actions.tsx +4 -4
- package/src/lib/components/data-table/data-table-column-header.tsx +17 -14
- package/src/lib/components/data-table/data-table-faceted-filter.tsx +33 -11
- package/src/lib/components/data-table/data-table-filter-badge-editable.tsx +35 -0
- package/src/lib/components/data-table/data-table-filter-badge.tsx +28 -14
- package/src/lib/components/data-table/data-table-filter-dialog.tsx +28 -8
- package/src/lib/components/data-table/data-table-pagination.tsx +23 -7
- package/src/lib/components/data-table/data-table.stories.tsx +249 -0
- package/src/lib/components/data-table/data-table.tsx +39 -11
- package/src/lib/components/data-table/filters/data-table-datetime-filter.tsx +79 -34
- package/src/lib/components/data-table/use-generated-columns.tsx +55 -27
- package/src/lib/components/layout/generated-breadcrumbs.tsx +4 -12
- package/src/lib/components/layout/nav-user.tsx +19 -13
- package/src/lib/components/login/login-form.tsx +39 -123
- package/src/lib/components/shared/alerts.tsx +29 -17
- package/src/lib/components/shared/asset/asset-bulk-actions.tsx +3 -3
- package/src/lib/components/shared/asset/asset-gallery.stories.tsx +76 -0
- package/src/lib/components/shared/asset/asset-gallery.tsx +147 -113
- package/src/lib/components/shared/asset/asset-picker-dialog.stories.tsx +58 -0
- package/src/lib/components/shared/configurable-operation-input.tsx +1 -1
- package/src/lib/components/shared/customer-group-selector.tsx +5 -2
- package/src/lib/components/shared/detail-page-button.stories.tsx +52 -0
- package/src/lib/components/shared/facet-value-selector.stories.tsx +48 -0
- package/src/lib/components/shared/facet-value-selector.tsx +130 -34
- package/src/lib/components/shared/paginated-list-data-table.stories.tsx +212 -0
- package/src/lib/components/shared/paginated-list-data-table.tsx +12 -12
- package/src/lib/components/shared/permission-guard.stories.tsx +46 -0
- package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +2 -0
- package/src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx +8 -4
- package/src/lib/components/shared/rich-text-editor/rich-text-editor.tsx +1 -0
- package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +40 -0
- package/src/lib/components/shared/vendure-image.stories.tsx +167 -0
- package/src/lib/components/shared/vendure-image.tsx +6 -7
- package/src/lib/components/ui/accordion.stories.tsx +33 -0
- package/src/lib/components/ui/alert-dialog.stories.tsx +48 -0
- package/src/lib/components/ui/alert.stories.tsx +35 -0
- package/src/lib/components/ui/aspect-ratio.stories.tsx +28 -0
- package/src/lib/components/ui/badge.stories.tsx +28 -0
- package/src/lib/components/ui/breadcrumb.stories.tsx +41 -0
- package/src/lib/components/ui/button.stories.tsx +38 -0
- package/src/lib/components/ui/calendar.stories.tsx +22 -0
- package/src/lib/components/ui/card.stories.tsx +28 -0
- package/src/lib/components/ui/carousel.stories.tsx +34 -0
- package/src/lib/components/ui/checkbox.stories.tsx +31 -0
- package/src/lib/components/ui/collapsible.stories.tsx +39 -0
- package/src/lib/components/ui/command.stories.tsx +44 -0
- package/src/lib/components/ui/context-menu.stories.tsx +38 -0
- package/src/lib/components/ui/dialog.stories.tsx +52 -0
- package/src/lib/components/ui/drawer.stories.tsx +50 -0
- package/src/lib/components/ui/dropdown-menu.stories.tsx +41 -0
- package/src/lib/components/ui/hover-card.stories.tsx +38 -0
- package/src/lib/components/ui/input-group.tsx +148 -0
- package/src/lib/components/ui/input-otp.stories.tsx +30 -0
- package/src/lib/components/ui/input.stories.tsx +38 -0
- package/src/lib/components/ui/label.stories.tsx +24 -0
- package/src/lib/components/ui/menubar.stories.tsx +53 -0
- package/src/lib/components/ui/navigation-menu.stories.tsx +54 -0
- package/src/lib/components/ui/pagination.stories.tsx +51 -0
- package/src/lib/components/ui/password-input.stories.tsx +32 -0
- package/src/lib/components/ui/password-input.tsx +33 -0
- package/src/lib/components/ui/popover.stories.tsx +33 -0
- package/src/lib/components/ui/progress.stories.tsx +27 -0
- package/src/lib/components/ui/radio-group.stories.tsx +34 -0
- package/src/lib/components/ui/resizable.stories.tsx +32 -0
- package/src/lib/components/ui/scroll-area.stories.tsx +31 -0
- package/src/lib/components/ui/select.stories.tsx +36 -0
- package/src/lib/components/ui/separator.stories.tsx +35 -0
- package/src/lib/components/ui/sheet.stories.tsx +50 -0
- package/src/lib/components/ui/sidebar-context.ts +16 -0
- package/src/lib/components/ui/sidebar.tsx +2 -13
- package/src/lib/components/ui/skeleton.stories.tsx +26 -0
- package/src/lib/components/ui/slider.stories.tsx +37 -0
- package/src/lib/components/ui/switch.stories.tsx +31 -0
- package/src/lib/components/ui/table.stories.tsx +52 -0
- package/src/lib/components/ui/tabs.stories.tsx +29 -0
- package/src/lib/components/ui/textarea.stories.tsx +32 -0
- package/src/lib/components/ui/toggle-group.stories.tsx +31 -0
- package/src/lib/components/ui/toggle.stories.tsx +39 -0
- package/src/lib/components/ui/tooltip.stories.tsx +30 -0
- package/src/lib/components/ui/tooltip.tsx +2 -2
- package/src/lib/framework/alert/alert-extensions.tsx +0 -11
- package/src/lib/framework/alert/alert-item.tsx +14 -19
- package/src/lib/framework/alert/alerts-indicator.tsx +14 -15
- package/src/lib/framework/alert/search-index-buffer-alert/search-index-buffer-alert.ts +41 -0
- package/src/lib/framework/component-registry/component-registry.tsx +3 -14
- package/src/lib/framework/dashboard-widget/base-widget.tsx +18 -9
- package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +0 -2
- package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +12 -11
- package/src/lib/framework/defaults.ts +9 -13
- package/src/lib/framework/extension-api/input-component-extensions.tsx +6 -1
- package/src/lib/framework/extension-api/logic/alerts.ts +3 -2
- package/src/lib/framework/extension-api/types/alerts.ts +12 -6
- package/src/lib/framework/extension-api/types/data-table.ts +5 -2
- package/src/lib/framework/extension-api/types/layout.ts +41 -1
- package/src/lib/framework/extension-api/types/login.ts +0 -21
- package/src/lib/framework/form-engine/value-transformers.ts +8 -1
- package/src/lib/framework/layout-engine/custom-form-page.stories.tsx +344 -0
- package/src/lib/framework/layout-engine/page-layout.tsx +69 -57
- package/src/lib/framework/layout-engine/page.stories.tsx +275 -0
- package/src/lib/framework/nav-menu/nav-menu-extensions.ts +32 -19
- package/src/lib/framework/page/detail-page.stories.tsx +151 -0
- package/src/lib/framework/page/detail-page.tsx +12 -15
- package/src/lib/framework/page/list-page.stories.tsx +217 -0
- package/src/lib/framework/page/list-page.tsx +8 -1
- package/src/lib/graphql/api.ts +18 -1
- package/src/lib/graphql/graphql-env.d.ts +1 -1
- package/src/lib/hooks/use-alerts.ts +84 -0
- package/src/lib/hooks/use-floating-bulk-actions.ts +2 -3
- package/src/lib/index.ts +12 -5
- package/src/lib/providers/alerts-provider.tsx +60 -0
- package/src/lib/providers/channel-provider.tsx +1 -0
- package/src/lib/providers/theme-provider.tsx +6 -3
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { Button } from '@/vdb/components/ui/button.js';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
+
import { RouterContextProvider } from '@tanstack/react-router';
|
|
4
|
+
import { createDemoRoute } from '../../../../.storybook/providers.js';
|
|
5
|
+
import {
|
|
6
|
+
FullWidthPageBlock,
|
|
7
|
+
Page,
|
|
8
|
+
PageActionBar,
|
|
9
|
+
PageActionBarLeft,
|
|
10
|
+
PageActionBarRight,
|
|
11
|
+
PageBlock,
|
|
12
|
+
PageLayout,
|
|
13
|
+
PageTitle,
|
|
14
|
+
} from './page-layout.js';
|
|
15
|
+
|
|
16
|
+
const meta = {
|
|
17
|
+
title: 'Layout/Page Layout',
|
|
18
|
+
component: Page,
|
|
19
|
+
parameters: {
|
|
20
|
+
layout: 'fullscreen',
|
|
21
|
+
},
|
|
22
|
+
tags: ['autodocs'],
|
|
23
|
+
} satisfies Meta<typeof Page>;
|
|
24
|
+
|
|
25
|
+
export default meta;
|
|
26
|
+
type Story = StoryObj<typeof meta>;
|
|
27
|
+
|
|
28
|
+
export const Playground: Story = {
|
|
29
|
+
render: () => {
|
|
30
|
+
const { route, router } = createDemoRoute();
|
|
31
|
+
return (
|
|
32
|
+
<RouterContextProvider router={router}>
|
|
33
|
+
<Page pageId="test-page">
|
|
34
|
+
<PageTitle>Test Page</PageTitle>
|
|
35
|
+
<PageLayout>
|
|
36
|
+
<PageBlock column="main" blockId="main-stuff">
|
|
37
|
+
This will display in the main area
|
|
38
|
+
</PageBlock>
|
|
39
|
+
<PageBlock column="side" blockId="side-stuff">
|
|
40
|
+
This will display in the side area
|
|
41
|
+
</PageBlock>
|
|
42
|
+
</PageLayout>
|
|
43
|
+
</Page>
|
|
44
|
+
</RouterContextProvider>
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const WithActionBar: Story = {
|
|
50
|
+
render: () => {
|
|
51
|
+
const { route, router } = createDemoRoute();
|
|
52
|
+
return (
|
|
53
|
+
<RouterContextProvider router={router}>
|
|
54
|
+
<Page pageId="product-detail">
|
|
55
|
+
<PageTitle>Product Details</PageTitle>
|
|
56
|
+
<PageActionBar>
|
|
57
|
+
<PageActionBarLeft>
|
|
58
|
+
<Button variant="outline">Cancel</Button>
|
|
59
|
+
</PageActionBarLeft>
|
|
60
|
+
<PageActionBarRight>
|
|
61
|
+
<Button>Save</Button>
|
|
62
|
+
</PageActionBarRight>
|
|
63
|
+
</PageActionBar>
|
|
64
|
+
<PageLayout>
|
|
65
|
+
<PageBlock column="main" blockId="product-info" title="Product Information">
|
|
66
|
+
<div className="space-y-4">
|
|
67
|
+
<div>
|
|
68
|
+
<label className="text-sm font-medium">Name</label>
|
|
69
|
+
<input
|
|
70
|
+
type="text"
|
|
71
|
+
className="w-full border rounded px-3 py-2 mt-1"
|
|
72
|
+
defaultValue="Wireless Headphones"
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
<div>
|
|
76
|
+
<label className="text-sm font-medium">Description</label>
|
|
77
|
+
<textarea
|
|
78
|
+
className="w-full border rounded px-3 py-2 mt-1"
|
|
79
|
+
rows={4}
|
|
80
|
+
defaultValue="High-quality wireless headphones with active noise cancellation."
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</PageBlock>
|
|
85
|
+
<PageBlock column="side" blockId="product-meta" title="Metadata">
|
|
86
|
+
<div className="space-y-3">
|
|
87
|
+
<div>
|
|
88
|
+
<div className="text-sm font-medium">Status</div>
|
|
89
|
+
<div className="text-sm text-muted-foreground">Active</div>
|
|
90
|
+
</div>
|
|
91
|
+
<div>
|
|
92
|
+
<div className="text-sm font-medium">SKU</div>
|
|
93
|
+
<div className="text-sm text-muted-foreground">WH-001</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div>
|
|
96
|
+
<div className="text-sm font-medium">Price</div>
|
|
97
|
+
<div className="text-sm text-muted-foreground">$299.00</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</PageBlock>
|
|
101
|
+
</PageLayout>
|
|
102
|
+
</Page>
|
|
103
|
+
</RouterContextProvider>
|
|
104
|
+
);
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const MultipleBlocks: Story = {
|
|
109
|
+
render: () => {
|
|
110
|
+
const { route, router } = createDemoRoute();
|
|
111
|
+
return (
|
|
112
|
+
<RouterContextProvider router={router}>
|
|
113
|
+
<Page pageId="complex-page">
|
|
114
|
+
<PageTitle>Complex Page Layout</PageTitle>
|
|
115
|
+
<PageLayout>
|
|
116
|
+
<PageBlock
|
|
117
|
+
column="main"
|
|
118
|
+
blockId="block-1"
|
|
119
|
+
title="Main Block 1"
|
|
120
|
+
description="This is the first main block"
|
|
121
|
+
>
|
|
122
|
+
<p>Content for the first main block goes here.</p>
|
|
123
|
+
</PageBlock>
|
|
124
|
+
<PageBlock
|
|
125
|
+
column="main"
|
|
126
|
+
blockId="block-2"
|
|
127
|
+
title="Main Block 2"
|
|
128
|
+
description="This is the second main block"
|
|
129
|
+
>
|
|
130
|
+
<p>Content for the second main block goes here.</p>
|
|
131
|
+
</PageBlock>
|
|
132
|
+
<PageBlock column="side" blockId="side-1" title="Sidebar Block 1">
|
|
133
|
+
<p>First sidebar block content.</p>
|
|
134
|
+
</PageBlock>
|
|
135
|
+
<PageBlock column="side" blockId="side-2" title="Sidebar Block 2">
|
|
136
|
+
<p>Second sidebar block content.</p>
|
|
137
|
+
</PageBlock>
|
|
138
|
+
<PageBlock column="side" blockId="side-3" title="Sidebar Block 3">
|
|
139
|
+
<p>Third sidebar block content.</p>
|
|
140
|
+
</PageBlock>
|
|
141
|
+
</PageLayout>
|
|
142
|
+
</Page>
|
|
143
|
+
</RouterContextProvider>
|
|
144
|
+
);
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const WithFullWidthBlock: Story = {
|
|
149
|
+
render: () => {
|
|
150
|
+
const { route, router } = createDemoRoute();
|
|
151
|
+
return (
|
|
152
|
+
<RouterContextProvider router={router}>
|
|
153
|
+
<Page pageId="dashboard-overview">
|
|
154
|
+
<PageTitle>Dashboard Overview</PageTitle>
|
|
155
|
+
<PageLayout>
|
|
156
|
+
<FullWidthPageBlock blockId="stats">
|
|
157
|
+
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 p-6 bg-muted/50 rounded-lg">
|
|
158
|
+
<div className="text-center">
|
|
159
|
+
<div className="text-3xl font-bold">1,234</div>
|
|
160
|
+
<div className="text-sm text-muted-foreground">Total Orders</div>
|
|
161
|
+
</div>
|
|
162
|
+
<div className="text-center">
|
|
163
|
+
<div className="text-3xl font-bold">$45,678</div>
|
|
164
|
+
<div className="text-sm text-muted-foreground">Revenue</div>
|
|
165
|
+
</div>
|
|
166
|
+
<div className="text-center">
|
|
167
|
+
<div className="text-3xl font-bold">567</div>
|
|
168
|
+
<div className="text-sm text-muted-foreground">Products</div>
|
|
169
|
+
</div>
|
|
170
|
+
<div className="text-center">
|
|
171
|
+
<div className="text-3xl font-bold">890</div>
|
|
172
|
+
<div className="text-sm text-muted-foreground">Customers</div>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</FullWidthPageBlock>
|
|
176
|
+
<PageBlock column="main" blockId="recent-orders" title="Recent Orders">
|
|
177
|
+
<div className="space-y-2">
|
|
178
|
+
{[1, 2, 3].map(i => (
|
|
179
|
+
<div key={i} className="flex justify-between py-2 border-b">
|
|
180
|
+
<span>Order #{1000 + i}</span>
|
|
181
|
+
<span className="text-muted-foreground">$99.00</span>
|
|
182
|
+
</div>
|
|
183
|
+
))}
|
|
184
|
+
</div>
|
|
185
|
+
</PageBlock>
|
|
186
|
+
<PageBlock column="side" blockId="quick-stats" title="Quick Stats">
|
|
187
|
+
<div className="space-y-3">
|
|
188
|
+
<div>
|
|
189
|
+
<div className="text-sm font-medium">Pending Orders</div>
|
|
190
|
+
<div className="text-2xl font-bold">12</div>
|
|
191
|
+
</div>
|
|
192
|
+
<div>
|
|
193
|
+
<div className="text-sm font-medium">Low Stock Items</div>
|
|
194
|
+
<div className="text-2xl font-bold">5</div>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
</PageBlock>
|
|
198
|
+
</PageLayout>
|
|
199
|
+
</Page>
|
|
200
|
+
</RouterContextProvider>
|
|
201
|
+
);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export const MinimalPage: Story = {
|
|
206
|
+
render: () => {
|
|
207
|
+
const { route, router } = createDemoRoute();
|
|
208
|
+
return (
|
|
209
|
+
<RouterContextProvider router={router}>
|
|
210
|
+
<Page pageId="simple-page">
|
|
211
|
+
<PageTitle>Simple Page</PageTitle>
|
|
212
|
+
<PageLayout>
|
|
213
|
+
<PageBlock column="main" blockId="content">
|
|
214
|
+
<p>This is a minimal page with just a title and one content block.</p>
|
|
215
|
+
</PageBlock>
|
|
216
|
+
</PageLayout>
|
|
217
|
+
</Page>
|
|
218
|
+
</RouterContextProvider>
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export const WithBlockDescriptions: Story = {
|
|
224
|
+
render: () => {
|
|
225
|
+
const { route, router } = createDemoRoute();
|
|
226
|
+
return (
|
|
227
|
+
<RouterContextProvider router={router}>
|
|
228
|
+
<Page pageId="settings-page">
|
|
229
|
+
<PageTitle>Settings</PageTitle>
|
|
230
|
+
<PageLayout>
|
|
231
|
+
<PageBlock
|
|
232
|
+
column="main"
|
|
233
|
+
blockId="general"
|
|
234
|
+
title="General Settings"
|
|
235
|
+
description="Configure general application settings and preferences"
|
|
236
|
+
>
|
|
237
|
+
<div className="space-y-4">
|
|
238
|
+
<div className="flex items-center justify-between">
|
|
239
|
+
<label className="text-sm font-medium">Enable notifications</label>
|
|
240
|
+
<input type="checkbox" defaultChecked />
|
|
241
|
+
</div>
|
|
242
|
+
<div className="flex items-center justify-between">
|
|
243
|
+
<label className="text-sm font-medium">Dark mode</label>
|
|
244
|
+
<input type="checkbox" />
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
</PageBlock>
|
|
248
|
+
<PageBlock
|
|
249
|
+
column="main"
|
|
250
|
+
blockId="advanced"
|
|
251
|
+
title="Advanced Settings"
|
|
252
|
+
description="Advanced configuration options for power users"
|
|
253
|
+
>
|
|
254
|
+
<div className="space-y-4">
|
|
255
|
+
<div>
|
|
256
|
+
<label className="text-sm font-medium">API Key</label>
|
|
257
|
+
<input
|
|
258
|
+
type="text"
|
|
259
|
+
className="w-full border rounded px-3 py-2 mt-1"
|
|
260
|
+
defaultValue="sk_test_..."
|
|
261
|
+
/>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</PageBlock>
|
|
265
|
+
<PageBlock column="side" blockId="help" title="Help" description="Need assistance?">
|
|
266
|
+
<Button variant="outline" className="w-full">
|
|
267
|
+
View Documentation
|
|
268
|
+
</Button>
|
|
269
|
+
</PageBlock>
|
|
270
|
+
</PageLayout>
|
|
271
|
+
</Page>
|
|
272
|
+
</RouterContextProvider>
|
|
273
|
+
);
|
|
274
|
+
},
|
|
275
|
+
};
|
|
@@ -7,17 +7,46 @@ export type NavMenuSectionPlacement = 'top' | 'bottom';
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @description
|
|
10
|
-
*
|
|
10
|
+
* Defines an items in the navigation menu.
|
|
11
11
|
*
|
|
12
12
|
* @docsCategory extensions-api
|
|
13
13
|
* @docsPage Navigation
|
|
14
14
|
* @since 3.4.0
|
|
15
15
|
*/
|
|
16
|
-
interface
|
|
16
|
+
interface NavMenuItem {
|
|
17
|
+
/**
|
|
18
|
+
* @description
|
|
19
|
+
* A unique ID for this nav menu item
|
|
20
|
+
*/
|
|
17
21
|
id: string;
|
|
22
|
+
/**
|
|
23
|
+
* @description
|
|
24
|
+
* The title that will appear in the nav menu
|
|
25
|
+
*/
|
|
18
26
|
title: string;
|
|
27
|
+
/**
|
|
28
|
+
* @description
|
|
29
|
+
* The url of the route which this nav item links to.
|
|
30
|
+
*/
|
|
31
|
+
url: string;
|
|
32
|
+
/**
|
|
33
|
+
* @description
|
|
34
|
+
* An optional icon component to represent the item,
|
|
35
|
+
* which should be imported from `lucide-react`.
|
|
36
|
+
*/
|
|
19
37
|
icon?: LucideIcon;
|
|
38
|
+
/**
|
|
39
|
+
* @description
|
|
40
|
+
* The order is an number which allows you to control
|
|
41
|
+
* the relative position in relation to other items in the
|
|
42
|
+
* menu.
|
|
43
|
+
* A higher number appears further down the list.
|
|
44
|
+
*/
|
|
20
45
|
order?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Whether this item should appear in the top of bottom section
|
|
48
|
+
* of the nav menu.
|
|
49
|
+
*/
|
|
21
50
|
placement?: NavMenuSectionPlacement;
|
|
22
51
|
/**
|
|
23
52
|
* @description
|
|
@@ -27,23 +56,7 @@ interface NavMenuBaseItem {
|
|
|
27
56
|
requiresPermission?: string | string[];
|
|
28
57
|
}
|
|
29
58
|
|
|
30
|
-
|
|
31
|
-
* @description
|
|
32
|
-
* Defines an items in the navigation menu.
|
|
33
|
-
*
|
|
34
|
-
* @docsCategory extensions-api
|
|
35
|
-
* @docsPage Navigation
|
|
36
|
-
* @since 3.4.0
|
|
37
|
-
*/
|
|
38
|
-
export interface NavMenuItem extends NavMenuBaseItem {
|
|
39
|
-
/**
|
|
40
|
-
* @description
|
|
41
|
-
* The url of the route which this nav item links to.
|
|
42
|
-
*/
|
|
43
|
-
url: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface NavMenuSection extends NavMenuBaseItem {
|
|
59
|
+
export interface NavMenuSection extends Omit<NavMenuItem, 'url'> {
|
|
47
60
|
defaultOpen?: boolean;
|
|
48
61
|
items?: NavMenuItem[];
|
|
49
62
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { graphql } from '@/vdb/graphql/graphql.js';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { DemoRouterProvider } from '../../../../.storybook/providers.js';
|
|
4
|
+
import { DetailPage, DetailPageProps } from './detail-page.js';
|
|
5
|
+
|
|
6
|
+
// Sample GraphQL query for a product detail
|
|
7
|
+
const productFragment = graphql(`
|
|
8
|
+
fragment ProductDetail on Product {
|
|
9
|
+
id
|
|
10
|
+
createdAt
|
|
11
|
+
updatedAt
|
|
12
|
+
name
|
|
13
|
+
slug
|
|
14
|
+
description
|
|
15
|
+
enabled
|
|
16
|
+
featuredAsset {
|
|
17
|
+
id
|
|
18
|
+
}
|
|
19
|
+
assets {
|
|
20
|
+
id
|
|
21
|
+
}
|
|
22
|
+
facetValues {
|
|
23
|
+
id
|
|
24
|
+
}
|
|
25
|
+
translations {
|
|
26
|
+
id
|
|
27
|
+
languageCode
|
|
28
|
+
name
|
|
29
|
+
slug
|
|
30
|
+
description
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
`);
|
|
34
|
+
|
|
35
|
+
const productQuery = graphql(
|
|
36
|
+
`
|
|
37
|
+
query Product($id: ID!) {
|
|
38
|
+
product(id: $id) {
|
|
39
|
+
...ProductDetail
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
`,
|
|
43
|
+
[productFragment],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const createProductDocument = graphql(`
|
|
47
|
+
mutation CreateProduct($input: CreateProductInput!) {
|
|
48
|
+
createProduct(input: $input) {
|
|
49
|
+
id
|
|
50
|
+
name
|
|
51
|
+
slug
|
|
52
|
+
description
|
|
53
|
+
enabled
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
`);
|
|
57
|
+
|
|
58
|
+
const updateProductDocument = graphql(`
|
|
59
|
+
mutation UpdateProduct($input: UpdateProductInput!) {
|
|
60
|
+
updateProduct(input: $input) {
|
|
61
|
+
id
|
|
62
|
+
name
|
|
63
|
+
slug
|
|
64
|
+
description
|
|
65
|
+
enabled
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
`);
|
|
69
|
+
|
|
70
|
+
function DetailPageStoryWrapper(props: Omit<DetailPageProps<any, any, any>, 'route'>) {
|
|
71
|
+
return (
|
|
72
|
+
<DemoRouterProvider
|
|
73
|
+
component={route => <DetailPage {...props} route={route} />}
|
|
74
|
+
path={'/products/$id'}
|
|
75
|
+
initialPath={'/products/1'}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const meta = {
|
|
81
|
+
title: 'Layout/DetailPage',
|
|
82
|
+
component: DetailPageStoryWrapper,
|
|
83
|
+
parameters: {
|
|
84
|
+
layout: 'fullscreen',
|
|
85
|
+
},
|
|
86
|
+
tags: ['autodocs'],
|
|
87
|
+
argTypes: {
|
|
88
|
+
pageId: {
|
|
89
|
+
control: 'text',
|
|
90
|
+
description: 'Unique identifier for the detail page',
|
|
91
|
+
},
|
|
92
|
+
entityName: {
|
|
93
|
+
control: 'text',
|
|
94
|
+
description: 'Name of the entity (inferred from query if not provided)',
|
|
95
|
+
},
|
|
96
|
+
title: {
|
|
97
|
+
control: false,
|
|
98
|
+
description: 'Function that returns the page title based on the entity',
|
|
99
|
+
},
|
|
100
|
+
queryDocument: {
|
|
101
|
+
control: false,
|
|
102
|
+
description: 'GraphQL query document for fetching entity data',
|
|
103
|
+
},
|
|
104
|
+
createDocument: {
|
|
105
|
+
control: false,
|
|
106
|
+
description: 'GraphQL mutation document for creating the entity',
|
|
107
|
+
},
|
|
108
|
+
updateDocument: {
|
|
109
|
+
control: false,
|
|
110
|
+
description: 'GraphQL mutation document for updating the entity',
|
|
111
|
+
},
|
|
112
|
+
setValuesForUpdate: {
|
|
113
|
+
control: false,
|
|
114
|
+
description: 'Function to map entity data to update input',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
} satisfies Meta<typeof DetailPageStoryWrapper>;
|
|
118
|
+
|
|
119
|
+
export default meta;
|
|
120
|
+
type Story = StoryObj<typeof meta>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Basic example of a DetailPage showing a product entity.
|
|
124
|
+
* This demonstrates the minimal configuration needed to render a detail page.
|
|
125
|
+
*/
|
|
126
|
+
export const BasicDetail: Story = {
|
|
127
|
+
args: {
|
|
128
|
+
pageId: 'product-detail',
|
|
129
|
+
queryDocument: productQuery,
|
|
130
|
+
updateDocument: updateProductDocument,
|
|
131
|
+
title: entity => entity?.name || 'Product',
|
|
132
|
+
setValuesForUpdate: entity => ({
|
|
133
|
+
id: entity.id,
|
|
134
|
+
name: entity.name,
|
|
135
|
+
slug: entity.slug,
|
|
136
|
+
description: entity.description,
|
|
137
|
+
enabled: entity.enabled,
|
|
138
|
+
featuredAssetId: entity.featuredAsset?.id,
|
|
139
|
+
assetIds: entity.assets.map(asset => asset.id),
|
|
140
|
+
facetValueIds: entity.facetValues.map(facetValue => facetValue.id),
|
|
141
|
+
translations: entity.translations.map(translation => ({
|
|
142
|
+
id: translation.id,
|
|
143
|
+
languageCode: translation.languageCode,
|
|
144
|
+
name: translation.name,
|
|
145
|
+
slug: translation.slug,
|
|
146
|
+
description: translation.description,
|
|
147
|
+
customFields: (translation as any).customFields,
|
|
148
|
+
})),
|
|
149
|
+
}),
|
|
150
|
+
},
|
|
151
|
+
};
|
|
@@ -5,8 +5,8 @@ import { Checkbox } from '@/vdb/components/ui/checkbox.js';
|
|
|
5
5
|
import { Input } from '@/vdb/components/ui/input.js';
|
|
6
6
|
import { NEW_ENTITY_PATH } from '@/vdb/constants.js';
|
|
7
7
|
import { useDetailPage } from '@/vdb/framework/page/use-detail-page.js';
|
|
8
|
-
import { Trans } from '@lingui/react/macro';
|
|
9
8
|
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
9
|
+
import { Trans } from '@lingui/react/macro';
|
|
10
10
|
import { AnyRoute, useNavigate } from '@tanstack/react-router';
|
|
11
11
|
import { ResultOf, VariablesOf } from 'gql.tada';
|
|
12
12
|
import { toast } from 'sonner';
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
getOperationVariablesFields,
|
|
17
17
|
} from '../document-introspection/get-document-structure.js';
|
|
18
18
|
|
|
19
|
+
import { NumberInput } from '@/vdb/components/data-input/number-input.js';
|
|
19
20
|
import { TranslatableFormFieldWrapper } from '@/vdb/components/shared/translatable-form-field.js';
|
|
20
21
|
import { FormControl } from '@/vdb/components/ui/form.js';
|
|
21
22
|
import { ControllerRenderProps, FieldPath, FieldValues } from 'react-hook-form';
|
|
@@ -108,11 +109,7 @@ function FieldInputRenderer<
|
|
|
108
109
|
case 'Float':
|
|
109
110
|
return (
|
|
110
111
|
<FormControl>
|
|
111
|
-
<
|
|
112
|
-
type="number"
|
|
113
|
-
value={field.value}
|
|
114
|
-
onChange={e => field.onChange(e.target.valueAsNumber)}
|
|
115
|
-
/>
|
|
112
|
+
<NumberInput {...field} />
|
|
116
113
|
</FormControl>
|
|
117
114
|
);
|
|
118
115
|
case 'DateTime':
|
|
@@ -152,15 +149,15 @@ export function DetailPage<
|
|
|
152
149
|
C extends TypedDocumentNode<any, any>,
|
|
153
150
|
U extends TypedDocumentNode<any, any>,
|
|
154
151
|
>({
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
152
|
+
pageId,
|
|
153
|
+
route,
|
|
154
|
+
entityName: passedEntityName,
|
|
155
|
+
queryDocument,
|
|
156
|
+
createDocument,
|
|
157
|
+
updateDocument,
|
|
158
|
+
setValuesForUpdate,
|
|
159
|
+
title,
|
|
160
|
+
}: DetailPageProps<T, C, U>) {
|
|
164
161
|
const params = route.useParams();
|
|
165
162
|
const creatingNewEntity = params.id === NEW_ENTITY_PATH;
|
|
166
163
|
const navigate = useNavigate();
|