@vendure/dashboard 3.3.8 → 3.4.0

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 (131) hide show
  1. package/README.md +62 -0
  2. package/dist/plugin/api/api-extensions.d.ts +1 -0
  3. package/dist/plugin/api/api-extensions.js +38 -0
  4. package/dist/plugin/api/metrics.resolver.d.ts +8 -0
  5. package/dist/plugin/api/metrics.resolver.js +40 -0
  6. package/dist/plugin/config/metrics-strategies.d.ts +39 -0
  7. package/dist/plugin/config/metrics-strategies.js +74 -0
  8. package/dist/plugin/constants.d.ts +4 -3
  9. package/dist/plugin/constants.js +10 -277
  10. package/dist/plugin/dashboard.plugin.d.ts +95 -0
  11. package/dist/plugin/dashboard.plugin.js +168 -0
  12. package/dist/plugin/index.d.ts +2 -1
  13. package/dist/plugin/index.js +18 -1
  14. package/dist/plugin/package.json +3 -0
  15. package/dist/plugin/service/metrics.service.d.ts +15 -0
  16. package/dist/plugin/service/metrics.service.js +145 -0
  17. package/dist/plugin/types.d.ts +20 -37
  18. package/dist/plugin/types.js +13 -1
  19. package/dist/vite/constants.d.ts +5 -0
  20. package/dist/vite/constants.js +277 -0
  21. package/dist/vite/index.d.ts +1 -0
  22. package/dist/vite/index.js +1 -0
  23. package/dist/vite/types.d.ts +40 -0
  24. package/dist/vite/utils/config-loader.js +1 -0
  25. package/dist/{plugin → vite}/utils/plugin-discovery.js +1 -1
  26. package/dist/vite/utils/ui-config.d.ts +3 -0
  27. package/dist/vite/utils/ui-config.js +30 -0
  28. package/dist/vite/vite-plugin-ui-config.d.ts +123 -0
  29. package/dist/{plugin → vite}/vite-plugin-ui-config.js +3 -11
  30. package/dist/{plugin → vite}/vite-plugin-vendure-dashboard.js +1 -1
  31. package/index.html +1 -1
  32. package/package.json +16 -7
  33. package/src/app/app-providers.tsx +1 -1
  34. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +1 -1
  35. package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +20 -35
  36. package/src/app/routes/_authenticated/_facets/facets.graphql.ts +40 -0
  37. package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +147 -0
  38. package/src/app/routes/_authenticated/_orders/components/order-history/order-history.tsx +380 -33
  39. package/src/app/routes/_authenticated/_products/components/option-value-input.tsx +1 -1
  40. package/src/app/routes/_authenticated/_system/healthchecks.tsx +1 -1
  41. package/src/app/routes/_authenticated/_system/job-queue.tsx +1 -0
  42. package/src/app/routes/_authenticated/index.tsx +2 -2
  43. package/src/app/routes/_authenticated.tsx +1 -1
  44. package/src/lib/components/data-input/rich-text-input.tsx +14 -8
  45. package/src/lib/components/data-table/data-table-bulk-actions.tsx +17 -4
  46. package/src/lib/components/layout/app-layout.tsx +2 -7
  47. package/src/lib/components/layout/channel-switcher.tsx +166 -57
  48. package/src/lib/components/layout/dev-mode-indicator.tsx +18 -0
  49. package/src/lib/components/layout/language-dialog.tsx +2 -1
  50. package/src/lib/components/layout/manage-languages-dialog.tsx +77 -40
  51. package/src/lib/components/layout/nav-item-wrapper.tsx +107 -0
  52. package/src/lib/components/layout/nav-main.tsx +196 -107
  53. package/src/lib/components/login/login-form.tsx +80 -45
  54. package/src/lib/components/shared/asset/asset-bulk-actions.tsx +19 -4
  55. package/src/lib/components/shared/asset/asset-gallery.tsx +2 -2
  56. package/src/lib/components/shared/detail-page-button.tsx +42 -0
  57. package/src/lib/components/shared/history-timeline/history-entry-date.tsx +37 -0
  58. package/src/lib/components/shared/history-timeline/history-entry.tsx +135 -65
  59. package/src/lib/components/shared/history-timeline/history-note-input.tsx +4 -4
  60. package/src/lib/components/shared/history-timeline/history-timeline.tsx +7 -54
  61. package/src/lib/components/shared/translatable-form-field.tsx +16 -2
  62. package/src/lib/framework/defaults.ts +4 -10
  63. package/src/lib/framework/extension-api/define-dashboard-extension.ts +4 -0
  64. package/src/lib/framework/extension-api/extension-api-types.ts +11 -2
  65. package/src/lib/framework/extension-api/logic/index.ts +1 -0
  66. package/src/lib/framework/extension-api/logic/login.ts +17 -0
  67. package/src/lib/framework/extension-api/logic/navigation.ts +1 -0
  68. package/src/lib/framework/extension-api/types/data-table.ts +12 -3
  69. package/src/lib/framework/extension-api/types/detail-forms.ts +13 -0
  70. package/src/lib/framework/extension-api/types/form-components.ts +11 -0
  71. package/src/lib/framework/extension-api/types/index.ts +1 -0
  72. package/src/lib/framework/extension-api/types/layout.ts +3 -6
  73. package/src/lib/framework/extension-api/types/login.ts +96 -0
  74. package/src/lib/framework/extension-api/types/navigation.ts +57 -0
  75. package/src/lib/framework/extension-api/types/widgets.ts +0 -4
  76. package/src/lib/framework/extension-api/use-login-extensions.ts +26 -0
  77. package/src/lib/framework/layout-engine/dev-mode-button.tsx +24 -0
  78. package/src/lib/framework/layout-engine/location-wrapper.tsx +5 -12
  79. package/src/lib/framework/registry/global-registry.ts +4 -0
  80. package/src/lib/framework/registry/registry-types.ts +2 -0
  81. package/src/lib/graphql/api.ts +25 -3
  82. package/src/lib/graphql/graphql-env.d.ts +28 -28
  83. package/src/lib/graphql/settings-store-operations.ts +17 -0
  84. package/src/lib/hooks/use-floating-bulk-actions.ts +82 -0
  85. package/src/lib/hooks/use-local-format.ts +20 -5
  86. package/src/lib/index.ts +2 -1
  87. package/src/lib/providers/channel-provider.tsx +13 -11
  88. package/src/lib/providers/user-settings.tsx +78 -3
  89. package/src/lib/virtual.d.ts +26 -2
  90. package/src/vite-env.d.ts +2 -0
  91. package/vite/utils/plugin-discovery.ts +1 -1
  92. package/vite/utils/ui-config.ts +30 -42
  93. package/vite/vite-plugin-ui-config.ts +119 -17
  94. package/vite/vite-plugin-vendure-dashboard.ts +1 -1
  95. package/dist/plugin/utils/ui-config.d.ts +0 -3
  96. package/dist/plugin/utils/ui-config.js +0 -34
  97. package/dist/plugin/vite-plugin-ui-config.d.ts +0 -15
  98. package/src/app/routes/_authenticated/_facets/components/add-facet-value-dialog.tsx +0 -146
  99. package/src/lib/components/shared/rich-text-editor.tsx +0 -0
  100. /package/dist/{plugin/utils/ast-utils.spec.d.ts → vite/types.js} +0 -0
  101. /package/dist/{plugin → vite}/utils/ast-utils.d.ts +0 -0
  102. /package/dist/{plugin → vite}/utils/ast-utils.js +0 -0
  103. /package/dist/{plugin/utils/config-loader.d.ts → vite/utils/ast-utils.spec.d.ts} +0 -0
  104. /package/dist/{plugin → vite}/utils/ast-utils.spec.js +0 -0
  105. /package/dist/{plugin → vite}/utils/compiler.d.ts +0 -0
  106. /package/dist/{plugin → vite}/utils/compiler.js +0 -0
  107. /package/dist/{plugin/utils/config-loader.js → vite/utils/config-loader.d.ts} +0 -0
  108. /package/dist/{plugin → vite}/utils/logger.d.ts +0 -0
  109. /package/dist/{plugin → vite}/utils/logger.js +0 -0
  110. /package/dist/{plugin → vite}/utils/plugin-discovery.d.ts +0 -0
  111. /package/dist/{plugin → vite}/utils/schema-generator.d.ts +0 -0
  112. /package/dist/{plugin → vite}/utils/schema-generator.js +0 -0
  113. /package/dist/{plugin → vite}/utils/tsconfig-utils.d.ts +0 -0
  114. /package/dist/{plugin → vite}/utils/tsconfig-utils.js +0 -0
  115. /package/dist/{plugin → vite}/vite-plugin-admin-api-schema.d.ts +0 -0
  116. /package/dist/{plugin → vite}/vite-plugin-admin-api-schema.js +0 -0
  117. /package/dist/{plugin → vite}/vite-plugin-config-loader.d.ts +0 -0
  118. /package/dist/{plugin → vite}/vite-plugin-config-loader.js +0 -0
  119. /package/dist/{plugin → vite}/vite-plugin-config.d.ts +0 -0
  120. /package/dist/{plugin → vite}/vite-plugin-config.js +0 -0
  121. /package/dist/{plugin → vite}/vite-plugin-dashboard-metadata.d.ts +0 -0
  122. /package/dist/{plugin → vite}/vite-plugin-dashboard-metadata.js +0 -0
  123. /package/dist/{plugin → vite}/vite-plugin-gql-tada.d.ts +0 -0
  124. /package/dist/{plugin → vite}/vite-plugin-gql-tada.js +0 -0
  125. /package/dist/{plugin → vite}/vite-plugin-tailwind-source.d.ts +0 -0
  126. /package/dist/{plugin → vite}/vite-plugin-tailwind-source.js +0 -0
  127. /package/dist/{plugin → vite}/vite-plugin-theme.d.ts +0 -0
  128. /package/dist/{plugin → vite}/vite-plugin-theme.js +0 -0
  129. /package/dist/{plugin → vite}/vite-plugin-transform-index.d.ts +0 -0
  130. /package/dist/{plugin → vite}/vite-plugin-transform-index.js +0 -0
  131. /package/dist/{plugin → vite}/vite-plugin-vendure-dashboard.d.ts +0 -0
