@vendure/dashboard 3.3.6-master-202507010731 → 3.3.6-master-202507011151
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 +131 -131
- package/src/app/common/duplicate-bulk-action.tsx +134 -0
- package/src/app/routes/_authenticated/_collections/collections.graphql.ts +9 -0
- package/src/app/routes/_authenticated/_collections/collections.tsx +10 -0
- package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +66 -6
- package/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx +4 -5
- package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +19 -106
- package/src/app/routes/_authenticated/_products/products.graphql.ts +0 -17
- package/src/lib/components/shared/custom-fields-form.tsx +18 -1
- package/src/lib/components/shared/detail-page-button.tsx +1 -1
- package/src/lib/framework/extension-api/use-dashboard-extensions.ts +2 -1
- package/src/lib/framework/form-engine/use-generated-form.tsx +5 -8
- package/src/lib/framework/form-engine/utils.ts +43 -15
- package/src/lib/framework/page/use-detail-page.ts +4 -4
- package/src/lib/framework/page/use-extended-router.tsx +4 -5
- package/src/lib/graphql/common-operations.ts +18 -0
- package/src/lib/graphql/{fragments.tsx → fragments.ts} +1 -2
- package/src/lib/graphql/graphql-env.d.ts +3 -3
- package/src/lib/hooks/use-channel.ts +2 -1
- package/src/lib/hooks/use-extended-detail-query.ts +2 -1
- package/src/lib/hooks/use-extended-list-query.ts +3 -2
- package/src/lib/hooks/use-grouped-permissions.ts +4 -2
- package/src/lib/hooks/use-page-block.tsx +1 -1
- package/src/lib/hooks/use-page.tsx +2 -2
- package/src/lib/hooks/use-permissions.ts +3 -2
- package/src/lib/hooks/use-server-config.ts +2 -1
- package/src/lib/hooks/use-theme.ts +2 -1
- package/src/lib/providers/auth.tsx +34 -11
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { api } from '@/graphql/api.js';
|
|
2
|
-
import {
|
|
2
|
+
import { graphql, ResultOf } from '@/graphql/graphql.js';
|
|
3
3
|
import { useUserSettings } from '@/hooks/use-user-settings.js';
|
|
4
4
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
5
5
|
import * as React from 'react';
|
|
@@ -14,7 +14,7 @@ import * as React from 'react';
|
|
|
14
14
|
* @since 3.3.0
|
|
15
15
|
*/
|
|
16
16
|
export interface AuthContext {
|
|
17
|
-
status: 'authenticated' | 'verifying' | 'unauthenticated';
|
|
17
|
+
status: 'initial' | 'authenticated' | 'verifying' | 'unauthenticated';
|
|
18
18
|
authenticationError?: string;
|
|
19
19
|
isAuthenticated: boolean;
|
|
20
20
|
login: (username: string, password: string, onSuccess?: () => void) => void;
|
|
@@ -71,8 +71,9 @@ const CurrentUserQuery = graphql(`
|
|
|
71
71
|
export const AuthContext = React.createContext<AuthContext | null>(null);
|
|
72
72
|
|
|
73
73
|
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
74
|
-
const [status, setStatus] = React.useState<AuthContext['status']>('
|
|
74
|
+
const [status, setStatus] = React.useState<AuthContext['status']>('initial');
|
|
75
75
|
const [authenticationError, setAuthenticationError] = React.useState<string | undefined>();
|
|
76
|
+
const [isLoginLogoutInProgress, setIsLoginLogoutInProgress] = React.useState(false);
|
|
76
77
|
const { settings, setActiveChannelId } = useUserSettings();
|
|
77
78
|
const queryClient = useQueryClient();
|
|
78
79
|
|
|
@@ -84,7 +85,10 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
|
84
85
|
refetch: refetchCurrentUser,
|
|
85
86
|
} = useQuery({
|
|
86
87
|
queryKey: ['currentUser'],
|
|
87
|
-
queryFn: () =>
|
|
88
|
+
queryFn: () => {
|
|
89
|
+
return api.query(CurrentUserQuery);
|
|
90
|
+
},
|
|
91
|
+
retry: false, // Disable retries to avoid waiting for multiple attempts
|
|
88
92
|
});
|
|
89
93
|
|
|
90
94
|
// Set active channel if needed
|
|
@@ -97,6 +101,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
|
97
101
|
// Auth actions
|
|
98
102
|
const login = React.useCallback(
|
|
99
103
|
(username: string, password: string, onLoginSuccess?: () => void) => {
|
|
104
|
+
setIsLoginLogoutInProgress(true);
|
|
100
105
|
setStatus('verifying');
|
|
101
106
|
api.mutate(LoginMutation)({ username, password })
|
|
102
107
|
.then(async data => {
|
|
@@ -106,15 +111,18 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
|
106
111
|
// Invalidate all queries to ensure fresh data after login
|
|
107
112
|
await queryClient.invalidateQueries();
|
|
108
113
|
setStatus('authenticated');
|
|
114
|
+
setIsLoginLogoutInProgress(false);
|
|
109
115
|
onLoginSuccess?.();
|
|
110
116
|
} else {
|
|
111
117
|
setAuthenticationError(data?.login.message);
|
|
112
118
|
setStatus('unauthenticated');
|
|
119
|
+
setIsLoginLogoutInProgress(false);
|
|
113
120
|
}
|
|
114
121
|
})
|
|
115
122
|
.catch(error => {
|
|
116
123
|
setAuthenticationError(error.message);
|
|
117
124
|
setStatus('unauthenticated');
|
|
125
|
+
setIsLoginLogoutInProgress(false);
|
|
118
126
|
});
|
|
119
127
|
},
|
|
120
128
|
[refetchCurrentUser, queryClient],
|
|
@@ -122,6 +130,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
|
122
130
|
|
|
123
131
|
const logout = React.useCallback(
|
|
124
132
|
async (onLogoutSuccess?: () => void) => {
|
|
133
|
+
setIsLoginLogoutInProgress(true);
|
|
125
134
|
setStatus('verifying');
|
|
126
135
|
api.mutate(LogOutMutation)({}).then(async data => {
|
|
127
136
|
if (data?.logout.success) {
|
|
@@ -131,6 +140,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
|
131
140
|
localStorage.removeItem('vendure-selected-channel');
|
|
132
141
|
localStorage.removeItem('vendure-selected-channel-token');
|
|
133
142
|
setStatus('unauthenticated');
|
|
143
|
+
setIsLoginLogoutInProgress(false);
|
|
134
144
|
onLogoutSuccess?.();
|
|
135
145
|
}
|
|
136
146
|
});
|
|
@@ -141,15 +151,28 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
|
141
151
|
// Determine isAuthenticated from currentUserData
|
|
142
152
|
const isAuthenticated = !!currentUserData?.me?.id;
|
|
143
153
|
|
|
144
|
-
//
|
|
154
|
+
// Handle status transitions based on query state
|
|
145
155
|
React.useEffect(() => {
|
|
146
|
-
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
156
|
+
// Don't change status if we're in the middle of login/logout
|
|
157
|
+
if (isLoginLogoutInProgress) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If query is loading and we haven't started verifying yet, set to verifying
|
|
162
|
+
if (isLoading && status === 'initial') {
|
|
163
|
+
setStatus('verifying');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// If query has completed (not loading) and we're in verifying state, determine final status
|
|
168
|
+
if (!isLoading && status === 'verifying') {
|
|
169
|
+
if (currentUserError || !currentUserData?.me?.id) {
|
|
170
|
+
setStatus('unauthenticated');
|
|
171
|
+
} else {
|
|
172
|
+
setStatus('authenticated');
|
|
173
|
+
}
|
|
151
174
|
}
|
|
152
|
-
}, [currentUserData, currentUserError]);
|
|
175
|
+
}, [isLoading, currentUserData, currentUserError, status, isLoginLogoutInProgress]);
|
|
153
176
|
|
|
154
177
|
return (
|
|
155
178
|
<AuthContext.Provider
|