@vendure/dashboard 3.4.3-master-202509260228 → 3.5.0-minor-202509261210

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 (74) hide show
  1. package/dist/plugin/api/api-extensions.js +11 -14
  2. package/dist/plugin/api/metrics.resolver.d.ts +2 -2
  3. package/dist/plugin/api/metrics.resolver.js +2 -2
  4. package/dist/plugin/config/metrics-strategies.d.ts +9 -9
  5. package/dist/plugin/config/metrics-strategies.js +6 -6
  6. package/dist/plugin/constants.d.ts +2 -0
  7. package/dist/plugin/constants.js +3 -1
  8. package/dist/plugin/dashboard.plugin.js +13 -0
  9. package/dist/plugin/service/metrics.service.d.ts +3 -3
  10. package/dist/plugin/service/metrics.service.js +37 -53
  11. package/dist/plugin/types.d.ts +9 -12
  12. package/dist/plugin/types.js +7 -11
  13. package/dist/vite/vite-plugin-vendure-dashboard.js +2 -2
  14. package/package.json +4 -4
  15. package/src/app/routes/_authenticated/_collections/collections.tsx +7 -2
  16. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +15 -2
  17. package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +14 -2
  18. package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +10 -0
  19. package/src/app/routes/_authenticated/_products/components/product-option-group-badge.tsx +19 -0
  20. package/src/app/routes/_authenticated/_products/components/product-options-table.tsx +111 -0
  21. package/src/app/routes/_authenticated/_products/product-option-groups.graphql.ts +103 -0
  22. package/src/app/routes/_authenticated/_products/products.graphql.ts +13 -1
  23. package/src/app/routes/_authenticated/_products/products.tsx +27 -3
  24. package/src/app/routes/_authenticated/_products/products_.$id.tsx +26 -9
  25. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$id.tsx +181 -0
  26. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +208 -0
  27. package/src/app/routes/_authenticated/_zones/components/zone-countries-sheet.tsx +4 -1
  28. package/src/app/routes/_authenticated/index.tsx +41 -24
  29. package/src/lib/components/data-display/json.tsx +16 -1
  30. package/src/lib/components/data-input/index.ts +3 -0
  31. package/src/lib/components/data-input/slug-input.tsx +296 -0
  32. package/src/lib/components/data-table/add-filter-menu.tsx +13 -6
  33. package/src/lib/components/data-table/data-table-bulk-action-item.tsx +38 -1
  34. package/src/lib/components/data-table/data-table-context.tsx +91 -0
  35. package/src/lib/components/data-table/data-table-filter-badge.tsx +9 -5
  36. package/src/lib/components/data-table/data-table-view-options.tsx +17 -8
  37. package/src/lib/components/data-table/data-table.tsx +146 -94
  38. package/src/lib/components/data-table/global-views-bar.tsx +97 -0
  39. package/src/lib/components/data-table/global-views-sheet.tsx +11 -0
  40. package/src/lib/components/data-table/manage-global-views-button.tsx +26 -0
  41. package/src/lib/components/data-table/my-views-button.tsx +47 -0
  42. package/src/lib/components/data-table/refresh-button.tsx +12 -3
  43. package/src/lib/components/data-table/save-view-button.tsx +45 -0
  44. package/src/lib/components/data-table/save-view-dialog.tsx +113 -0
  45. package/src/lib/components/data-table/use-generated-columns.tsx +3 -1
  46. package/src/lib/components/data-table/user-views-sheet.tsx +11 -0
  47. package/src/lib/components/data-table/views-sheet.tsx +297 -0
  48. package/src/lib/components/date-range-picker.tsx +184 -0
  49. package/src/lib/components/shared/paginated-list-data-table.tsx +59 -32
  50. package/src/lib/components/ui/button.tsx +1 -1
  51. package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +29 -2
  52. package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +10 -7
  53. package/src/lib/framework/dashboard-widget/metrics-widget/metrics-widget.graphql.ts +9 -3
  54. package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +19 -75
  55. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +33 -0
  56. package/src/lib/framework/document-introspection/add-custom-fields.spec.ts +319 -9
  57. package/src/lib/framework/document-introspection/add-custom-fields.ts +60 -31
  58. package/src/lib/framework/document-introspection/get-document-structure.spec.ts +1 -159
  59. package/src/lib/framework/document-introspection/include-only-selected-list-fields.spec.ts +1840 -0
  60. package/src/lib/framework/document-introspection/include-only-selected-list-fields.ts +940 -0
  61. package/src/lib/framework/document-introspection/testing-utils.ts +161 -0
  62. package/src/lib/framework/extension-api/display-component-extensions.tsx +2 -0
  63. package/src/lib/framework/extension-api/types/data-table.ts +62 -4
  64. package/src/lib/framework/extension-api/types/navigation.ts +16 -0
  65. package/src/lib/framework/form-engine/utils.ts +34 -0
  66. package/src/lib/framework/page/list-page.tsx +289 -4
  67. package/src/lib/framework/page/use-extended-router.tsx +59 -17
  68. package/src/lib/graphql/api.ts +4 -2
  69. package/src/lib/graphql/graphql-env.d.ts +13 -10
  70. package/src/lib/hooks/use-extended-list-query.ts +5 -0
  71. package/src/lib/hooks/use-saved-views.ts +230 -0
  72. package/src/lib/index.ts +15 -0
  73. package/src/lib/types/saved-views.ts +39 -0
  74. package/src/lib/utils/saved-views-utils.ts +40 -0