@@ -7,6 +7,7 @@ import { DocumentNode } from 'graphql';
7
7
  * The pageId is already defined in the data table extension, so only the column name is needed.
8
8
  *
9
9
  * @docsCategory extensions
10
+ * @docsPage DataTable
10
11
  * @since 3.4.0
11
12
  */
12
13
  export interface DashboardDataTableDisplayComponent {
@@ -39,21 +40,29 @@ export type BulkActionComponent<Item extends { id: string } & Record<string, any
39
40
  * A bulk action is a component that will be rendered in the bulk actions dropdown.
40
41
  *
41
42
  * @docsCategory components
42
- * @docsPage DataTableBulkActions
43
+ * @docsPage DataTable
43
44
  * @since 3.4.0
44
45
  */
45
46
  export type BulkAction = {
47
+ /**
48
+ * @description
49
+ * Optional order number to control the position of this bulk action in the dropdown.
50
+ * A larger number will appear lower in the list.
51
+ */
46
52
  order?: number;
53
+ /**
54
+ * @description
55
+ * The React component that will be rendered as the bulk action item.
56
+ */
47
57
  component: BulkActionComponent<any>;
48
58
  };
49
59
 
50
60
  /**
51
61
  * @description
52
- * **Status: Developer Preview**
53
- *
54
62
  * This allows you to customize aspects of existing data tables in the dashboard.
55
63
  *
56
64
  * @docsCategory extensions
65
+ * @docsPage DataTable
57
66
  * @since 3.4.0
58
67
  */
59
68
  export interface DashboardDataTableExtensionDefinition {
@@ -10,6 +10,7 @@ import { DocumentNode } from 'graphql';
10
10
  * The pageId is already defined in the detail form extension, so only the blockId and field are needed.
11
11
  *
12
12
  * @docsCategory extensions
13
+ * @docsPage DetailForms
13
14
  * @since 3.4.0
14
15
  */
15
16
  export interface DashboardDetailFormInputComponent {
@@ -37,6 +38,7 @@ export interface DashboardDetailFormInputComponent {
37
38
  * The pageId is already defined in the detail form extension, so only the blockId and field are needed.
38
39
  *
39
40
  * @docsCategory extensions
41
+ * @docsPage DetailForms
40
42
  * @since 3.4.0
41
43
  */
42
44
  export interface DashboardDetailFormDisplayComponent {
@@ -58,6 +60,15 @@ export interface DashboardDetailFormDisplayComponent {
58
60
  component: DataDisplayComponent;
59
61
  }
60
62
 
63
+ /**
64
+ * @description
65
+ * Allows you to extend existing detail forms (e.g. on the product detail or customer detail pages)
66
+ * with custom GraphQL queries, input components, and display components.
67
+ *
68
+ * @since 3.4.0
69
+ * @docsPage DetailForms
70
+ * @docsCategory extensions
71
+ */
61
72
  export interface DashboardDetailFormExtensionDefinition {
62
73
  /**
63
74
  * @description
@@ -66,6 +77,8 @@ export interface DashboardDetailFormExtensionDefinition {
66
77
  pageId: string;
67
78
  /**
68
79
  * @description
80
+ * Extends the GraphQL query used to fetch data for the detail page, allowing you to add additional
81
+ * fields that can be used by custom input or display components.
69
82
  */
70
83
  extendDetailDocument?: string | DocumentNode | (() => DocumentNode | string);
71
84
  /**
@@ -7,10 +7,20 @@ import { CustomFormComponentInputProps } from '../../form-engine/custom-form-com
7
7
  * Allows you to define custom form components for custom fields in the dashboard.
8
8
  *
9
9
  * @docsCategory extensions
10
+ * @docsPage FormComponents
10
11
  * @since 3.4.0
11
12
  */
12
13
  export interface DashboardCustomFormComponent {
14
+ /**
15
+ * @description
16
+ * A unique identifier for the custom form component. It is a good practice to namespace
17
+ * these IDs to avoid naming collisions, for example `"my-plugin.markdown-editor"`.
18
+ */
13
19
  id: string;
20
+ /**
21
+ * @description
22
+ * The React component that will be rendered as the custom form input.
23
+ */
14
24
  component: React.FunctionComponent<CustomFormComponentInputProps>;
15
25
  }
16
26
 
@@ -20,6 +30,7 @@ export interface DashboardCustomFormComponent {
20
30
  * For input and display components, use the co-located approach with detailForms.
21
31
  *
22
32
  * @docsCategory extensions
33
+ * @docsPage FormComponents
23
34
  * @since 3.4.0
24
35
  */
25
36
  export interface DashboardCustomFormComponents {
@@ -4,5 +4,6 @@ export * from './data-table.js';
4
4
  export * from './detail-forms.js';
5
5
  export * from './form-components.js';
6
6
  export * from './layout.js';
7
+ export * from './login.js';
7
8
  export * from './navigation.js';
8
9
  export * from './widgets.js';
@@ -9,11 +9,10 @@ export interface ActionBarButtonState {
9
9
 
10
10
  /**
11
11
  * @description
12
- * **Status: Developer Preview**
13
- *
14
12
  * Allows you to define custom action bar items for any page in the dashboard.
15
13
  *
16
14
  * @docsCategory extensions
15
+ * @docsPage Layout
17
16
  * @since 3.3.0
18
17
  */
19
18
  export interface DashboardActionBarItem {
@@ -59,13 +58,12 @@ export type PageBlockPosition = { blockId: string; order: 'before' | 'after' | '
59
58
 
60
59
  /**
61
60
  * @description
62
- * **Status: Developer Preview**
63
- *
64
61
  * The location of a page block in the dashboard. The location can be found by turning on
65
62
  * "developer mode" in the dashboard user menu (bottom left corner) and then
66
63
  * clicking the `< />` icon when hovering over a page block.
67
64
  *
68
65
  * @docsCategory extensions
66
+ * @docsPage Layout
69
67
  * @since 3.3.0
70
68
  */
71
69
  export type PageBlockLocation = {
@@ -76,12 +74,11 @@ export type PageBlockLocation = {
76
74
 
77
75
  /**
78
76
  * @description
79
- * **Status: Developer Preview**
80
- *
81
77
  * This allows you to insert a custom component into a specific location
82
78
  * on any page in the dashboard.
83
79
  *
84
80
  * @docsCategory extensions
81
+ * @docsPage Layout
85
82
  * @since 3.3.0
86
83
  */
87
84
  export interface DashboardPageBlockDefinition {
@@ -0,0 +1,96 @@
1
+ import type React from 'react';
2
+
3
+ /**
4
+ * @description
5
+ * Defines a custom logo component for the login page.
6
+ *
7
+ * @docsCategory extensions
8
+ * @docsPage Login
9
+ * @since 3.4.0
10
+ */
11
+ export interface LoginLogoExtension {
12
+ /**
13
+ * @description
14
+ * A React component that will replace the default Vendure logo.
15
+ */
16
+ component: React.ComponentType;
17
+ }
18
+
19
+ /**
20
+ * @description
21
+ * Defines content to display before the login form.
22
+ *
23
+ * @docsCategory extensions
24
+ * @docsPage Login
25
+ * @since 3.4.0
26
+ */
27
+ export interface LoginBeforeFormExtension {
28
+ /**
29
+ * @description
30
+ * A React component that will be rendered before the login form.
31
+ */
32
+ component: React.ComponentType;
33
+ }
34
+
35
+ /**
36
+ * @description
37
+ * Defines content to display after the login form.
38
+ *
39
+ * @docsCategory extensions
40
+ * @docsPage Login
41
+ * @since 3.4.0
42
+ */
43
+ export interface LoginAfterFormExtension {
44
+ /**
45
+ * @description
46
+ * A React component that will be rendered after the login form.
47
+ */
48
+ component: React.ComponentType;
49
+ }
50
+
51
+ /**
52
+ * @description
53
+ * Defines a custom login image component that replaces the default image panel.
54
+ *
55
+ * @docsCategory extensions
56
+ * @docsPage Login
57
+ * @since 3.4.0
58
+ */
59
+ export interface LoginImageExtension {
60
+ /**
61
+ * @description
62
+ * A React component that will replace the default login image panel.
63
+ */
64
+ component: React.ComponentType;
65
+ }
66
+
67
+ /**
68
+ * @description
69
+ * Defines all available login page extensions.
70
+ *
71
+ * @docsCategory extensions
72
+ * @docsPage Login
73
+ * @since 3.4.0
74
+ */
75
+ export interface DashboardLoginExtensions {
76
+ /**
77
+ * @description
78
+ * Custom logo component to replace the default Vendure logo.
79
+ */
80
+ logo?: LoginLogoExtension;
81
+ /**
82
+ * @description
83
+ * Component to render before the login form.
84
+ */
85
+ beforeForm?: LoginBeforeFormExtension;
86
+ /**
87
+ * @description
88
+ * Component to render after the login form.
89
+ */
90
+ afterForm?: LoginAfterFormExtension;
91
+ /**
92
+ * @description
93
+ * Custom login image component to replace the default image panel.
94
+ */
95
+ loginImage?: LoginImageExtension;
96
+ }
@@ -4,16 +4,73 @@ import type React from 'react';
4
4
 
5
5
  import { NavMenuItem } from '../../nav-menu/nav-menu-extensions.js';
6
6
 
7
+ /**
8
+ * @description
9
+ * Defines a custom route for the dashboard with optional navigation menu integration.
10
+ *
11
+ * @docsCategory extensions
12
+ * @docsPage Navigation
13
+ * @since 3.4.0
14
+ */
7
15
  export interface DashboardRouteDefinition {
16
+ /**
17
+ * @description
18
+ * The React component that will be rendered for this route.
19
+ */
8
20
  component: (route: AnyRoute) => React.ReactNode;
21
+ /**
22
+ * @description
23
+ * The URL path for this route, e.g. '/my-custom-page'.
24
+ */
9
25
  path: string;
26
+ /**
27
+ * @description
28
+ * Optional navigation menu item configuration to add this route to the nav menu
29
+ * on the left side of the dashboard.
30
+ */
10
31
  navMenuItem?: Partial<NavMenuItem> & { sectionId: string };
32
+ /**
33
+ * @description
34
+ * Optional loader function to fetch data before the route renders.
35
+ * The value is a Tanstack Router
36
+ * [loader function](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#route-loaders)
37
+ */
11
38
  loader?: RouteOptions['loader'];
12
39
  }
13
40
 
41
+ /**
42
+ * @description
43
+ * Defines a custom navigation section in the dashboard sidebar.
44
+ *
45
+ * @docsCategory extensions
46
+ * @docsPage Navigation
47
+ * @since 3.4.0
48
+ */
14
49
  export interface DashboardNavSectionDefinition {
50
+ /**
51
+ * @description
52
+ * A unique identifier for the navigation section.
53
+ */
15
54
  id: string;
55
+ /**
56
+ * @description
57
+ * The display title for the navigation section.
58
+ */
16
59
  title: string;
60
+ /**
61
+ * @description
62
+ * Optional icon to display next to the section title. The icons should
63
+ * be imported from `'lucide-react'`.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * import { PlusIcon } from 'lucide-react';
68
+ * ```
69
+ */
17
70
  icon?: LucideIcon;
71
+ /**
72
+ * @description
73
+ * Optional order number to control the position of this section in the sidebar.
74
+ */
18
75
  order?: number;
19
76
  }
@@ -2,8 +2,6 @@ import React, { PropsWithChildren } from 'react';
2
2
 
3
3
  /**
4
4
  * @description
5
- * **Status: Developer Preview**
6
- *
7
5
  * Base props interface for dashboard widgets.
8
6
  *
9
7
  * @docsCategory extensions
@@ -19,8 +17,6 @@ export type DashboardBaseWidgetProps = PropsWithChildren<{
19
17
 
20
18
  /**
21
19
  * @description
22
- * **Status: Developer Preview**
23
- *
24
20
  * Represents an instance of a dashboard widget with its layout and configuration.
25
21
  *
26
22
  * @docsCategory extensions
@@ -0,0 +1,26 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ import { globalRegistry } from '../registry/global-registry.js';
4
+
5
+ import { onExtensionSourceChange } from './define-dashboard-extension.js';
6
+ import { DashboardLoginExtensions } from './types/login.js';
7
+
8
+ export function useLoginExtensions(): DashboardLoginExtensions {
9
+ const [extensions, setExtensions] = useState<DashboardLoginExtensions>(() => {
10
+ return globalRegistry.get('loginExtensions') || {};
11
+ });
12
+
13
+ useEffect(() => {
14
+ const updateExtensions = () => {
15
+ setExtensions(globalRegistry.get('loginExtensions') || {});
16
+ };
17
+
18
+ // Subscribe to extension changes
19
+ onExtensionSourceChange(updateExtensions);
20
+
21
+ // Update immediately in case extensions were registered before this hook was called
22
+ updateExtensions();
23
+ }, []);
24
+
25
+ return extensions;
26
+ }
@@ -0,0 +1,24 @@
1
+ import { Button } from '@/vdb/components/ui/button.js';
2
+ import { cn } from '@/vdb/lib/utils.js';
3
+ import { CodeXmlIcon } from 'lucide-react';
4
+ import { forwardRef } from 'react';
5
+
6
+ export const DevModeButton = forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
7
+ (props, ref) => {
8
+ const { className, ...rest } = props;
9
+ return (
10
+ <Button
11
+ ref={ref}
12
+ variant="secondary"
13
+ size="icon"
14
+ className={cn(
15
+ 'h-8 w-8 rounded-full bg-dev-mode/20 hover:bg-dev-mode/30 border border-dev-mode/20 shadow-sm',
16
+ className,
17
+ )}
18
+ {...rest}
19
+ >
20
+ <CodeXmlIcon className="text-dev-mode w-4 h-4" />
21
+ </Button>
22
+ );
23
+ },
24
+ );
@@ -1,12 +1,11 @@
1
1
  import { CopyableText } from '@/vdb/components/shared/copyable-text.js';
2
- import { Button } from '@/vdb/components/ui/button.js';
3
2
  import { Popover, PopoverContent, PopoverTrigger } from '@/vdb/components/ui/popover.js';
4
3
  import { usePageBlock } from '@/vdb/hooks/use-page-block.js';
5
4
  import { usePage } from '@/vdb/hooks/use-page.js';
6
5
  import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
7
6
  import { cn } from '@/vdb/lib/utils.js';
8
- import { CodeXmlIcon } from 'lucide-react';
9
7
  import React, { useEffect, useState } from 'react';
8
+ import { DevModeButton } from './dev-mode-button.js';
10
9
 
11
10
  // Singleton state for hover tracking
12
11
  let globalHoveredId: string | null = null;
@@ -74,10 +73,10 @@ export function LocationWrapper({ children, identifier }: Readonly<LocationWrapp
74
73
  return (
75
74
  <div
76
75
  className={cn(
77
- `ring-2 transition-all delay-50 relative`,
76
+ `ring-2 transition-all ring-offset-4 ring-offset-background delay-50 relative`,
78
77
  isHovered || isPopoverOpen ? 'ring-dev-mode' : 'ring-transparent',
79
- isPageWrapper ? 'ring-inset' : '',
80
- identifier ? 'rounded-md' : 'rounded-xl',
78
+ isPageWrapper ? 'ring-offset-8' : '',
79
+ identifier ? 'rounded-md' : 'rounded',
81
80
  )}
82
81
  onMouseEnter={handleMouseEnter}
83
82
  onMouseLeave={handleMouseLeave}
@@ -87,13 +86,7 @@ export function LocationWrapper({ children, identifier }: Readonly<LocationWrapp
87
86
  >
88
87
  <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
89
88
  <PopoverTrigger asChild>
90
- <Button
91
- variant="secondary"
92
- size="icon"
93
- className="h-8 w-8 rounded-full bg-dev-mode/10 hover:bg-dev-mode/20 border border-dev-mode/20 shadow-sm"
94
- >
95
- <CodeXmlIcon className="text-dev-mode w-4 h-4" />
96
- </Button>
89
+ <DevModeButton />
97
90
  </PopoverTrigger>
98
91
  <PopoverContent className="w-48 p-3">
99
92
  <div className="space-y-2">
@@ -36,6 +36,10 @@ class GlobalRegistry {
36
36
  const oldValue = this.get(key);
37
37
  this.registry.set(key, updater(oldValue));
38
38
  }
39
+
40
+ public has(key: string): boolean {
41
+ return this.registry.has(key);
42
+ }
39
43
  }
40
44
 
41
45
  export type GlobalRegistryKey = keyof GlobalRegistryContents;
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  BulkAction,
3
3
  DashboardActionBarItem,
4
+ DashboardLoginExtensions,
4
5
  DashboardPageBlockDefinition,
5
6
  DashboardWidgetDefinition,
6
7
  } from '@/vdb/framework/extension-api/types/index.js';
@@ -26,4 +27,5 @@ export interface GlobalRegistryContents {
26
27
  bulkActionsRegistry: Map<string, BulkAction[]>;
27
28
  listQueryDocumentRegistry: Map<string, DocumentNode[]>;
28
29
  detailQueryDocumentRegistry: Map<string, DocumentNode[]>;
30
+ loginExtensions: DashboardLoginExtensions;
29
31
  }
@@ -3,7 +3,10 @@ import { AwesomeGraphQLClient } from 'awesome-graphql-client';
3
3
  import { DocumentNode, print } from 'graphql';
4
4
  import { uiConfig } from 'virtual:vendure-ui-config';
5
5
 
6
- const API_URL = uiConfig.apiHost + (uiConfig.apiPort !== 'auto' ? `:${uiConfig.apiPort}` : '') + '/admin-api';
6
+ const API_URL =
7
+ uiConfig.api.host +
8
+ (uiConfig.api.port !== 'auto' ? `:${uiConfig.api.port}` : '') +
9
+ `/${uiConfig.api.adminApiPath}`;
7
10
 
8
11
  export type Variables = object;
9
12
  export type RequestDocument = string | DocumentNode;
@@ -16,10 +19,29 @@ const awesomeClient = new AwesomeGraphQLClient({
16
19
  const headers = new Headers(options.headers);
17
20
 
18
21
  if (channelToken) {
19
- headers.set('vendure-token', channelToken);
22
+ headers.set(uiConfig.api.channelTokenKey, channelToken);
20
23
  }
21
24
 
22
- return fetch(url, {
25
+ // Get the content language from user settings and add as query parameter
26
+ let finalUrl = url;
27
+ try {
28
+ const userSettings = localStorage.getItem('vendure-user-settings');
29
+ if (userSettings) {
30
+ const settings = JSON.parse(userSettings);
31
+ const contentLanguage = settings.contentLanguage;
32
+
33
+ if (contentLanguage) {
34
+ const urlObj = new URL(finalUrl);
35
+ urlObj.searchParams.set('languageCode', contentLanguage);
36
+ finalUrl = urlObj.toString();
37
+ }
38
+ }
39
+ } catch (error) {
40
+ // eslint-disable-next-line no-console
41
+ console.warn('Failed to read content language from user settings:', error);
42
+ }
43
+
44
+ return fetch(finalUrl, {
23
45
  ...options,
24
46
  headers,
25
47
  credentials: 'include',