@vendure/dashboard 3.5.0-minor-202510012036 → 3.5.0-minor-202510071456
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/dashboard.plugin.d.ts +25 -6
- package/dist/plugin/dashboard.plugin.js +184 -27
- package/dist/plugin/default-page.html +188 -0
- package/dist/vite/utils/tsconfig-utils.js +2 -1
- package/package.json +10 -9
- package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +4 -8
- package/src/app/routes/_authenticated/_global-settings/utils/global-languages.ts +268 -0
- package/src/app/routes/_authenticated/_orders/components/order-address.tsx +15 -15
- package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +4 -4
- package/src/app/routes/_authenticated/_product-variants/components/add-currency-dropdown.tsx +49 -0
- package/src/app/routes/_authenticated/_product-variants/components/add-stock-location-dropdown.tsx +56 -0
- package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +12 -0
- package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +178 -50
- package/src/app/routes/_authenticated/_products/components/product-variants-table.tsx +0 -11
- package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +3 -14
- package/src/app/routes/_authenticated/_shipping-methods/components/test-address-form.tsx +13 -12
- package/src/app/routes/_authenticated/_shipping-methods/components/test-order-builder.tsx +3 -2
- package/src/lib/components/data-input/customer-group-input.tsx +0 -1
- package/src/lib/components/data-input/money-input.tsx +7 -11
- package/src/lib/components/data-input/number-input.tsx +6 -1
- package/src/lib/components/data-table/data-table-filter-badge.tsx +15 -8
- package/src/lib/components/data-table/data-table.tsx +2 -2
- package/src/lib/components/data-table/my-views-button.tsx +12 -12
- package/src/lib/components/data-table/save-view-button.tsx +5 -1
- package/src/lib/components/layout/generated-breadcrumbs.tsx +4 -12
- package/src/lib/components/shared/configurable-operation-input.tsx +1 -1
- package/src/lib/constants.ts +10 -0
- package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +0 -2
- package/src/lib/framework/extension-api/types/layout.ts +41 -1
- package/src/lib/framework/form-engine/value-transformers.ts +8 -1
- package/src/lib/framework/layout-engine/page-layout.tsx +58 -48
- package/src/lib/framework/page/detail-page.tsx +12 -15
- package/src/lib/graphql/api.ts +17 -4
- package/src/lib/graphql/graphql-env.d.ts +29 -50
- package/src/lib/hooks/use-saved-views.ts +7 -0
- package/src/lib/providers/auth.tsx +2 -2
- package/src/lib/providers/channel-provider.tsx +4 -2
- package/src/lib/providers/user-settings.tsx +46 -5
|
@@ -7,9 +7,8 @@ import {
|
|
|
7
7
|
} from '@/vdb/components/ui/breadcrumb.js';
|
|
8
8
|
import type { NavMenuItem, NavMenuSection } from '@/vdb/framework/nav-menu/nav-menu-extensions.js';
|
|
9
9
|
import { getNavMenuConfig } from '@/vdb/framework/nav-menu/nav-menu-extensions.js';
|
|
10
|
-
import { useDisplayLocale } from '@/vdb/hooks/use-display-locale.js';
|
|
11
10
|
import { useLingui } from '@lingui/react';
|
|
12
|
-
import { Link,
|
|
11
|
+
import { Link, useRouterState } from '@tanstack/react-router';
|
|
13
12
|
import * as React from 'react';
|
|
14
13
|
import { Fragment } from 'react';
|
|
15
14
|
|
|
@@ -25,11 +24,8 @@ export type PageBreadcrumb = BreadcrumbPair | BreadcrumbShorthand;
|
|
|
25
24
|
export function GeneratedBreadcrumbs() {
|
|
26
25
|
const matches = useRouterState({ select: s => s.matches });
|
|
27
26
|
const currentPath = useRouterState({ select: s => s.location.pathname });
|
|
28
|
-
const router = useRouter();
|
|
29
27
|
const { i18n } = useLingui();
|
|
30
28
|
const navMenuConfig = getNavMenuConfig();
|
|
31
|
-
const { bcp47Tag } = useDisplayLocale();
|
|
32
|
-
const basePath = router.basepath || '';
|
|
33
29
|
|
|
34
30
|
const normalizeBreadcrumb = (breadcrumb: any, pathname: string): BreadcrumbPair[] => {
|
|
35
31
|
if (typeof breadcrumb === 'string') {
|
|
@@ -58,12 +54,11 @@ export function GeneratedBreadcrumbs() {
|
|
|
58
54
|
.flatMap(({ pathname, loaderData }) => normalizeBreadcrumb(loaderData.breadcrumb, pathname));
|
|
59
55
|
}, [matches]);
|
|
60
56
|
|
|
61
|
-
const isBaseRoute = (p: string) => p ===
|
|
57
|
+
const isBaseRoute = (p: string) => p === '' || p === `/`;
|
|
62
58
|
const pageCrumbs: BreadcrumbPair[] = rawCrumbs.filter(c => !isBaseRoute(c.path));
|
|
63
59
|
|
|
64
60
|
const normalizePath = (path: string): string => {
|
|
65
|
-
|
|
66
|
-
return normalizedPath.startsWith('/') ? normalizedPath : `/${normalizedPath}`;
|
|
61
|
+
return path.startsWith('/') ? path : `/${path}`;
|
|
67
62
|
};
|
|
68
63
|
|
|
69
64
|
const pathMatches = (cleanPath: string, rawUrl?: string): boolean => {
|
|
@@ -115,10 +110,7 @@ export function GeneratedBreadcrumbs() {
|
|
|
115
110
|
return undefined;
|
|
116
111
|
};
|
|
117
112
|
|
|
118
|
-
const sectionCrumb = React.useMemo(
|
|
119
|
-
() => findSectionCrumb(currentPath),
|
|
120
|
-
[currentPath, basePath, navMenuConfig],
|
|
121
|
-
);
|
|
113
|
+
const sectionCrumb = React.useMemo(() => findSectionCrumb(currentPath), [currentPath, navMenuConfig]);
|
|
122
114
|
const breadcrumbs: BreadcrumbPair[] = React.useMemo(() => {
|
|
123
115
|
const arr = sectionCrumb ? [sectionCrumb, ...pageCrumbs] : pageCrumbs;
|
|
124
116
|
return arr.filter(
|
|
@@ -144,7 +144,7 @@ export function interpolateDescription(
|
|
|
144
144
|
(substring: string, argName: string) => {
|
|
145
145
|
const normalizedArgName = argName.toLowerCase();
|
|
146
146
|
const value = values.find(v => v.name === normalizedArgName)?.value;
|
|
147
|
-
if (value == null) {
|
|
147
|
+
if (value == null || value === '') {
|
|
148
148
|
return '_';
|
|
149
149
|
}
|
|
150
150
|
let formatted = value;
|
package/src/lib/constants.ts
CHANGED
|
@@ -3,6 +3,16 @@ export const AUTHENTICATED_ROUTE_PREFIX = '/_authenticated';
|
|
|
3
3
|
export const DEFAULT_CHANNEL_CODE = '__default_channel__';
|
|
4
4
|
export const SUPER_ADMIN_ROLE_CODE = '__super_admin_role__';
|
|
5
5
|
export const CUSTOMER_ROLE_CODE = '__customer_role__';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Local storage keys
|
|
9
|
+
*/
|
|
10
|
+
export const LS_KEY_SESSION_TOKEN = 'vendure-session-token';
|
|
11
|
+
export const LS_KEY_USER_SETTINGS = 'vendure-user-settings';
|
|
12
|
+
export const LS_KEY_SELECTED_CHANNEL_TOKEN = 'vendure-selected-channel-token';
|
|
13
|
+
export const LS_KEY_SHIPPING_TEST_ORDER = 'vendure-shipping-test-order';
|
|
14
|
+
export const LS_KEY_SHIPPING_TEST_ADDRESS = 'vendure-shipping-test-address';
|
|
15
|
+
|
|
6
16
|
/**
|
|
7
17
|
* This is copied from the generated types from @vendure/common/lib/generated-types.d.ts
|
|
8
18
|
* It is used to provide a list of available currency codes for the user to select from.
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
OrderStateCell,
|
|
6
6
|
} from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
|
|
7
7
|
import { Button } from '@/vdb/components/ui/button.js';
|
|
8
|
-
import { useLocalFormat } from '@/vdb/hooks/use-local-format.js';
|
|
9
8
|
import { useLingui } from '@lingui/react/macro';
|
|
10
9
|
import { Link } from '@tanstack/react-router';
|
|
11
10
|
import { ColumnFiltersState, SortingState } from '@tanstack/react-table';
|
|
@@ -39,7 +38,6 @@ export function LatestOrdersWidget() {
|
|
|
39
38
|
},
|
|
40
39
|
},
|
|
41
40
|
]);
|
|
42
|
-
const { formatCurrency } = useLocalFormat();
|
|
43
41
|
|
|
44
42
|
// Update filters when date range changes
|
|
45
43
|
useEffect(() => {
|
|
@@ -93,9 +93,49 @@ export type PageBlockLocation = {
|
|
|
93
93
|
* @since 3.3.0
|
|
94
94
|
*/
|
|
95
95
|
export interface DashboardPageBlockDefinition {
|
|
96
|
+
/**
|
|
97
|
+
* @description
|
|
98
|
+
* An ID for the page block. Should be unique at least
|
|
99
|
+
* to the page in which it appears.
|
|
100
|
+
*/
|
|
96
101
|
id: string;
|
|
102
|
+
/**
|
|
103
|
+
* @description
|
|
104
|
+
* An optional title for the page block
|
|
105
|
+
*/
|
|
97
106
|
title?: React.ReactNode;
|
|
107
|
+
/**
|
|
108
|
+
* @description
|
|
109
|
+
* The location of the page block. It specifies the pageId, and then the
|
|
110
|
+
* relative location compared to another existing block.
|
|
111
|
+
*/
|
|
98
112
|
location: PageBlockLocation;
|
|
99
|
-
|
|
113
|
+
/**
|
|
114
|
+
* @description
|
|
115
|
+
* The component to be rendered inside the page block.
|
|
116
|
+
*/
|
|
117
|
+
component?: React.FunctionComponent<{ context: PageContextValue }>;
|
|
118
|
+
/**
|
|
119
|
+
* @description
|
|
120
|
+
* Control whether to render the page block depending on your custom
|
|
121
|
+
* logic.
|
|
122
|
+
*
|
|
123
|
+
* This can also be used to disable any built-in blocks you
|
|
124
|
+
* do not need to display.
|
|
125
|
+
*
|
|
126
|
+
* If you need to query aspects about the current context not immediately
|
|
127
|
+
* provided in the `PageContextValue`, you can also use hooks such as
|
|
128
|
+
* `useChannel` in this function.
|
|
129
|
+
*
|
|
130
|
+
* @since 3.5.0
|
|
131
|
+
*/
|
|
132
|
+
shouldRender?: (context: PageContextValue) => boolean;
|
|
133
|
+
/**
|
|
134
|
+
* @description
|
|
135
|
+
* If provided, the logged-in user must have one or more of the specified
|
|
136
|
+
* permissions in order for the block to render.
|
|
137
|
+
*
|
|
138
|
+
* For more advanced control over rendering, use the `shouldRender` function.
|
|
139
|
+
*/
|
|
100
140
|
requiresPermission?: string | string[];
|
|
101
141
|
}
|
|
@@ -29,9 +29,16 @@ export const nativeValueTransformer: ValueTransformer = {
|
|
|
29
29
|
*/
|
|
30
30
|
export const jsonStringValueTransformer: ValueTransformer = {
|
|
31
31
|
parse: (value: string, fieldDef: ConfigurableFieldDef) => {
|
|
32
|
-
if (
|
|
32
|
+
if (value === undefined) {
|
|
33
33
|
return getDefaultValue(fieldDef);
|
|
34
34
|
}
|
|
35
|
+
// This case arises often when the administrator is actively editing
|
|
36
|
+
// values and clears out the input. At that point, we don't want to suddenly
|
|
37
|
+
// switch to the default value otherwise it results in poor UX, e.g. pressing
|
|
38
|
+
// backspace to delete a number would result in `0` suddenly appearing as the value.
|
|
39
|
+
if (value === '') {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
35
42
|
|
|
36
43
|
try {
|
|
37
44
|
// For JSON string mode, parse the string to get the native value
|
|
@@ -119,12 +119,12 @@ export function Page({ children, pageId, entity, form, submitHandler, ...props }
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
function PageContent({
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
pageHeader,
|
|
123
|
+
pageContent,
|
|
124
|
+
form,
|
|
125
|
+
submitHandler,
|
|
126
|
+
...props
|
|
127
|
+
}: {
|
|
128
128
|
pageHeader: React.ReactNode;
|
|
129
129
|
pageContent: React.ReactNode;
|
|
130
130
|
form?: UseFormReturn<any>;
|
|
@@ -146,11 +146,11 @@ function PageContent({
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
export function PageContentWithOptionalForm({
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
form,
|
|
150
|
+
pageHeader,
|
|
151
|
+
pageContent,
|
|
152
|
+
submitHandler,
|
|
153
|
+
}: {
|
|
154
154
|
form?: UseFormReturn<any>;
|
|
155
155
|
pageHeader: React.ReactNode;
|
|
156
156
|
pageContent: React.ReactNode;
|
|
@@ -235,22 +235,32 @@ export function PageLayout({ children, className }: Readonly<PageLayoutProps>) {
|
|
|
235
235
|
childBlock.props.blockId ??
|
|
236
236
|
(isOfType(childBlock, CustomFieldsPageBlock) ? 'custom-fields' : undefined);
|
|
237
237
|
const extensionBlock = extensionBlocks.find(block => block.location.position.blockId === blockId);
|
|
238
|
+
|
|
238
239
|
if (extensionBlock) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
240
|
+
let extensionBlockShouldRender = true;
|
|
241
|
+
if (typeof extensionBlock?.shouldRender === 'function') {
|
|
242
|
+
extensionBlockShouldRender = extensionBlock.shouldRender(page);
|
|
243
|
+
}
|
|
244
|
+
const ExtensionBlock =
|
|
245
|
+
extensionBlock.component && extensionBlockShouldRender ? (
|
|
246
|
+
<PageBlock
|
|
247
|
+
key={childBlock.key}
|
|
248
|
+
column={extensionBlock.location.column}
|
|
249
|
+
blockId={extensionBlock.id}
|
|
250
|
+
title={extensionBlock.title}
|
|
251
|
+
>
|
|
252
|
+
{<extensionBlock.component context={page} />}
|
|
253
|
+
</PageBlock>
|
|
254
|
+
) : undefined;
|
|
249
255
|
if (extensionBlock.location.position.order === 'before') {
|
|
250
|
-
finalChildArray.push(ExtensionBlock, childBlock);
|
|
256
|
+
finalChildArray.push(...[ExtensionBlock, childBlock].filter(x => !!x));
|
|
251
257
|
} else if (extensionBlock.location.position.order === 'after') {
|
|
252
|
-
finalChildArray.push(childBlock, ExtensionBlock);
|
|
253
|
-
} else if (
|
|
258
|
+
finalChildArray.push(...[childBlock, ExtensionBlock].filter(x => !!x));
|
|
259
|
+
} else if (
|
|
260
|
+
extensionBlock.location.position.order === 'replace' &&
|
|
261
|
+
extensionBlockShouldRender &&
|
|
262
|
+
ExtensionBlock
|
|
263
|
+
) {
|
|
254
264
|
finalChildArray.push(ExtensionBlock);
|
|
255
265
|
}
|
|
256
266
|
} else {
|
|
@@ -425,9 +435,9 @@ function EntityInfoDropdown({ entity }: Readonly<{ entity: any }>) {
|
|
|
425
435
|
* @since 3.3.0
|
|
426
436
|
*/
|
|
427
437
|
export function PageActionBarRight({
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
438
|
+
children,
|
|
439
|
+
dropdownMenuItems,
|
|
440
|
+
}: Readonly<{
|
|
431
441
|
children: React.ReactNode;
|
|
432
442
|
dropdownMenuItems?: InlineDropdownItem[];
|
|
433
443
|
}>) {
|
|
@@ -458,9 +468,9 @@ export function PageActionBarRight({
|
|
|
458
468
|
}
|
|
459
469
|
|
|
460
470
|
function PageActionBarItem({
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
471
|
+
item,
|
|
472
|
+
page,
|
|
473
|
+
}: Readonly<{ item: DashboardActionBarItem; page: PageContextValue }>) {
|
|
464
474
|
return (
|
|
465
475
|
<PermissionGuard requires={item.requiresPermission ?? []}>
|
|
466
476
|
<item.component context={page} />
|
|
@@ -469,9 +479,9 @@ function PageActionBarItem({
|
|
|
469
479
|
}
|
|
470
480
|
|
|
471
481
|
function PageActionBarDropdown({
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
482
|
+
items,
|
|
483
|
+
page,
|
|
484
|
+
}: Readonly<{ items: DashboardActionBarItem[]; page: PageContextValue }>) {
|
|
475
485
|
return (
|
|
476
486
|
<DropdownMenu>
|
|
477
487
|
<DropdownMenuTrigger asChild>
|
|
@@ -550,13 +560,13 @@ export type PageBlockProps = {
|
|
|
550
560
|
* @since 3.3.0
|
|
551
561
|
*/
|
|
552
562
|
export function PageBlock({
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
563
|
+
children,
|
|
564
|
+
title,
|
|
565
|
+
description,
|
|
566
|
+
className,
|
|
567
|
+
blockId,
|
|
568
|
+
column,
|
|
569
|
+
}: Readonly<PageBlockProps>) {
|
|
560
570
|
const contextValue = useMemo(
|
|
561
571
|
() => ({
|
|
562
572
|
blockId,
|
|
@@ -595,10 +605,10 @@ export function PageBlock({
|
|
|
595
605
|
* @since 3.3.0
|
|
596
606
|
*/
|
|
597
607
|
export function FullWidthPageBlock({
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
608
|
+
children,
|
|
609
|
+
className,
|
|
610
|
+
blockId,
|
|
611
|
+
}: Readonly<Pick<PageBlockProps, 'children' | 'className' | 'blockId'>>) {
|
|
602
612
|
const contextValue = useMemo(() => ({ blockId, column: 'main' as const }), [blockId]);
|
|
603
613
|
return (
|
|
604
614
|
<PageBlockContext.Provider value={contextValue}>
|
|
@@ -625,10 +635,10 @@ export function FullWidthPageBlock({
|
|
|
625
635
|
* @since 3.3.0
|
|
626
636
|
*/
|
|
627
637
|
export function CustomFieldsPageBlock({
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
638
|
+
column,
|
|
639
|
+
entityType,
|
|
640
|
+
control,
|
|
641
|
+
}: Readonly<{
|
|
632
642
|
column: 'main' | 'side';
|
|
633
643
|
entityType: string;
|
|
634
644
|
control: Control<any, any>;
|
|
@@ -5,8 +5,8 @@ import { Checkbox } from '@/vdb/components/ui/checkbox.js';
|
|
|
5
5
|
import { Input } from '@/vdb/components/ui/input.js';
|
|
6
6
|
import { NEW_ENTITY_PATH } from '@/vdb/constants.js';
|
|
7
7
|
import { useDetailPage } from '@/vdb/framework/page/use-detail-page.js';
|
|
8
|
-
import { Trans } from '@lingui/react/macro';
|
|
9
8
|
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
9
|
+
import { Trans } from '@lingui/react/macro';
|
|
10
10
|
import { AnyRoute, useNavigate } from '@tanstack/react-router';
|
|
11
11
|
import { ResultOf, VariablesOf } from 'gql.tada';
|
|
12
12
|
import { toast } from 'sonner';
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
getOperationVariablesFields,
|
|
17
17
|
} from '../document-introspection/get-document-structure.js';
|
|
18
18
|
|
|
19
|
+
import { NumberInput } from '@/vdb/components/data-input/number-input.js';
|
|
19
20
|
import { TranslatableFormFieldWrapper } from '@/vdb/components/shared/translatable-form-field.js';
|
|
20
21
|
import { FormControl } from '@/vdb/components/ui/form.js';
|
|
21
22
|
import { ControllerRenderProps, FieldPath, FieldValues } from 'react-hook-form';
|
|
@@ -108,11 +109,7 @@ function FieldInputRenderer<
|
|
|
108
109
|
case 'Float':
|
|
109
110
|
return (
|
|
110
111
|
<FormControl>
|
|
111
|
-
<
|
|
112
|
-
type="number"
|
|
113
|
-
value={field.value}
|
|
114
|
-
onChange={e => field.onChange(e.target.valueAsNumber)}
|
|
115
|
-
/>
|
|
112
|
+
<NumberInput {...field} />
|
|
116
113
|
</FormControl>
|
|
117
114
|
);
|
|
118
115
|
case 'DateTime':
|
|
@@ -152,15 +149,15 @@ export function DetailPage<
|
|
|
152
149
|
C extends TypedDocumentNode<any, any>,
|
|
153
150
|
U extends TypedDocumentNode<any, any>,
|
|
154
151
|
>({
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
152
|
+
pageId,
|
|
153
|
+
route,
|
|
154
|
+
entityName: passedEntityName,
|
|
155
|
+
queryDocument,
|
|
156
|
+
createDocument,
|
|
157
|
+
updateDocument,
|
|
158
|
+
setValuesForUpdate,
|
|
159
|
+
title,
|
|
160
|
+
}: DetailPageProps<T, C, U>) {
|
|
164
161
|
const params = route.useParams();
|
|
165
162
|
const creatingNewEntity = params.id === NEW_ENTITY_PATH;
|
|
166
163
|
const navigate = useNavigate();
|
package/src/lib/graphql/api.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LS_KEY_SELECTED_CHANNEL_TOKEN,
|
|
3
|
+
LS_KEY_SESSION_TOKEN,
|
|
4
|
+
LS_KEY_USER_SETTINGS,
|
|
5
|
+
} from '@/vdb/constants.js';
|
|
1
6
|
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
2
7
|
import { AwesomeGraphQLClient } from 'awesome-graphql-client';
|
|
3
8
|
import { DocumentNode, print } from 'graphql';
|
|
@@ -12,8 +17,6 @@ const API_URL =
|
|
|
12
17
|
`:${uiConfig.api.port !== 'auto' ? uiConfig.api.port : window.location.port}` +
|
|
13
18
|
`/${uiConfig.api.adminApiPath}`;
|
|
14
19
|
|
|
15
|
-
export const SELECTED_CHANNEL_TOKEN_KEY = 'vendure-selected-channel-token';
|
|
16
|
-
|
|
17
20
|
export type Variables = object;
|
|
18
21
|
export type RequestDocument = string | DocumentNode;
|
|
19
22
|
|
|
@@ -21,9 +24,13 @@ const awesomeClient = new AwesomeGraphQLClient({
|
|
|
21
24
|
endpoint: API_URL,
|
|
22
25
|
fetch: async (url: string, options: RequestInit = {}) => {
|
|
23
26
|
// Get the active channel token from localStorage
|
|
24
|
-
const channelToken = localStorage.getItem(
|
|
27
|
+
const channelToken = localStorage.getItem(LS_KEY_SELECTED_CHANNEL_TOKEN);
|
|
28
|
+
const sessionToken = localStorage.getItem(LS_KEY_SESSION_TOKEN);
|
|
25
29
|
const headers = new Headers(options.headers);
|
|
26
30
|
|
|
31
|
+
if (sessionToken) {
|
|
32
|
+
headers.set('Authorization', `Bearer ${sessionToken}`);
|
|
33
|
+
}
|
|
27
34
|
if (channelToken) {
|
|
28
35
|
headers.set(uiConfig.api.channelTokenKey, channelToken);
|
|
29
36
|
}
|
|
@@ -31,7 +38,7 @@ const awesomeClient = new AwesomeGraphQLClient({
|
|
|
31
38
|
// Get the content language from user settings and add as query parameter
|
|
32
39
|
let finalUrl = url;
|
|
33
40
|
try {
|
|
34
|
-
const userSettings = localStorage.getItem(
|
|
41
|
+
const userSettings = localStorage.getItem(LS_KEY_USER_SETTINGS);
|
|
35
42
|
if (userSettings) {
|
|
36
43
|
const settings = JSON.parse(userSettings);
|
|
37
44
|
const contentLanguage = settings.contentLanguage;
|
|
@@ -52,6 +59,12 @@ const awesomeClient = new AwesomeGraphQLClient({
|
|
|
52
59
|
headers,
|
|
53
60
|
credentials: 'include',
|
|
54
61
|
mode: 'cors',
|
|
62
|
+
}).then(res => {
|
|
63
|
+
const authToken = res.headers.get('vendure-auth-token');
|
|
64
|
+
if (authToken) {
|
|
65
|
+
localStorage.setItem(LS_KEY_SESSION_TOKEN, authToken);
|
|
66
|
+
}
|
|
67
|
+
return res;
|
|
55
68
|
});
|
|
56
69
|
},
|
|
57
70
|
});
|