@vendure/dashboard 3.5.0-minor-202510012036 → 3.5.0-minor-202510071456

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 (38) hide show
  1. package/dist/plugin/dashboard.plugin.d.ts +25 -6
  2. package/dist/plugin/dashboard.plugin.js +184 -27
  3. package/dist/plugin/default-page.html +188 -0
  4. package/dist/vite/utils/tsconfig-utils.js +2 -1
  5. package/package.json +10 -9
  6. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +4 -8
  7. package/src/app/routes/_authenticated/_global-settings/utils/global-languages.ts +268 -0
  8. package/src/app/routes/_authenticated/_orders/components/order-address.tsx +15 -15
  9. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +4 -4
  10. package/src/app/routes/_authenticated/_product-variants/components/add-currency-dropdown.tsx +49 -0
  11. package/src/app/routes/_authenticated/_product-variants/components/add-stock-location-dropdown.tsx +56 -0
  12. package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +12 -0
  13. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +178 -50
  14. package/src/app/routes/_authenticated/_products/components/product-variants-table.tsx +0 -11
  15. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +3 -14
  16. package/src/app/routes/_authenticated/_shipping-methods/components/test-address-form.tsx +13 -12
  17. package/src/app/routes/_authenticated/_shipping-methods/components/test-order-builder.tsx +3 -2
  18. package/src/lib/components/data-input/customer-group-input.tsx +0 -1
  19. package/src/lib/components/data-input/money-input.tsx +7 -11
  20. package/src/lib/components/data-input/number-input.tsx +6 -1
  21. package/src/lib/components/data-table/data-table-filter-badge.tsx +15 -8
  22. package/src/lib/components/data-table/data-table.tsx +2 -2
  23. package/src/lib/components/data-table/my-views-button.tsx +12 -12
  24. package/src/lib/components/data-table/save-view-button.tsx +5 -1
  25. package/src/lib/components/layout/generated-breadcrumbs.tsx +4 -12
  26. package/src/lib/components/shared/configurable-operation-input.tsx +1 -1
  27. package/src/lib/constants.ts +10 -0
  28. package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +0 -2
  29. package/src/lib/framework/extension-api/types/layout.ts +41 -1
  30. package/src/lib/framework/form-engine/value-transformers.ts +8 -1
  31. package/src/lib/framework/layout-engine/page-layout.tsx +58 -48
  32. package/src/lib/framework/page/detail-page.tsx +12 -15
  33. package/src/lib/graphql/api.ts +17 -4
  34. package/src/lib/graphql/graphql-env.d.ts +29 -50
  35. package/src/lib/hooks/use-saved-views.ts +7 -0
  36. package/src/lib/providers/auth.tsx +2 -2
  37. package/src/lib/providers/channel-provider.tsx +4 -2
  38. package/src/lib/providers/user-settings.tsx +46 -5