@@ -114,25 +114,75 @@ export function addCustomFields<T, V extends Variables = Variables>(
114
114
  const customFields = options?.customFieldsMap || globalCustomFieldsMap;
115
115
 
116
116
  const targetNodes: Array<{ typeName: string; selectionSet: SelectionSetNode }> = [];
117
+ const topLevelFragments = new Set<string>();
117
118
 
118
- const fragmentDefs = clone.definitions.filter(isFragmentDefinition);
119
- for (const fragmentDef of fragmentDefs) {
120
- targetNodes.push({
121
- typeName: fragmentDef.typeCondition.name.value,
122
- selectionSet: fragmentDef.selectionSet,
123
- });
124
- }
119
+ // First, identify which fragments are used at the top level (directly in items or in the main query)
125
120
  const queryDefs = clone.definitions.filter(isOperationDefinition);
126
121
 
127
122
  for (const queryDef of queryDefs) {
128
123
  const typeInfo = getOperationTypeInfo(queryDef);
129
124
  const fieldNode = queryDef.selectionSet.selections[0] as FieldNode;
130
125
  if (typeInfo && fieldNode?.selectionSet) {
126
+ let topLevelSelectionSet: SelectionSetNode | undefined;
127
+
128
+ // For paginated list queries, find the items field and add custom fields to its entity type
129
+ if (typeInfo.isPaginatedList) {
130
+ const itemsField = fieldNode.selectionSet.selections.find(
131
+ sel => sel.kind === 'Field' && sel.name.value === 'items',
132
+ ) as FieldNode | undefined;
133
+
134
+ if (itemsField?.selectionSet) {
135
+ // For paginated lists, the type is like "ProductList" but we need "Product"
136
+ const entityTypeName = typeInfo.type.replace(/List$/, '');
137
+ targetNodes.push({
138
+ typeName: entityTypeName,
139
+ selectionSet: itemsField.selectionSet,
140
+ });
141
+ topLevelSelectionSet = itemsField.selectionSet;
142
+ }
143
+ } else {
144
+ // For single entity queries, add custom fields to the top-level entity
145
+ targetNodes.push({
146
+ typeName: typeInfo.type,
147
+ selectionSet: fieldNode.selectionSet,
148
+ });
149
+ topLevelSelectionSet = fieldNode.selectionSet;
150
+ }
151
+
152
+ // Track which fragments are used at the top level (not in nested entities)
153
+ if (topLevelSelectionSet) {
154
+ for (const selection of topLevelSelectionSet.selections) {
155
+ if (selection.kind === Kind.FRAGMENT_SPREAD) {
156
+ topLevelFragments.add(selection.name.value);
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ // Now add fragments
164
+ const fragmentDefs = clone.definitions.filter(isFragmentDefinition);
165
+
166
+ // Check if this document has query definitions - if not, add all fragments
167
+ const hasQueries = queryDefs.length > 0;
168
+
169
+ for (const fragmentDef of fragmentDefs) {
170
+ if (hasQueries) {
171
+ // If we have queries, only add custom fields to fragments used at the top level
172
+ // Skip fragments that are only used in nested contexts
173
+ if (topLevelFragments.has(fragmentDef.name.value)) {
174
+ targetNodes.push({
175
+ typeName: fragmentDef.typeCondition.name.value,
176
+ selectionSet: fragmentDef.selectionSet,
177
+ });
178
+ }
179
+ } else {
180
+ // For standalone fragments (no queries), add custom fields to all fragments
181
+ // since we don't know where they'll be used
131
182
  targetNodes.push({
132
- typeName: typeInfo.type,
133
- selectionSet: fieldNode.selectionSet,
183
+ typeName: fragmentDef.typeCondition.name.value,
184
+ selectionSet: fragmentDef.selectionSet,
134
185
  });
135
- addTargetNodesRecursively(fieldNode.selectionSet, typeInfo.type, targetNodes);
136
186
  }
137
187
  }
138
188
 
@@ -271,24 +321,3 @@ function isOperationDefinition(value: DefinitionNode): value is OperationDefinit
271
321
  function isFieldNode(value: SelectionNode): value is FieldNode {
272
322
  return value.kind === Kind.FIELD;
273
323
  }
274
-
275
- function addTargetNodesRecursively(
276
- selectionSet: SelectionSetNode,
277
- parentTypeName: string,
278
- targetNodes: Array<{ typeName: string; selectionSet: SelectionSetNode }>,
279
- ) {
280
- for (const selection of selectionSet.selections) {
281
- if (selection.kind === 'Field' && selection.selectionSet) {
282
- const fieldNode = selection;
283
- const typeInfo = getOperationTypeInfo(fieldNode, parentTypeName); // Assuming this function can handle FieldNode
284
- if (typeInfo && fieldNode.selectionSet) {
285
- targetNodes.push({
286
- typeName: typeInfo.type,
287
- selectionSet: fieldNode.selectionSet,
288
- });
289
- // Recursively process the selection set of the current field
290
- addTargetNodesRecursively(fieldNode.selectionSet, typeInfo.type, targetNodes);
291
- }
292
- }
293
- }
294
- }
@@ -8,165 +8,7 @@ import {
8
8
  } from './get-document-structure.js';
9
9
 
10
10
  vi.mock('virtual:admin-api-schema', () => {
11
- return {
12
- schemaInfo: {
13
- types: {
14
- Query: {
15
- products: ['ProductList', false, false, true],
16
- product: ['Product', false, false, false],
17
- collection: ['Collection', false, false, false],
18
- order: ['Order', false, false, false],
19
- },
20
- Mutation: {
21
- updateProduct: ['Product', false, false, false],
22
- adjustDraftOrderLine: ['Order', false, false, false],
23
- },
24
-
25
- Collection: {
26
- id: ['ID', false, false, false],
27
- name: ['String', false, false, false],
28
- productVariants: ['ProductVariantList', false, false, true],
29
- },
30
-
31
- ProductVariantList: {
32
- items: ['ProductVariant', false, true, false],
33
- totalItems: ['Int', false, false, false],
34
- },
35
-
36
- Product: {
37
- channels: ['Channel', false, true, false],
38
- id: ['ID', false, false, false],
39
- createdAt: ['DateTime', false, false, false],
40
- updatedAt: ['DateTime', false, false, false],
41
- languageCode: ['LanguageCode', false, false, false],
42
- name: ['String', false, false, false],
43
- slug: ['String', false, false, false],
44
- description: ['String', false, false, false],
45
- enabled: ['Boolean', false, false, false],
46
- featuredAsset: ['Asset', true, false, false],
47
- assets: ['Asset', false, true, false],
48
- variants: ['ProductVariant', false, true, false],
49
- variantList: ['ProductVariantList', false, false, true],
50
- optionGroups: ['ProductOptionGroup', false, true, false],
51
- facetValues: ['FacetValue', false, true, false],
52
- translations: ['ProductTranslation', false, true, false],
53
- collections: ['Collection', false, true, false],
54
- reviews: ['ProductReviewList', false, false, true],
55
- reviewsHistogram: ['ProductReviewHistogramItem', false, true, false],
56
- customFields: ['ProductCustomFields', true, false, false],
57
- },
58
- ProductVariantPrice: {
59
- currencyCode: ['CurrencyCode', false, false, false],
60
- price: ['Money', false, false, false],
61
- customFields: ['JSON', true, false, false],
62
- },
63
- ProductVariant: {
64
- enabled: ['Boolean', false, false, false],
65
- trackInventory: ['GlobalFlag', false, false, false],
66
- stockOnHand: ['Int', false, false, false],
67
- stockAllocated: ['Int', false, false, false],
68
- outOfStockThreshold: ['Int', false, false, false],
69
- useGlobalOutOfStockThreshold: ['Boolean', false, false, false],
70
- prices: ['ProductVariantPrice', false, true, false],
71
- stockLevels: ['StockLevel', false, true, false],
72
- stockMovements: ['StockMovementList', false, false, false],
73
- channels: ['Channel', false, true, false],
74
- id: ['ID', false, false, false],
75
- product: ['Product', false, false, false],
76
- productId: ['ID', false, false, false],
77
- createdAt: ['DateTime', false, false, false],
78
- updatedAt: ['DateTime', false, false, false],
79
- languageCode: ['LanguageCode', false, false, false],
80
- sku: ['String', false, false, false],
81
- name: ['String', false, false, false],
82
- featuredAsset: ['Asset', true, false, false],
83
- assets: ['Asset', false, true, false],
84
- price: ['Money', false, false, false],
85
- currencyCode: ['CurrencyCode', false, false, false],
86
- priceWithTax: ['Money', false, false, false],
87
- stockLevel: ['String', false, false, false],
88
- taxRateApplied: ['TaxRate', false, false, false],
89
- taxCategory: ['TaxCategory', false, false, false],
90
- options: ['ProductOption', false, true, false],
91
- facetValues: ['FacetValue', false, true, false],
92
- translations: ['ProductVariantTranslation', false, true, false],
93
- customFields: ['JSON', true, false, false],
94
- },
95
- ProductCustomFields: {
96
- custom1: ['String', false, false, false],
97
- },
98
-
99
- Asset: {
100
- id: ['ID', false, false, false],
101
- createdAt: ['DateTime', false, false, false],
102
- updatedAt: ['DateTime', false, false, false],
103
- name: ['String', false, false, false],
104
- type: ['AssetType', false, false, false],
105
- fileSize: ['Int', false, false, false],
106
- mimeType: ['String', false, false, false],
107
- width: ['Int', false, false, false],
108
- height: ['Int', false, false, false],
109
- source: ['String', false, false, false],
110
- preview: ['String', false, false, false],
111
- focalPoint: ['Coordinate', true, false, false],
112
- tags: ['Tag', false, true, false],
113
- customFields: ['JSON', true, false, false],
114
- },
115
- ProductTranslation: {
116
- id: ['ID', false, false, false],
117
- createdAt: ['DateTime', false, false, false],
118
- updatedAt: ['DateTime', false, false, false],
119
- languageCode: ['LanguageCode', false, false, false],
120
- name: ['String', false, false, false],
121
- slug: ['String', false, false, false],
122
- description: ['String', false, false, false],
123
- customFields: ['ProductTranslationCustomFields', true, false, false],
124
- },
125
- ProductList: {
126
- items: ['Product', false, true, false],
127
- totalItems: ['Int', false, false, false],
128
- },
129
-
130
- ProductVariantTranslation: {
131
- id: ['ID', false, false, false],
132
- createdAt: ['DateTime', false, false, false],
133
- updatedAt: ['DateTime', false, false, false],
134
- languageCode: ['LanguageCode', false, false, false],
135
- name: ['String', false, false, false],
136
- },
137
- Order: {
138
- id: ['ID', false, false, false],
139
- lines: ['OrderLine', false, true, false],
140
- },
141
- OrderLine: {
142
- id: ['ID', false, false, false],
143
- quantity: ['Int', false, false, false],
144
- },
145
- },
146
- inputs: {
147
- UpdateProductInput: {
148
- id: ['ID', false, false, false],
149
- name: ['String', false, false, false],
150
- },
151
- AdjustDraftOrderLineInput: {
152
- orderLineId: ['ID', false, false, false],
153
- quantity: ['Int', false, false, false],
154
- },
155
- },
156
- scalars: [
157
- 'ID',
158
- 'String',
159
- 'Int',
160
- 'Boolean',
161
- 'Float',
162
- 'JSON',
163
- 'DateTime',
164
- 'Upload',
165
- 'CurrencyCode',
166
- ],
167
- enums: {},
168
- },
169
- };
11
+ return import('./testing-utils.js').then(m => m.getMockSchemaInfo());
170
12
  });
171
13
 
172
14
  describe('getListQueryFields', () => {