@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.
- package/dist/plugin/api/api-extensions.js +11 -14
- package/dist/plugin/api/metrics.resolver.d.ts +2 -2
- package/dist/plugin/api/metrics.resolver.js +2 -2
- package/dist/plugin/config/metrics-strategies.d.ts +9 -9
- package/dist/plugin/config/metrics-strategies.js +6 -6
- package/dist/plugin/constants.d.ts +2 -0
- package/dist/plugin/constants.js +3 -1
- package/dist/plugin/dashboard.plugin.js +13 -0
- package/dist/plugin/service/metrics.service.d.ts +3 -3
- package/dist/plugin/service/metrics.service.js +37 -53
- package/dist/plugin/types.d.ts +9 -12
- package/dist/plugin/types.js +7 -11
- package/dist/vite/vite-plugin-vendure-dashboard.js +2 -2
- package/package.json +4 -4
- package/src/app/routes/_authenticated/_collections/collections.tsx +7 -2
- package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +15 -2
- package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +14 -2
- package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +10 -0
- package/src/app/routes/_authenticated/_products/components/product-option-group-badge.tsx +19 -0
- package/src/app/routes/_authenticated/_products/components/product-options-table.tsx +111 -0
- package/src/app/routes/_authenticated/_products/product-option-groups.graphql.ts +103 -0
- package/src/app/routes/_authenticated/_products/products.graphql.ts +13 -1
- package/src/app/routes/_authenticated/_products/products.tsx +27 -3
- package/src/app/routes/_authenticated/_products/products_.$id.tsx +26 -9
- package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$id.tsx +181 -0
- package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +208 -0
- package/src/app/routes/_authenticated/_zones/components/zone-countries-sheet.tsx +4 -1
- package/src/app/routes/_authenticated/index.tsx +41 -24
- package/src/lib/components/data-display/json.tsx +16 -1
- package/src/lib/components/data-input/index.ts +3 -0
- package/src/lib/components/data-input/slug-input.tsx +296 -0
- package/src/lib/components/data-table/add-filter-menu.tsx +13 -6
- package/src/lib/components/data-table/data-table-bulk-action-item.tsx +38 -1
- package/src/lib/components/data-table/data-table-context.tsx +91 -0
- package/src/lib/components/data-table/data-table-filter-badge.tsx +9 -5
- package/src/lib/components/data-table/data-table-view-options.tsx +17 -8
- package/src/lib/components/data-table/data-table.tsx +146 -94
- package/src/lib/components/data-table/global-views-bar.tsx +97 -0
- package/src/lib/components/data-table/global-views-sheet.tsx +11 -0
- package/src/lib/components/data-table/manage-global-views-button.tsx +26 -0
- package/src/lib/components/data-table/my-views-button.tsx +47 -0
- package/src/lib/components/data-table/refresh-button.tsx +12 -3
- package/src/lib/components/data-table/save-view-button.tsx +45 -0
- package/src/lib/components/data-table/save-view-dialog.tsx +113 -0
- package/src/lib/components/data-table/use-generated-columns.tsx +3 -1
- package/src/lib/components/data-table/user-views-sheet.tsx +11 -0
- package/src/lib/components/data-table/views-sheet.tsx +297 -0
- package/src/lib/components/date-range-picker.tsx +184 -0
- package/src/lib/components/shared/paginated-list-data-table.tsx +59 -32
- package/src/lib/components/ui/button.tsx +1 -1
- package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +29 -2
- package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +10 -7
- package/src/lib/framework/dashboard-widget/metrics-widget/metrics-widget.graphql.ts +9 -3
- package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +19 -75
- package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +33 -0
- package/src/lib/framework/document-introspection/add-custom-fields.spec.ts +319 -9
- package/src/lib/framework/document-introspection/add-custom-fields.ts +60 -31
- package/src/lib/framework/document-introspection/get-document-structure.spec.ts +1 -159
- package/src/lib/framework/document-introspection/include-only-selected-list-fields.spec.ts +1840 -0
- package/src/lib/framework/document-introspection/include-only-selected-list-fields.ts +940 -0
- package/src/lib/framework/document-introspection/testing-utils.ts +161 -0
- package/src/lib/framework/extension-api/display-component-extensions.tsx +2 -0
- package/src/lib/framework/extension-api/types/data-table.ts +62 -4
- package/src/lib/framework/extension-api/types/navigation.ts +16 -0
- package/src/lib/framework/form-engine/utils.ts +34 -0
- package/src/lib/framework/page/list-page.tsx +289 -4
- package/src/lib/framework/page/use-extended-router.tsx +59 -17
- package/src/lib/graphql/api.ts +4 -2
- package/src/lib/graphql/graphql-env.d.ts +13 -10
- package/src/lib/hooks/use-extended-list-query.ts +5 -0
- package/src/lib/hooks/use-saved-views.ts +230 -0
- package/src/lib/index.ts +15 -0
- package/src/lib/types/saved-views.ts +39 -0
- 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
|
-
|
|
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:
|
|
133
|
-
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', () => {
|