@@ -0,0 +1,268 @@
1
+ export const globalLanguageCodes = [
2
+ /** Afrikaans */
3
+ 'af',
4
+ /** Akan */
5
+ 'ak',
6
+ /** Amharic */
7
+ 'am',
8
+ /** Arabic */
9
+ 'ar',
10
+ /** Assamese */
11
+ 'as',
12
+ /** Azerbaijani */
13
+ 'az',
14
+ /** Belarusian */
15
+ 'be',
16
+ /** Bulgarian */
17
+ 'bg',
18
+ /** Bambara */
19
+ 'bm',
20
+ /** Bangla */
21
+ 'bn',
22
+ /** Breton */
23
+ 'br',
24
+ /** Bosnian */
25
+ 'bs',
26
+ /** Catalan */
27
+ 'ca',
28
+ /** Chechen */
29
+ 'co',
30
+ /** Czech */
31
+ 'cs',
32
+ /** Welsh */
33
+ 'cy',
34
+ /** Danish */
35
+ 'da',
36
+ /** German */
37
+ 'de',
38
+ /** Ewe */
39
+ 'ee',
40
+ /** Greek */
41
+ 'el',
42
+ /** English */
43
+ 'en',
44
+ /** Esperanto */
45
+ 'eo',
46
+ /** Spanish */
47
+ 'es',
48
+ /** European Spanish */
49
+ 'es_ES',
50
+ /** Mexican Spanish */
51
+ 'es_MX',
52
+ /** Estonian */
53
+ 'et',
54
+ /** Basque */
55
+ 'eu',
56
+ /** Persian */
57
+ 'fa',
58
+ /** Dari */
59
+ 'fa_AF',
60
+ /** Finnish */
61
+ 'fi',
62
+ /** Faroese */
63
+ 'fo',
64
+ /** French */
65
+ 'fr',
66
+ /** Canadian French */
67
+ 'fr_CA',
68
+ /** Swiss French */
69
+ 'fr_CH',
70
+ /** Western Frisian */
71
+ 'fy',
72
+ /** Irish */
73
+ 'ga',
74
+ /** Scottish Gaelic */
75
+ 'gd',
76
+ /** Galician */
77
+ 'gl',
78
+ /** Gujarati */
79
+ 'gu',
80
+ /** Hausa */
81
+ 'ha',
82
+ /** Hebrew */
83
+ 'he',
84
+ /** Hindi */
85
+ 'hi',
86
+ /** Croatian */
87
+ 'hr',
88
+ /** Haitian Creole */
89
+ 'ht',
90
+ /** Hungarian */
91
+ 'hu',
92
+ /** Armenian */
93
+ 'hy',
94
+ /** Interlingua */
95
+ 'ia',
96
+ /** Indonesian */
97
+ 'id',
98
+ /** Igbo */
99
+ 'ig',
100
+ /** Icelandic */
101
+ 'is',
102
+ /** Italian */
103
+ 'it',
104
+ /** Japanese */
105
+ 'ja',
106
+ /** Javanese */
107
+ 'jv',
108
+ /** Georgian */
109
+ 'ka',
110
+ /** Kazakh */
111
+ 'kk',
112
+ /** Khmer */
113
+ 'km',
114
+ /** Kannada */
115
+ 'kn',
116
+ /** Korean */
117
+ 'ko',
118
+ /** Kurdish */
119
+ 'ku',
120
+ /** Kyrgyz */
121
+ 'ky',
122
+ /** Latin */
123
+ 'la',
124
+ /** Luxembourgish */
125
+ 'lb',
126
+ /** Ganda */
127
+ 'lg',
128
+ /** Lingala */
129
+ 'ln',
130
+ /** Lao */
131
+ 'lo',
132
+ /** Lithuanian */
133
+ 'lt',
134
+ /** Latvian */
135
+ 'lv',
136
+ /** Malagasy */
137
+ 'mg',
138
+ /** Maori */
139
+ 'mi',
140
+ /** Macedonian */
141
+ 'mk',
142
+ /** Malayalam */
143
+ 'ml',
144
+ /** Mongolian */
145
+ 'mn',
146
+ /** Marathi */
147
+ 'mr',
148
+ /** Malay */
149
+ 'ms',
150
+ /** Maltese */
151
+ 'mt',
152
+ /** Burmese */
153
+ 'my',
154
+ /** Norwegian Bokmål */
155
+ 'nb',
156
+ /** Nepali */
157
+ 'ne',
158
+ /** Dutch */
159
+ 'nl',
160
+ /** Flemish */
161
+ 'nl_BE',
162
+ /** Norwegian Nynorsk */
163
+ 'nn',
164
+ /** Nyanja */
165
+ 'ny',
166
+ /** Oromo */
167
+ 'om',
168
+ /** Odia */
169
+ 'or',
170
+ /** Punjabi */
171
+ 'pa',
172
+ /** Polish */
173
+ 'pl',
174
+ /** Pashto */
175
+ 'ps',
176
+ /** Portuguese */
177
+ 'pt',
178
+ /** Brazilian Portuguese */
179
+ 'pt_BR',
180
+ /** European Portuguese */
181
+ 'pt_PT',
182
+ /** Quechua */
183
+ 'qu',
184
+ /** Romansh */
185
+ 'rm',
186
+ /** Romanian */
187
+ 'ro',
188
+ /** Moldavian */
189
+ 'ro_MD',
190
+ /** Russian */
191
+ 'ru',
192
+ /** Kinyarwanda */
193
+ 'rw',
194
+ /** Sanskrit */
195
+ 'sa',
196
+ /** Sindhi */
197
+ 'sd',
198
+ /** Sinhala */
199
+ 'si',
200
+ /** Slovak */
201
+ 'sk',
202
+ /** Slovenian */
203
+ 'sl',
204
+ /** Samoan */
205
+ 'sm',
206
+ /** Shona */
207
+ 'sn',
208
+ /** Somali */
209
+ 'so',
210
+ /** Albanian */
211
+ 'sq',
212
+ /** Serbian */
213
+ 'sr',
214
+ /** Southern Sotho */
215
+ 'st',
216
+ /** Sundanese */
217
+ 'su',
218
+ /** Swedish */
219
+ 'sv',
220
+ /** Swahili */
221
+ 'sw',
222
+ /** Congo Swahili */
223
+ 'sw_CD',
224
+ /** Tamil */
225
+ 'ta',
226
+ /** Telugu */
227
+ 'te',
228
+ /** Tajik */
229
+ 'tg',
230
+ /** Thai */
231
+ 'th',
232
+ /** Tigrinya */
233
+ 'ti',
234
+ /** Turkmen */
235
+ 'tk',
236
+ /** Tongan */
237
+ 'to',
238
+ /** Turkish */
239
+ 'tr',
240
+ /** Tatar */
241
+ 'tt',
242
+ /** Uyghur */
243
+ 'ug',
244
+ /** Ukrainian */
245
+ 'uk',
246
+ /** Urdu */
247
+ 'ur',
248
+ /** Uzbek */
249
+ 'uz',
250
+ /** Vietnamese */
251
+ 'vi',
252
+ /** Wolof */
253
+ 'wo',
254
+ /** Xhosa */
255
+ 'xh',
256
+ /** Yiddish */
257
+ 'yi',
258
+ /** Yoruba */
259
+ 'yo',
260
+ /** Chinese */
261
+ 'zh',
262
+ /** Simplified Chinese */
263
+ 'zh_Hans',
264
+ /** Traditional Chinese */
265
+ 'zh_Hant',
266
+ /** Zulu */
267
+ 'zu',
268
+ ];
@@ -1,15 +1,13 @@
1
- import { Separator } from '@/vdb/components/ui/separator.js';
1
+ import { Trans } from '@lingui/react/macro';
2
2
  import { ResultOf } from 'gql.tada';
