@vendure/dashboard 3.3.6-master-202507050232 → 3.3.6-master-202507090236
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/package.json +4 -4
- package/src/app/routes/_authenticated/_customers/components/customer-order-table.tsx +2 -2
- package/src/app/routes/_authenticated/_orders/components/money-gross-net.tsx +2 -2
- package/src/app/routes/_authenticated/_orders/components/shipping-method-selector.tsx +1 -1
- package/src/app/routes/_authenticated/_orders/orders.tsx +2 -2
- package/src/app/routes/_authenticated/_products/products_.$id.tsx +1 -1
- package/src/lib/framework/form-engine/use-generated-form.tsx +5 -2
- package/src/lib/framework/form-engine/utils.spec.ts +37 -0
- package/src/lib/framework/form-engine/utils.ts +47 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vendure/dashboard",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "3.3.6-master-
|
|
4
|
+
"version": "3.3.6-master-202507090236",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"@types/react-dom": "^19.0.4",
|
|
87
87
|
"@types/react-grid-layout": "^1.3.5",
|
|
88
88
|
"@uidotdev/usehooks": "^2.4.1",
|
|
89
|
-
"@vendure/common": "^3.3.6-master-
|
|
90
|
-
"@vendure/core": "^3.3.6-master-
|
|
89
|
+
"@vendure/common": "^3.3.6-master-202507090236",
|
|
90
|
+
"@vendure/core": "^3.3.6-master-202507090236",
|
|
91
91
|
"@vitejs/plugin-react": "^4.3.4",
|
|
92
92
|
"awesome-graphql-client": "^2.1.0",
|
|
93
93
|
"class-variance-authority": "^0.7.1",
|
|
@@ -130,5 +130,5 @@
|
|
|
130
130
|
"lightningcss-linux-arm64-musl": "^1.29.3",
|
|
131
131
|
"lightningcss-linux-x64-musl": "^1.29.1"
|
|
132
132
|
},
|
|
133
|
-
"gitHead": "
|
|
133
|
+
"gitHead": "df60d656c924e7574df61467ef1bbdb9a0221dcc"
|
|
134
134
|
}
|
|
@@ -40,7 +40,7 @@ export function CustomerOrderTable({ customerId }: Readonly<CustomerOrderTablePr
|
|
|
40
40
|
cell: ({ cell, row }) => {
|
|
41
41
|
const value = cell.getValue();
|
|
42
42
|
const currencyCode = row.original.currencyCode;
|
|
43
|
-
return <Money value={value}
|
|
43
|
+
return <Money value={value} currency={currencyCode} />;
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
46
|
totalWithTax: {
|
|
@@ -48,7 +48,7 @@ export function CustomerOrderTable({ customerId }: Readonly<CustomerOrderTablePr
|
|
|
48
48
|
cell: ({ cell, row }) => {
|
|
49
49
|
const value = cell.getValue();
|
|
50
50
|
const currencyCode = row.original.currencyCode;
|
|
51
|
-
return <Money value={value}
|
|
51
|
+
return <Money value={value} currency={currencyCode} />;
|
|
52
52
|
},
|
|
53
53
|
},
|
|
54
54
|
state: {
|
|
@@ -10,10 +10,10 @@ export function MoneyGrossNet({ priceWithTax, price, currencyCode }: Readonly<Mo
|
|
|
10
10
|
return (
|
|
11
11
|
<div className="flex flex-col gap-1">
|
|
12
12
|
<div>
|
|
13
|
-
<Money value={priceWithTax}
|
|
13
|
+
<Money value={priceWithTax} currency={currencyCode} />
|
|
14
14
|
</div>
|
|
15
15
|
<div className="text-xs text-muted-foreground">
|
|
16
|
-
<Money value={price}
|
|
16
|
+
<Money value={price} currency={currencyCode} />
|
|
17
17
|
</div>
|
|
18
18
|
</div>
|
|
19
19
|
);
|
|
@@ -48,7 +48,7 @@ export function ShippingMethodSelector({
|
|
|
48
48
|
<span className="text-sm font-medium">
|
|
49
49
|
<Trans>Price</Trans>
|
|
50
50
|
</span>
|
|
51
|
-
<Money value={method.priceWithTax}
|
|
51
|
+
<Money value={method.priceWithTax} currency={currencyCode} />
|
|
52
52
|
</div>
|
|
53
53
|
</div>
|
|
54
54
|
</CardContent>
|
|
@@ -61,7 +61,7 @@ function OrderListPage() {
|
|
|
61
61
|
cell: ({ cell, row }) => {
|
|
62
62
|
const value = cell.getValue();
|
|
63
63
|
const currencyCode = row.original.currencyCode;
|
|
64
|
-
return <Money value={value}
|
|
64
|
+
return <Money value={value} currency={currencyCode} />;
|
|
65
65
|
},
|
|
66
66
|
},
|
|
67
67
|
totalWithTax: {
|
|
@@ -69,7 +69,7 @@ function OrderListPage() {
|
|
|
69
69
|
cell: ({ cell, row }) => {
|
|
70
70
|
const value = cell.getValue();
|
|
71
71
|
const currencyCode = row.original.currencyCode;
|
|
72
|
-
return <Money value={value}
|
|
72
|
+
return <Money value={value} currency={currencyCode} />;
|
|
73
73
|
},
|
|
74
74
|
},
|
|
75
75
|
state: {
|
|
@@ -84,7 +84,7 @@ function ProductDetailPage() {
|
|
|
84
84
|
toast.success(i18n.t('Successfully updated product'));
|
|
85
85
|
resetForm();
|
|
86
86
|
if (creatingNewEntity) {
|
|
87
|
-
await navigate({ to: `../$
|
|
87
|
+
await navigate({ to: `../$id`, params: { id: data.id } });
|
|
88
88
|
}
|
|
89
89
|
},
|
|
90
90
|
onError: err => {
|
|
@@ -7,7 +7,7 @@ import { useChannel } from '../../hooks/use-channel.js';
|
|
|
7
7
|
import { useServerConfig } from '../../hooks/use-server-config.js';
|
|
8
8
|
import { getOperationVariablesFields } from '../document-introspection/get-document-structure.js';
|
|
9
9
|
import { createFormSchemaFromFields, getDefaultValuesFromFields } from './form-schema-tools.js';
|
|
10
|
-
import { transformRelationFields } from './utils.js';
|
|
10
|
+
import { removeEmptyIdFields, transformRelationFields } from './utils.js';
|
|
11
11
|
|
|
12
12
|
export interface GeneratedFormOptions<
|
|
13
13
|
T extends TypedDocumentNode<any, any>,
|
|
@@ -64,7 +64,10 @@ export function useGeneratedForm<
|
|
|
64
64
|
};
|
|
65
65
|
if (onSubmit) {
|
|
66
66
|
submitHandler = (event: FormEvent) => {
|
|
67
|
-
|
|
67
|
+
const onSubmitWrapper = (values: any) => {
|
|
68
|
+
onSubmit(removeEmptyIdFields(values, updateFields));
|
|
69
|
+
};
|
|
70
|
+
form.handleSubmit(onSubmitWrapper)(event);
|
|
68
71
|
};
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { graphql, VariablesOf } from 'gql.tada';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { getOperationVariablesFields } from '../document-introspection/get-document-structure.js';
|
|
5
|
+
|
|
6
|
+
import { removeEmptyIdFields } from './utils.js';
|
|
7
|
+
|
|
8
|
+
const createProductDocument = graphql(`
|
|
9
|
+
mutation CreateProduct($input: CreateProductInput!) {
|
|
10
|
+
createProduct(input: $input) {
|
|
11
|
+
id
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
`);
|
|
15
|
+
|
|
16
|
+
type CreateProductInput = VariablesOf<typeof createProductDocument>;
|
|
17
|
+
|
|
18
|
+
describe('removeEmptyIdFields', () => {
|
|
19
|
+
it('should remove empty translation id field', () => {
|
|
20
|
+
const values: CreateProductInput = {
|
|
21
|
+
input: { translations: [{ id: '', languageCode: 'en' }] },
|
|
22
|
+
};
|
|
23
|
+
const fields = getOperationVariablesFields(createProductDocument);
|
|
24
|
+
const result = removeEmptyIdFields(values, fields);
|
|
25
|
+
|
|
26
|
+
expect(result).toEqual({ input: { translations: [{ languageCode: 'en' }] } });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should remove empty featuredAsset id field', () => {
|
|
30
|
+
const values: CreateProductInput = {
|
|
31
|
+
input: { featuredAssetId: '', translations: [] },
|
|
32
|
+
};
|
|
33
|
+
const fields = getOperationVariablesFields(createProductDocument);
|
|
34
|
+
const result = removeEmptyIdFields(values, fields);
|
|
35
|
+
expect(result).toEqual({ input: { translations: [] } });
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -56,3 +56,50 @@ export function transformRelationFields<E extends Record<string, any>>(fields: F
|
|
|
56
56
|
|
|
57
57
|
return processedEntity;
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @description
|
|
62
|
+
* Due to the schema types, sometimes "create" mutations will have a default empty "id"
|
|
63
|
+
* field which can cause issues if we actually send them with a "create" mutation to the server.
|
|
64
|
+
* This function deletes any empty ID fields on the entity or its nested objects.
|
|
65
|
+
*/
|
|
66
|
+
export function removeEmptyIdFields<T extends Record<string, any>>(values: T, fields: FieldInfo[]): T {
|
|
67
|
+
if (!values) {
|
|
68
|
+
return values;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Create a deep copy to avoid mutating the original values
|
|
72
|
+
const result = structuredClone(values);
|
|
73
|
+
|
|
74
|
+
function recursiveRemove(obj: any, fieldDefs: FieldInfo[]) {
|
|
75
|
+
if (Array.isArray(obj)) {
|
|
76
|
+
for (const item of obj) {
|
|
77
|
+
recursiveRemove(item, fieldDefs);
|
|
78
|
+
}
|
|
79
|
+
} else if (typeof obj === 'object' && obj !== null) {
|
|
80
|
+
for (const field of fieldDefs) {
|
|
81
|
+
// Remove empty string ID fields at this level
|
|
82
|
+
if (field.type === 'ID' && typeof obj[field.name] === 'string' && obj[field.name] === '') {
|
|
83
|
+
delete obj[field.name];
|
|
84
|
+
}
|
|
85
|
+
// If the field is an object or array, recurse into it
|
|
86
|
+
if (Array.isArray(obj[field.name])) {
|
|
87
|
+
if (field.typeInfo) {
|
|
88
|
+
for (const item of obj[field.name]) {
|
|
89
|
+
recursiveRemove(item, field.typeInfo);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} else if (
|
|
93
|
+
typeof obj[field.name] === 'object' &&
|
|
94
|
+
obj[field.name] !== null &&
|
|
95
|
+
field.typeInfo
|
|
96
|
+
) {
|
|
97
|
+
recursiveRemove(obj[field.name], field.typeInfo);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
recursiveRemove(result, fields);
|
|
104
|
+
return result;
|
|
105
|
+
}
|