@vendure/dashboard 3.5.2-master-202512040233 → 3.5.2-master-202512180239
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/constants.js +2 -2
- package/dist/plugin/dashboard.plugin.js +1 -1
- package/dist/vite/constants.js +1 -0
- package/lingui.config.js +1 -0
- package/package.json +7 -7
- package/src/app/routeTree.gen.ts +1221 -0
- package/src/app/routes/_authenticated/_collections/collections.graphql.ts +1 -0
- package/src/app/routes/_authenticated/_collections/collections.tsx +249 -167
- package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +8 -0
- package/src/app/routes/_authenticated/_collections/components/move-collections-dialog.tsx +4 -0
- package/src/app/routes/_authenticated/_customers/components/customer-history/index.ts +0 -1
- package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +1 -1
- package/src/app/routes/_authenticated/_orders/components/add-surcharge-form.tsx +139 -0
- package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +3 -0
- package/src/app/routes/_authenticated/_orders/components/order-address.tsx +3 -3
- package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +49 -11
- package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +9 -0
- package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +23 -0
- package/src/app/routes/_authenticated/_product-variants/components/add-currency-dropdown.tsx +3 -3
- package/src/app/routes/_authenticated/_product-variants/components/add-stock-location-dropdown.tsx +2 -2
- package/src/app/routes/_authenticated/_products/products.graphql.ts +1 -0
- package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +2 -9
- package/src/i18n/locales/bg.po +3436 -0
- package/src/lib/components/data-input/datetime-input.tsx +1 -1
- package/src/lib/components/data-input/number-input.tsx +24 -5
- package/src/lib/components/data-input/relation-selector.tsx +1 -1
- package/src/lib/components/data-input/struct-form-input.tsx +175 -174
- package/src/lib/components/data-table/data-table-utils.ts +241 -1
- package/src/lib/components/data-table/data-table.tsx +190 -60
- package/src/lib/components/layout/manage-languages-dialog.tsx +2 -25
- package/src/lib/components/shared/custom-fields-form.tsx +13 -8
- package/src/lib/components/shared/paginated-list-data-table.tsx +19 -0
- package/src/lib/components/ui/alert.tsx +1 -1
- package/src/lib/components/ui/carousel.tsx +2 -2
- package/src/lib/components/ui/chart.tsx +1 -1
- package/src/lib/components/ui/context-menu.tsx +1 -1
- package/src/lib/components/ui/drawer.tsx +1 -1
- package/src/lib/components/ui/grid-layout.tsx +1 -1
- package/src/lib/components/ui/input-group.tsx +1 -0
- package/src/lib/components/ui/input-otp.tsx +1 -1
- package/src/lib/components/ui/menubar.tsx +1 -1
- package/src/lib/components/ui/navigation-menu.tsx +1 -1
- package/src/lib/components/ui/progress.tsx +1 -1
- package/src/lib/components/ui/radio-group.tsx +1 -1
- package/src/lib/components/ui/resizable.tsx +1 -1
- package/src/lib/components/ui/select.tsx +1 -1
- package/src/lib/components/ui/slider.tsx +1 -1
- package/src/lib/components/ui/toggle-group.tsx +2 -2
- package/src/lib/components/ui/toggle.tsx +1 -1
- package/src/lib/framework/component-registry/component-registry.tsx +2 -6
- package/src/lib/framework/extension-api/display-component-extensions.tsx +4 -3
- package/src/lib/framework/extension-api/logic/detail-forms.ts +0 -13
- package/src/lib/framework/extension-api/types/data-table.ts +4 -2
- package/src/lib/framework/extension-api/types/navigation.ts +2 -2
- package/src/lib/framework/form-engine/use-generated-form.tsx +7 -1
- package/src/lib/framework/layout-engine/page-layout.tsx +1 -1
- package/src/lib/framework/nav-menu/nav-menu-extensions.ts +1 -1
- package/src/lib/framework/page/detail-page-route-loader.tsx +1 -1
- package/src/lib/framework/page/list-page.tsx +62 -38
- package/src/lib/framework/page/page-api.ts +1 -1
- package/src/lib/framework/page/use-detail-page.ts +4 -2
- package/src/lib/framework/page/use-extended-router.tsx +20 -16
- package/src/lib/framework/registry/registry-types.ts +2 -1
- package/src/lib/graphql/graphql-env.d.ts +8 -12
- package/src/lib/hooks/use-drag-and-drop.ts +86 -0
- package/src/lib/providers/channel-provider.tsx +11 -7
- package/LICENSE.md +0 -42
- package/src/app/routes/_authenticated/_facets/components/edit-facet-value.tsx +0 -129
- /package/src/{app/routes/_authenticated/_global-settings → lib}/utils/global-languages.ts +0 -0
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from '@/vdb/components/ui/form.js';
|
|
11
11
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/vdb/components/ui/tabs.js';
|
|
12
12
|
import { CustomFormComponent } from '@/vdb/framework/form-engine/custom-form-component.js';
|
|
13
|
+
import { ConfigurableFieldDef } from '@/vdb/framework/form-engine/form-engine-types.js';
|
|
13
14
|
import { useCustomFieldConfig } from '@/vdb/hooks/use-custom-field-config.js';
|
|
14
15
|
import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
|
|
15
16
|
import { customFieldConfigFragment } from '@/vdb/providers/server-config.js';
|
|
@@ -20,7 +21,7 @@ import { Control } from 'react-hook-form';
|
|
|
20
21
|
import { FormControlAdapter } from '../../framework/form-engine/form-control-adapter.js';
|
|
21
22
|
import { TranslatableFormField } from './translatable-form-field.js';
|
|
22
23
|
|
|
23
|
-
type CustomFieldConfig = ResultOf<typeof customFieldConfigFragment>;
|
|
24
|
+
type CustomFieldConfig = Omit<ResultOf<typeof customFieldConfigFragment>, '__typename'>;
|
|
24
25
|
|
|
25
26
|
interface CustomFieldsFormProps {
|
|
26
27
|
entityType: string;
|
|
@@ -120,8 +121,8 @@ export function CustomFieldsForm({ entityType, control, formPathPrefix }: Readon
|
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
interface CustomFieldItemProps {
|
|
123
|
-
fieldDef:
|
|
124
|
-
control: Control<any
|
|
124
|
+
fieldDef: ConfigurableFieldDef;
|
|
125
|
+
control: Control<any>;
|
|
125
126
|
fieldName: string;
|
|
126
127
|
}
|
|
127
128
|
|
|
@@ -130,14 +131,19 @@ function CustomFieldItem({ fieldDef, control, fieldName }: Readonly<CustomFieldI
|
|
|
130
131
|
settings: { displayLanguage },
|
|
131
132
|
} = useUserSettings();
|
|
132
133
|
|
|
133
|
-
const getTranslation = (
|
|
134
|
+
const getTranslation = (
|
|
135
|
+
input: string | Array<{ languageCode: string; value: string }> | null | undefined,
|
|
136
|
+
) => {
|
|
137
|
+
if (typeof input === 'string') {
|
|
138
|
+
return input;
|
|
139
|
+
}
|
|
134
140
|
return input?.find(t => t.languageCode === displayLanguage)?.value;
|
|
135
141
|
};
|
|
136
142
|
const hasCustomFormComponent = fieldDef.ui?.component;
|
|
137
143
|
const isLocaleField = fieldDef.type === 'localeString' || fieldDef.type === 'localeText';
|
|
138
144
|
const shouldBeFullWidth = fieldDef.ui?.fullWidth === true;
|
|
139
145
|
const containerClassName = shouldBeFullWidth ? 'col-span-2' : '';
|
|
140
|
-
const isReadonly = fieldDef.readonly ?? false;
|
|
146
|
+
const isReadonly = (fieldDef as CustomFieldConfig).readonly ?? false;
|
|
141
147
|
|
|
142
148
|
// For locale fields, always use TranslatableFormField regardless of custom components
|
|
143
149
|
if (isLocaleField) {
|
|
@@ -212,7 +218,6 @@ function CustomFieldItem({ fieldDef, control, fieldName }: Readonly<CustomFieldI
|
|
|
212
218
|
<StructFormInput {...inputField} fieldDef={fieldDef} />
|
|
213
219
|
)}
|
|
214
220
|
defaultValue={{}} // Empty struct object as default
|
|
215
|
-
isFullWidth={true} // Structs should always be full-width
|
|
216
221
|
/>
|
|
217
222
|
</FormControl>
|
|
218
223
|
<FormDescription>{getTranslation(fieldDef.description)}</FormDescription>
|
|
@@ -266,9 +271,9 @@ function CustomFieldItem({ fieldDef, control, fieldName }: Readonly<CustomFieldI
|
|
|
266
271
|
}
|
|
267
272
|
|
|
268
273
|
interface CustomFieldFormItemProps {
|
|
269
|
-
fieldDef:
|
|
274
|
+
fieldDef: ConfigurableFieldDef;
|
|
270
275
|
getTranslation: (
|
|
271
|
-
input: Array<{ languageCode: string; value: string }> | null | undefined,
|
|
276
|
+
input: string | Array<{ languageCode: string; value: string }> | null | undefined,
|
|
272
277
|
) => string | undefined;
|
|
273
278
|
fieldName: string;
|
|
274
279
|
children: React.ReactNode;
|
|
@@ -234,6 +234,21 @@ export interface PaginatedListDataTableProps<
|
|
|
234
234
|
* the list needs to be refreshed.
|
|
235
235
|
*/
|
|
236
236
|
registerRefresher?: PaginatedListRefresherRegisterFn;
|
|
237
|
+
/**
|
|
238
|
+
* @description
|
|
239
|
+
* Callback when items are reordered via drag and drop.
|
|
240
|
+
* When provided, enables drag-and-drop functionality.
|
|
241
|
+
*/
|
|
242
|
+
onReorder?: (
|
|
243
|
+
oldIndex: number,
|
|
244
|
+
newIndex: number,
|
|
245
|
+
item: PaginatedListItemFields<T>,
|
|
246
|
+
) => void | Promise<void>;
|
|
247
|
+
/**
|
|
248
|
+
* @description
|
|
249
|
+
* When true, drag and drop will be disabled. This will only have an effect if the onReorder prop is also set
|
|
250
|
+
*/
|
|
251
|
+
disableDragAndDrop?: boolean;
|
|
237
252
|
}
|
|
238
253
|
|
|
239
254
|
export const PaginatedListDataTableKey = 'PaginatedListDataTable';
|
|
@@ -378,6 +393,8 @@ export function PaginatedListDataTable<
|
|
|
378
393
|
setTableOptions,
|
|
379
394
|
transformData,
|
|
380
395
|
registerRefresher,
|
|
396
|
+
onReorder,
|
|
397
|
+
disableDragAndDrop = false,
|
|
381
398
|
}: Readonly<PaginatedListDataTableProps<T, U, V, AC>>) {
|
|
382
399
|
const [searchTerm, setSearchTerm] = React.useState<string>('');
|
|
383
400
|
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
@@ -498,6 +515,8 @@ export function PaginatedListDataTable<
|
|
|
498
515
|
bulkActions={bulkActions}
|
|
499
516
|
setTableOptions={setTableOptions}
|
|
500
517
|
onRefresh={refetchPaginatedList}
|
|
518
|
+
onReorder={onReorder}
|
|
519
|
+
disableDragAndDrop={disableDragAndDrop}
|
|
501
520
|
/>
|
|
502
521
|
</PaginatedListContext.Provider>
|
|
503
522
|
);
|
|
@@ -8,7 +8,7 @@ const alertVariants = cva(
|
|
|
8
8
|
{
|
|
9
9
|
variants: {
|
|
10
10
|
variant: {
|
|
11
|
-
default: 'bg-background text-
|
|
11
|
+
default: 'bg-background text-primary/80',
|
|
12
12
|
destructive:
|
|
13
13
|
'border-destructive/50 text-destructive dark:text-destructive-foreground/80 dark:border-destructive [&>svg]:text-current dark:bg-destructive/50',
|
|
14
14
|
},
|
|
@@ -6,8 +6,8 @@ import useEmblaCarousel, {
|
|
|
6
6
|
} from "embla-carousel-react"
|
|
7
7
|
import { ArrowLeft, ArrowRight } from "lucide-react"
|
|
8
8
|
|
|
9
|
-
import { cn } from "@/vdb/lib/utils"
|
|
10
|
-
import { Button } from "@/vdb/components/ui/button"
|
|
9
|
+
import { cn } from "@/vdb/lib/utils.js"
|
|
10
|
+
import { Button } from "@/vdb/components/ui/button.js"
|
|
11
11
|
|
|
12
12
|
type CarouselApi = UseEmblaCarouselType[1]
|
|
13
13
|
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
|
@@ -4,7 +4,7 @@ import * as React from "react"
|
|
|
4
4
|
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
|
|
5
5
|
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
|
6
6
|
|
|
7
|
-
import { cn } from "@/vdb/lib/utils"
|
|
7
|
+
import { cn } from "@/vdb/lib/utils.js"
|
|
8
8
|
|
|
9
9
|
function ContextMenu({
|
|
10
10
|
...props
|
|
@@ -127,6 +127,7 @@ function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>)
|
|
|
127
127
|
'flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',
|
|
128
128
|
className,
|
|
129
129
|
)}
|
|
130
|
+
value={props.value}
|
|
130
131
|
{...props}
|
|
131
132
|
/>
|
|
132
133
|
);
|
|
@@ -2,7 +2,7 @@ import * as React from "react"
|
|
|
2
2
|
import * as MenubarPrimitive from "@radix-ui/react-menubar"
|
|
3
3
|
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
|
4
4
|
|
|
5
|
-
import { cn } from "@/vdb/lib/utils"
|
|
5
|
+
import { cn } from "@/vdb/lib/utils.js"
|
|
6
6
|
|
|
7
7
|
function Menubar({
|
|
8
8
|
className,
|
|
@@ -3,7 +3,7 @@ import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
|
|
|
3
3
|
import { cva } from "class-variance-authority"
|
|
4
4
|
import { ChevronDownIcon } from "lucide-react"
|
|
5
5
|
|
|
6
|
-
import { cn } from "@/vdb/lib/utils"
|
|
6
|
+
import { cn } from "@/vdb/lib/utils.js"
|
|
7
7
|
|
|
8
8
|
function NavigationMenu({
|
|
9
9
|
className,
|
|
@@ -2,7 +2,7 @@ import * as React from "react"
|
|
|
2
2
|
import { GripVerticalIcon } from "lucide-react"
|
|
3
3
|
import * as ResizablePrimitive from "react-resizable-panels"
|
|
4
4
|
|
|
5
|
-
import { cn } from "@/vdb/lib/utils"
|
|
5
|
+
import { cn } from "@/vdb/lib/utils.js"
|
|
6
6
|
|
|
7
7
|
function ResizablePanelGroup({
|
|
8
8
|
className,
|
|
@@ -2,7 +2,7 @@ import * as React from "react"
|
|
|
2
2
|
import * as SelectPrimitive from "@radix-ui/react-select"
|
|
3
3
|
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
|
4
4
|
|
|
5
|
-
import { cn } from "@/vdb/lib/utils"
|
|
5
|
+
import { cn } from "@/vdb/lib/utils.js"
|
|
6
6
|
|
|
7
7
|
function Select({
|
|
8
8
|
...props
|
|
@@ -4,8 +4,8 @@ import * as React from "react"
|
|
|
4
4
|
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
|
|
5
5
|
import { type VariantProps } from "class-variance-authority"
|
|
6
6
|
|
|
7
|
-
import { cn } from "@/vdb/lib/utils"
|
|
8
|
-
import { toggleVariants } from "@/vdb/components/ui/toggle"
|
|
7
|
+
import { cn } from "@/vdb/lib/utils.js"
|
|
8
|
+
import { toggleVariants } from "@/vdb/components/ui/toggle.js"
|
|
9
9
|
|
|
10
10
|
const ToggleGroupContext = React.createContext<
|
|
11
11
|
VariantProps<typeof toggleVariants>
|
|
@@ -2,7 +2,7 @@ import * as React from "react"
|
|
|
2
2
|
import * as TogglePrimitive from "@radix-ui/react-toggle"
|
|
3
3
|
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
4
|
|
|
5
|
-
import { cn } from "@/vdb/lib/utils"
|
|
5
|
+
import { cn } from "@/vdb/lib/utils.js"
|
|
6
6
|
|
|
7
7
|
const toggleVariants = cva(
|
|
8
8
|
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { DashboardFormComponent } from '@/vdb/framework/form-engine/form-engine-types.js';
|
|
2
|
-
import
|
|
2
|
+
import React from 'react';
|
|
3
3
|
import { getDisplayComponent } from '../extension-api/display-component-extensions.js';
|
|
4
4
|
import { getInputComponent } from '../extension-api/input-component-extensions.js';
|
|
5
5
|
|
|
6
|
-
export type
|
|
7
|
-
value: any;
|
|
8
|
-
} & T;
|
|
9
|
-
|
|
10
|
-
export type DataDisplayComponent = React.ComponentType<DataDisplayComponentProps>;
|
|
6
|
+
export type DataDisplayComponent<T extends Record<string, any> = Record<string, any>> = React.ComponentType<T & { value: any}>;
|
|
11
7
|
|
|
12
8
|
// Component registry hook that uses the global registry
|
|
13
9
|
export function useComponentRegistry() {
|
|
@@ -5,6 +5,7 @@ import { Money } from '@/vdb/components/data-display/money.js';
|
|
|
5
5
|
import { VendureImage } from '@/vdb/components/shared/vendure-image.js';
|
|
6
6
|
import { DataDisplayComponent } from '../component-registry/component-registry.js';
|
|
7
7
|
import { globalRegistry } from '../registry/global-registry.js';
|
|
8
|
+
import { DataTableDisplayComponent } from './types/data-table.js';
|
|
8
9
|
|
|
9
10
|
globalRegistry.register('displayComponents', new Map<string, DataDisplayComponent>());
|
|
10
11
|
|
|
@@ -21,7 +22,7 @@ displayComponents.set('vendure:money', Money);
|
|
|
21
22
|
displayComponents.set('vendure:json', Json);
|
|
22
23
|
|
|
23
24
|
export function getDisplayComponent(id: string): DataDisplayComponent | undefined {
|
|
24
|
-
return globalRegistry.get('displayComponents').get(id);
|
|
25
|
+
return globalRegistry.get('displayComponents').get(id) as DataDisplayComponent | undefined;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -42,10 +43,10 @@ export function addDisplayComponent({
|
|
|
42
43
|
pageId: string;
|
|
43
44
|
blockId: string;
|
|
44
45
|
field: string;
|
|
45
|
-
component:
|
|
46
|
+
component: DataDisplayComponent | DataTableDisplayComponent;
|
|
46
47
|
}) {
|
|
47
48
|
const displayComponents = globalRegistry.get('displayComponents');
|
|
48
|
-
|
|
49
|
+
|
|
49
50
|
// Generate the key using the helper function
|
|
50
51
|
const key = generateDisplayComponentKey(pageId, blockId, field);
|
|
51
52
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { addDetailQueryDocument } from '@/vdb/framework/form-engine/custom-form-component-extensions.js';
|
|
2
2
|
import { parse } from 'graphql';
|
|
3
3
|
|
|
4
|
-
import { addDisplayComponent } from '../display-component-extensions.js';
|
|
5
4
|
import { addInputComponent } from '../input-component-extensions.js';
|
|
6
5
|
import { DashboardDetailFormExtensionDefinition } from '../types/detail-forms.js';
|
|
7
6
|
|
|
@@ -31,18 +30,6 @@ export function registerDetailFormExtensions(detailForms?: DashboardDetailFormEx
|
|
|
31
30
|
});
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
// Register display components for this detail form
|
|
36
|
-
if (detailForm.displays) {
|
|
37
|
-
for (const displayComponent of detailForm.displays) {
|
|
38
|
-
addDisplayComponent({
|
|
39
|
-
pageId: detailForm.pageId,
|
|
40
|
-
blockId: displayComponent.blockId,
|
|
41
|
-
field: displayComponent.field,
|
|
42
|
-
component: displayComponent.component,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
33
|
}
|
|
47
34
|
}
|
|
48
35
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DataDisplayComponent } from '@/vdb/framework/component-registry/component-registry.js';
|
|
2
2
|
import { Table } from '@tanstack/react-table';
|
|
3
3
|
import { CellContext } from '@tanstack/table-core';
|
|
4
4
|
import { DocumentNode } from 'graphql';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
+
export type DataTableDisplayComponent = DataDisplayComponent<CellContext<any, any>>;
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* @description
|
|
9
11
|
* Allows you to define custom display components for specific columns in data tables.
|
|
@@ -24,7 +26,7 @@ export interface DashboardDataTableDisplayComponent {
|
|
|
24
26
|
* The React component that will be rendered as the display.
|
|
25
27
|
* It should accept `value` and other standard display props.
|
|
26
28
|
*/
|
|
27
|
-
component:
|
|
29
|
+
component: DataTableDisplayComponent;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
export type BulkActionContext<Item extends { id: string } & Record<string, any>> = {
|
|
@@ -39,7 +39,7 @@ export interface DashboardRouteDefinition {
|
|
|
39
39
|
* The value is a Tanstack Router
|
|
40
40
|
* [loader function](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#route-loaders)
|
|
41
41
|
*/
|
|
42
|
-
loader?: RouteOptions['loader'];
|
|
42
|
+
loader?: RouteOptions<any>['loader'];
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* @description
|
|
@@ -47,7 +47,7 @@ export interface DashboardRouteDefinition {
|
|
|
47
47
|
* The value is a Tanstack Router
|
|
48
48
|
* [validateSearch function](https://tanstack.com/router/latest/docs/framework/react/guide/search-params#search-param-validation)
|
|
49
49
|
*/
|
|
50
|
-
validateSearch?: RouteOptions['validateSearch'];
|
|
50
|
+
validateSearch?: RouteOptions<any>['validateSearch'];
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* @description
|
|
@@ -9,6 +9,10 @@ import { getOperationVariablesFields } from '../document-introspection/get-docum
|
|
|
9
9
|
import { createFormSchemaFromFields, getDefaultValuesFromFields } from './form-schema-tools.js';
|
|
10
10
|
import { removeEmptyIdFields, transformRelationFields } from './utils.js';
|
|
11
11
|
|
|
12
|
+
export type WithLooseCustomFields<T> = T extends { customFields?: any }
|
|
13
|
+
? Omit<T, 'customFields'> & { customFields?: T['customFields'] | unknown }
|
|
14
|
+
: T;
|
|
15
|
+
|
|
12
16
|
/**
|
|
13
17
|
* @description
|
|
14
18
|
* Options for the useGeneratedForm hook.
|
|
@@ -40,7 +44,9 @@ export interface GeneratedFormOptions<
|
|
|
40
44
|
customFieldConfig?: any[]; // Add custom field config for validation
|
|
41
45
|
setValues: (
|
|
42
46
|
entity: NonNullable<E>,
|
|
43
|
-
) =>
|
|
47
|
+
) => WithLooseCustomFields<
|
|
48
|
+
VarName extends keyof VariablesOf<T> ? VariablesOf<T>[VarName] : VariablesOf<T>
|
|
49
|
+
>;
|
|
44
50
|
onSubmit?: (
|
|
45
51
|
values: VarName extends keyof VariablesOf<T> ? VariablesOf<T>[VarName] : VariablesOf<T>,
|
|
46
52
|
) => void;
|
|
@@ -547,7 +547,7 @@ export type PageBlockProps = {
|
|
|
547
547
|
* @description
|
|
548
548
|
* Which column this block should appear in
|
|
549
549
|
*/
|
|
550
|
-
column: 'main' | 'side';
|
|
550
|
+
column: 'main' | 'side' | 'full';
|
|
551
551
|
/**
|
|
552
552
|
* @description
|
|
553
553
|
* The ID of the block, e.g. "gift-cards" or "related-products".
|
|
@@ -29,7 +29,7 @@ export function detailPageRouteLoader<T extends TypedDocumentNode<any, any>>({
|
|
|
29
29
|
queryDocument,
|
|
30
30
|
breadcrumb,
|
|
31
31
|
}: DetailPageRouteLoaderConfig<T>) {
|
|
32
|
-
const loader: FileBaseRouteOptions<any, any>['loader'] = async ({
|
|
32
|
+
const loader: FileBaseRouteOptions<any, any, any>['loader'] = async ({
|
|
33
33
|
context,
|
|
34
34
|
params,
|
|
35
35
|
location,
|
|
@@ -361,6 +361,22 @@ export interface ListPageProps<
|
|
|
361
361
|
* the list needs to be refreshed.
|
|
362
362
|
*/
|
|
363
363
|
registerRefresher?: PaginatedListRefresherRegisterFn;
|
|
364
|
+
/**
|
|
365
|
+
* @description
|
|
366
|
+
* Callback when items are reordered via drag and drop.
|
|
367
|
+
* Only applies to top-level items. When provided, enables drag-and-drop functionality.
|
|
368
|
+
*
|
|
369
|
+
* @param oldIndex - The original index of the dragged item
|
|
370
|
+
* @param newIndex - The new index where the item was dropped
|
|
371
|
+
* @param item - The data of the item that was moved
|
|
372
|
+
*/
|
|
373
|
+
onReorder?: (oldIndex: number, newIndex: number, item: any) => void | Promise<void>;
|
|
374
|
+
/**
|
|
375
|
+
* @description
|
|
376
|
+
* When true, drag and drop will be disabled. This will only have an effect if the onReorder prop is also set Useful when filtering or searching.
|
|
377
|
+
* Defaults to false. Only relevant when `onReorder` is provided.
|
|
378
|
+
*/
|
|
379
|
+
disableDragAndDrop?: boolean;
|
|
364
380
|
}
|
|
365
381
|
|
|
366
382
|
/**
|
|
@@ -481,6 +497,8 @@ export function ListPage<
|
|
|
481
497
|
setTableOptions,
|
|
482
498
|
bulkActions,
|
|
483
499
|
registerRefresher,
|
|
500
|
+
onReorder,
|
|
501
|
+
disableDragAndDrop = false,
|
|
484
502
|
}: Readonly<ListPageProps<T, U, V, AC>>) {
|
|
485
503
|
const route = typeof routeOrFn === 'function' ? routeOrFn() : routeOrFn;
|
|
486
504
|
const routeSearch = route.useSearch();
|
|
@@ -536,6 +554,47 @@ export function ListPage<
|
|
|
536
554
|
});
|
|
537
555
|
}
|
|
538
556
|
|
|
557
|
+
const commonTableProps = {
|
|
558
|
+
listQuery,
|
|
559
|
+
deleteMutation,
|
|
560
|
+
transformVariables,
|
|
561
|
+
customizeColumns: customizeColumns as any,
|
|
562
|
+
additionalColumns: additionalColumns as any,
|
|
563
|
+
defaultColumnOrder: columnOrder as any,
|
|
564
|
+
defaultVisibility: columnVisibility as any,
|
|
565
|
+
onSearchTermChange,
|
|
566
|
+
page: pagination.page,
|
|
567
|
+
itemsPerPage: pagination.itemsPerPage,
|
|
568
|
+
sorting,
|
|
569
|
+
columnFilters,
|
|
570
|
+
onPageChange: (table: Table<any>, page: number, perPage: number) => {
|
|
571
|
+
persistListStateToUrl(table, { page, perPage });
|
|
572
|
+
if (pageId) {
|
|
573
|
+
setTableSettings(pageId, 'pageSize', perPage);
|
|
574
|
+
}
|
|
575
|
+
},
|
|
576
|
+
onSortChange: (table: Table<any>, sorting: SortingState) => {
|
|
577
|
+
persistListStateToUrl(table, { sort: sorting });
|
|
578
|
+
},
|
|
579
|
+
onFilterChange: (table: Table<any>, filters: ColumnFiltersState) => {
|
|
580
|
+
persistListStateToUrl(table, { filters });
|
|
581
|
+
if (pageId) {
|
|
582
|
+
setTableSettings(pageId, 'columnFilters', filters);
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
onColumnVisibilityChange: (table: Table<any>, columnVisibility: any) => {
|
|
586
|
+
if (pageId) {
|
|
587
|
+
setTableSettings(pageId, 'columnVisibility', columnVisibility);
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
facetedFilters,
|
|
591
|
+
rowActions,
|
|
592
|
+
bulkActions,
|
|
593
|
+
setTableOptions,
|
|
594
|
+
transformData,
|
|
595
|
+
registerRefresher,
|
|
596
|
+
};
|
|
597
|
+
|
|
539
598
|
return (
|
|
540
599
|
<Page pageId={pageId}>
|
|
541
600
|
<PageTitle>{title}</PageTitle>
|
|
@@ -543,44 +602,9 @@ export function ListPage<
|
|
|
543
602
|
<PageLayout>
|
|
544
603
|
<FullWidthPageBlock blockId="list-table">
|
|
545
604
|
<PaginatedListDataTable
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
customizeColumns={customizeColumns as any}
|
|
550
|
-
additionalColumns={additionalColumns as any}
|
|
551
|
-
defaultColumnOrder={columnOrder as any}
|
|
552
|
-
defaultVisibility={columnVisibility as any}
|
|
553
|
-
onSearchTermChange={onSearchTermChange}
|
|
554
|
-
page={pagination.page}
|
|
555
|
-
itemsPerPage={pagination.itemsPerPage}
|
|
556
|
-
sorting={sorting}
|
|
557
|
-
columnFilters={columnFilters}
|
|
558
|
-
onPageChange={(table, page, perPage) => {
|
|
559
|
-
persistListStateToUrl(table, { page, perPage });
|
|
560
|
-
if (pageId) {
|
|
561
|
-
setTableSettings(pageId, 'pageSize', perPage);
|
|
562
|
-
}
|
|
563
|
-
}}
|
|
564
|
-
onSortChange={(table, sorting) => {
|
|
565
|
-
persistListStateToUrl(table, { sort: sorting });
|
|
566
|
-
}}
|
|
567
|
-
onFilterChange={(table, filters) => {
|
|
568
|
-
persistListStateToUrl(table, { filters });
|
|
569
|
-
if (pageId) {
|
|
570
|
-
setTableSettings(pageId, 'columnFilters', filters);
|
|
571
|
-
}
|
|
572
|
-
}}
|
|
573
|
-
onColumnVisibilityChange={(table, columnVisibility) => {
|
|
574
|
-
if (pageId) {
|
|
575
|
-
setTableSettings(pageId, 'columnVisibility', columnVisibility);
|
|
576
|
-
}
|
|
577
|
-
}}
|
|
578
|
-
facetedFilters={facetedFilters}
|
|
579
|
-
rowActions={rowActions}
|
|
580
|
-
bulkActions={bulkActions}
|
|
581
|
-
setTableOptions={setTableOptions}
|
|
582
|
-
transformData={transformData}
|
|
583
|
-
registerRefresher={registerRefresher}
|
|
605
|
+
{...commonTableProps}
|
|
606
|
+
onReorder={onReorder}
|
|
607
|
+
disableDragAndDrop={disableDragAndDrop}
|
|
584
608
|
/>
|
|
585
609
|
</FullWidthPageBlock>
|
|
586
610
|
</PageLayout>
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
getMutationName,
|
|
23
23
|
getQueryName,
|
|
24
24
|
} from '../document-introspection/get-document-structure.js';
|
|
25
|
-
import { useGeneratedForm } from '../form-engine/use-generated-form.js';
|
|
25
|
+
import { useGeneratedForm, WithLooseCustomFields } from '../form-engine/use-generated-form.js';
|
|
26
26
|
|
|
27
27
|
import { DetailEntityPath } from './page-types.js';
|
|
28
28
|
|
|
@@ -95,7 +95,9 @@ export interface DetailPageOptions<
|
|
|
95
95
|
* @description
|
|
96
96
|
* The function to set the values for the update document.
|
|
97
97
|
*/
|
|
98
|
-
setValuesForUpdate: (
|
|
98
|
+
setValuesForUpdate: (
|
|
99
|
+
entity: NonNullable<ResultOf<T>[EntityField]>,
|
|
100
|
+
) => WithLooseCustomFields<VariablesOf<U>[VarNameUpdate]>;
|
|
99
101
|
transformCreateInput?: (input: VariablesOf<C>[VarNameCreate]) => VariablesOf<C>[VarNameCreate];
|
|
100
102
|
transformUpdateInput?: (input: VariablesOf<U>[VarNameUpdate]) => VariablesOf<U>[VarNameUpdate];
|
|
101
103
|
/**
|