3
3
  import { Globe, Phone } from 'lucide-react';
4
4
  import { orderAddressFragment } from '../orders.graphql.js';
5
- import { Trans } from '@lingui/react/macro';
6
5
 
7
6
  type OrderAddress = Omit<ResultOf<typeof orderAddressFragment>, 'country'> & {
8
7
  country: string | { code: string; name: string } | null;
9
8
  };
10
9
 
11
10
  export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>) {
12
-
13
11
  const {
14
12
  fullName,
15
13
  company,
@@ -27,7 +25,11 @@ export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>)
27
25
  const countryCodeString = country && typeof country !== 'string' ? country?.code : countryCode;
28
26
 
29
27
  if (!address || Object.values(address).every(value => !value)) {
30
- return <div className="text-sm text-muted-foreground"><Trans>No address</Trans></div>;
28
+ return (
29
+ <div className="text-sm text-muted-foreground">
30
+ <Trans>No address</Trans>
31
+ </div>
32
+ );
31
33
  }
32
34
 
33
35
  return (
@@ -41,7 +43,7 @@ export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>)
41
43
  <p>{[city, province].filter(Boolean).join(', ')}</p>
42
44
  {postalCode && <p>{postalCode}</p>}
43
45
  {country && (
44
- <div className="flex items-center gap-1.5 mt-1">
46
+ <div className="flex items-center gap-1.5">
45
47
  <Globe className="h-3 w-3 text-muted-foreground" />
46
48
  <span>{countryName}</span>
47
49
  {countryCodeString && (
@@ -49,17 +51,15 @@ export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>)
49
51
  )}
50
52
  </div>
51
53
  )}
54
+ {phoneNumber && (
55
+ <>
56
+ <div className="flex items-center gap-1.5">
57
+ <Phone className="h-3 w-3 text-muted-foreground" />
58
+ <span className="text-sm">{phoneNumber}</span>
59
+ </div>
60
+ </>
61
+ )}
52
62
  </div>
53
-
54
- {phoneNumber && (
55
- <>
56
- <Separator className="my-2" />
57
- <div className="flex items-center gap-1.5">
58
- <Phone className="h-3 w-3 text-muted-foreground" />
59
- <span className="text-sm">{phoneNumber}</span>
60
- </div>
61
- </>
62
- )}
63
63
  </div>
64
64
  );
65
65
  }
@@ -241,7 +241,7 @@ export function OrderDetailShared({
241
241
  </PageBlock>
242
242
  <PageBlock column="side" blockId="customer" title={<Trans>Customer</Trans>}>
243
243
  {entity?.customer ? (
244
- <Button variant="ghost" asChild>
244
+ <Button variant="outline" asChild>
245
245
  <Link to={`/customers/${entity.customer.id}`}>
246
246
  <User className="w-4 h-4" />
247
247
  {entity.customer.firstName} {entity.customer.lastName}
@@ -255,7 +255,7 @@ export function OrderDetailShared({
255
255
  <div className="mt-4 divide-y">
256
256
  {entity?.shippingAddress && (
257
257
  <div className="pb-6">
258
- <div className="font-medium">
258
+ <div className="font-medium mb-6">
259
259
  <Trans>Shipping address</Trans>
260
260
  </div>
261
261
  <OrderAddress address={entity.shippingAddress} />
@@ -263,7 +263,7 @@ export function OrderDetailShared({
263
263
  )}
264
264
  {entity?.billingAddress && (
265
265
  <div className="pt-4">
266
- <div className="font-medium">
266
+ <div className="font-medium mb-6">
267
267
  <Trans>Billing address</Trans>
268
268
  </div>
269
269
  <OrderAddress address={entity.billingAddress} />
@@ -293,7 +293,7 @@ export function OrderDetailShared({
293
293
  ))}
294
294
  </div>
295
295
  ) : (
296
- <div className="text-muted-foreground text-xs font-medium p-3 border rounded-md">
296
+ <div className="text-muted-foreground text-sm">
297
297
  <Trans>No fulfillments</Trans>
298
298
  </div>
299
299
  )}
@@ -0,0 +1,49 @@
1
+ import { useLingui } from '@lingui/react/macro';
2
+ import { PlusIcon } from 'lucide-react';
3
+
4
+ import { Button } from '@/vdb/components/ui/button';
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuTrigger,
10
+ } from '@/vdb/components/ui/dropdown-menu';
11
+ import { useLocalFormat } from '@/vdb/hooks/use-local-format';
12
+
13
+ interface AddCurrencyDropdownProps {
14
+ unusedCurrencies: string[];
15
+ onCurrencySelect: (currencyCode: string) => void;
16
+ placeholder?: string;
17
+ }
18
+
19
+ export function AddCurrencyDropdown({
20
+ unusedCurrencies,
21
+ onCurrencySelect,
22
+ placeholder,
23
+ }: AddCurrencyDropdownProps) {
24
+ const { formatCurrencyName } = useLocalFormat();
25
+ const { t } = useLingui();
26
+
27
+ if (unusedCurrencies.length === 0) {
28
+ return null;
29
+ }
30
+
31
+ return (
32
+ <DropdownMenu>
33
+ <DropdownMenuTrigger asChild>
34
+ <Button variant="outline" className="gap-2">
35
+ <PlusIcon className="size-4" />
36
+ {placeholder || t`Add a price in another currency`}
37
+ </Button>
38
+ </DropdownMenuTrigger>
39
+ <DropdownMenuContent>
40
+ {unusedCurrencies.map(currencyCode => (
41
+ <DropdownMenuItem key={currencyCode} onSelect={() => onCurrencySelect(currencyCode)}>
42
+ <span className="uppercase text-muted-foreground">{currencyCode}</span>
43
+ {formatCurrencyName(currencyCode)}
44
+ </DropdownMenuItem>
45
+ ))}
46
+ </DropdownMenuContent>
47
+ </DropdownMenu>
48
+ );
49
+ }
@@ -0,0 +1,56 @@
1
+ import { useLingui } from '@lingui/react/macro';
2
+ import { PlusIcon } from 'lucide-react';
3
+
4
+ import { Button } from '@/vdb/components/ui/button';
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuTrigger,
10
+ } from '@/vdb/components/ui/dropdown-menu';
11
+ import { ResultOf } from 'gql.tada';
12
+
13
+ import { stockLocationsQueryDocument } from '../product-variants.graphql.js';
14
+
15
+ interface AddStockLocationDropdownProps {
16
+ availableStockLocations: ResultOf<typeof stockLocationsQueryDocument>['stockLocations']['items'];
17
+ usedStockLocationIds: string[];
18
+ onStockLocationSelect: (stockLocationId: string, stockLocationName: string) => void;
19
+ placeholder?: string;
20
+ }
21
+
22
+ export function AddStockLocationDropdown({
23
+ availableStockLocations,
24
+ usedStockLocationIds,
25
+ onStockLocationSelect,
26
+ placeholder,
27
+ }: AddStockLocationDropdownProps) {
28
+ const { t } = useLingui();
29
+
30
+ const unusedStockLocations = availableStockLocations.filter(sl => !usedStockLocationIds.includes(sl.id));
31
+
32
+ if (unusedStockLocations.length === 0) {
33
+ return null;
34
+ }
35
+
36
+ return (
37
+ <DropdownMenu>
38
+ <DropdownMenuTrigger asChild>
39
+ <Button variant="outline" className="gap-2">
40
+ <PlusIcon className="size-4" />
41
+ {placeholder || t`Add stock level for another location`}
42
+ </Button>
43
+ </DropdownMenuTrigger>
44
+ <DropdownMenuContent>
45
+ {unusedStockLocations.map(location => (
46
+ <DropdownMenuItem
47
+ key={location.id}
48
+ onSelect={() => onStockLocationSelect(location.id, location.name)}
49
+ >
50
+ {location.name}
51
+ </DropdownMenuItem>
52
+ ))}
53
+ </DropdownMenuContent>
54
+ </DropdownMenu>
55
+ );
56
+ }
@@ -193,3 +193,15 @@ export const updateProductVariantsDocument = graphql(`
193
193
  }
194
194
  }
195
195
  `);
196
+
197
+ export const stockLocationsQueryDocument = graphql(`
198
+ query StockLocations {
199
+ stockLocations(options: { take: 100 }) {
200
+ items {
201
+ id
202
+ name
203
+ description
204
+ }
205
+ }
206
+ }
207
+ `);