@apvee/spfx-react-toolkit 1.2.1 → 1.3.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.
- package/lib/extensions/spFxReactToolkitTest/SpFxReactToolkitTestApplicationCustomizer.d.ts +14 -0
- package/lib/extensions/spFxReactToolkitTest/SpFxReactToolkitTestApplicationCustomizer.d.ts.map +1 -0
- package/lib/extensions/spFxReactToolkitTest/SpFxReactToolkitTestApplicationCustomizer.js +41 -0
- package/lib/extensions/spFxReactToolkitTest/SpFxReactToolkitTestApplicationCustomizer.js.map +1 -0
- package/lib/extensions/spFxReactToolkitTest/SpFxReactToolkitTestApplicationCustomizer.manifest.json +17 -0
- package/lib/extensions/spFxReactToolkitTest/loc/en-us.js +5 -0
- package/lib/hooks/useSPFxAadHttpClient.d.ts +46 -0
- package/lib/hooks/useSPFxAadHttpClient.d.ts.map +1 -1
- package/lib/hooks/useSPFxAadHttpClient.js +53 -8
- package/lib/hooks/useSPFxAadHttpClient.js.map +1 -1
- package/lib/hooks/useSPFxHttpClient.d.ts +18 -2
- package/lib/hooks/useSPFxHttpClient.d.ts.map +1 -1
- package/lib/hooks/useSPFxHttpClient.js +12 -2
- package/lib/hooks/useSPFxHttpClient.js.map +1 -1
- package/lib/hooks/useSPFxMSGraphClient.d.ts +50 -3
- package/lib/hooks/useSPFxMSGraphClient.d.ts.map +1 -1
- package/lib/hooks/useSPFxMSGraphClient.js +58 -5
- package/lib/hooks/useSPFxMSGraphClient.js.map +1 -1
- package/lib/hooks/useSPFxOneDriveAppData.d.ts +0 -1
- package/lib/hooks/useSPFxOneDriveAppData.d.ts.map +1 -1
- package/lib/hooks/useSPFxOneDriveAppData.js +352 -101
- package/lib/hooks/useSPFxOneDriveAppData.js.map +1 -1
- package/lib/hooks/useSPFxSPHttpClient.d.ts +18 -2
- package/lib/hooks/useSPFxSPHttpClient.d.ts.map +1 -1
- package/lib/hooks/useSPFxSPHttpClient.js +12 -2
- package/lib/hooks/useSPFxSPHttpClient.js.map +1 -1
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts.map +1 -1
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js +3 -7
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js.map +1 -1
- package/package.json +8 -6
|
@@ -36,73 +36,293 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
36
36
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
|
-
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
39
|
+
import { useState, useCallback, useEffect, useRef, useMemo } from 'react';
|
|
40
40
|
import { useSPFxMSGraphClient } from './useSPFxMSGraphClient';
|
|
41
|
-
|
|
41
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
+
// PURE FUNCTIONS (extracted for stability and testability)
|
|
43
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
44
|
+
/**
|
|
45
|
+
* Build Graph API path with optional folder namespace.
|
|
46
|
+
* Sanitizes folder name to prevent path traversal attacks.
|
|
47
|
+
*
|
|
48
|
+
* @param fileName - Name of the file
|
|
49
|
+
* @param folderName - Optional folder namespace
|
|
50
|
+
* @returns Full Graph API path for file content
|
|
51
|
+
*/
|
|
52
|
+
function buildApiPath(fileName, folderName) {
|
|
53
|
+
var basePath = '/me/drive/special/appRoot:';
|
|
54
|
+
if (folderName) {
|
|
55
|
+
// Sanitize folder name: only allow alphanumeric, hyphens, underscores
|
|
56
|
+
// This prevents path traversal (../) and other injection attacks
|
|
57
|
+
var safeFolderName = folderName.replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
58
|
+
return "".concat(basePath, "/").concat(safeFolderName, "/").concat(fileName, ":/content");
|
|
59
|
+
}
|
|
60
|
+
return "".concat(basePath, "/").concat(fileName, ":/content");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if an error indicates a 404 / itemNotFound response from Graph API.
|
|
64
|
+
*
|
|
65
|
+
* @param err - The error to check
|
|
66
|
+
* @returns True if the error indicates file not found
|
|
67
|
+
*/
|
|
68
|
+
function isNotFoundError(err) {
|
|
69
|
+
var _a, _b, _c, _d, _e, _f;
|
|
70
|
+
var anyErr = err;
|
|
71
|
+
// Check status codes
|
|
72
|
+
if ((anyErr === null || anyErr === void 0 ? void 0 : anyErr.statusCode) === 404 || (anyErr === null || anyErr === void 0 ? void 0 : anyErr.status) === 404)
|
|
73
|
+
return true;
|
|
74
|
+
// Check error codes
|
|
75
|
+
var code = (_a = anyErr === null || anyErr === void 0 ? void 0 : anyErr.code) !== null && _a !== void 0 ? _a : (_c = (_b = anyErr === null || anyErr === void 0 ? void 0 : anyErr.body) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.code;
|
|
76
|
+
if (code && /itemnotfound/i.test(code))
|
|
77
|
+
return true;
|
|
78
|
+
// Check error messages as fallback
|
|
79
|
+
var message = (_d = anyErr === null || anyErr === void 0 ? void 0 : anyErr.message) !== null && _d !== void 0 ? _d : (_f = (_e = anyErr === null || anyErr === void 0 ? void 0 : anyErr.body) === null || _e === void 0 ? void 0 : _e.error) === null || _f === void 0 ? void 0 : _f.message;
|
|
80
|
+
if (message && /(\b404\b|not found|itemnotfound)/i.test(message))
|
|
81
|
+
return true;
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Hook to manage JSON files in user's OneDrive appRoot folder
|
|
86
|
+
*
|
|
87
|
+
* Provides unified read/write operations for JSON data stored in OneDrive's special
|
|
88
|
+
* appRoot folder (accessible per-app, user-scoped storage).
|
|
89
|
+
*
|
|
90
|
+
* Features:
|
|
91
|
+
* - Automatic JSON serialization/deserialization
|
|
92
|
+
* - Separate loading states for read/write operations
|
|
93
|
+
* - Optional auto-fetch on mount
|
|
94
|
+
* - Folder/namespace support for file organization
|
|
95
|
+
* - Type-safe with TypeScript generics
|
|
96
|
+
* - Memory leak safe with mounted state tracking
|
|
97
|
+
* - Error handling for both read and write operations
|
|
98
|
+
*
|
|
99
|
+
* Requirements:
|
|
100
|
+
* - Microsoft Graph permissions: Files.ReadWrite or Files.ReadWrite.AppFolder
|
|
101
|
+
* - User must be authenticated
|
|
102
|
+
*
|
|
103
|
+
* @param fileName - Name of the JSON file (e.g., 'config.json', 'settings.json')
|
|
104
|
+
* @param folder - Optional folder/namespace identifier for file organization.
|
|
105
|
+
* Will be sanitized to prevent path traversal.
|
|
106
|
+
* Examples: 'my-app', instanceId (GUID), 'config-v2'
|
|
107
|
+
* @param autoFetch - Whether to automatically load file on mount. Default: true
|
|
108
|
+
*
|
|
109
|
+
* @returns Object with data, loading states, error states, and read/write functions
|
|
110
|
+
*
|
|
111
|
+
* @example Basic usage - auto-fetch from root
|
|
112
|
+
* ```tsx
|
|
113
|
+
* import type { MyConfig } from './types';
|
|
114
|
+
*
|
|
115
|
+
* function ConfigPanel() {
|
|
116
|
+
* const { data, isLoading, error, write, isWriting } =
|
|
117
|
+
* useSPFxOneDriveAppData<MyConfig>('config.json');
|
|
118
|
+
*
|
|
119
|
+
* if (isLoading) return <Spinner label="Loading configuration..." />;
|
|
120
|
+
* if (error) return <MessageBar messageBarType={MessageBarType.error}>
|
|
121
|
+
* Failed to load: {error.message}
|
|
122
|
+
* </MessageBar>;
|
|
123
|
+
*
|
|
124
|
+
* const handleSave = async (newConfig: MyConfig) => {
|
|
125
|
+
* try {
|
|
126
|
+
* await write(newConfig);
|
|
127
|
+
* console.log('Saved successfully!');
|
|
128
|
+
* } catch (err) {
|
|
129
|
+
* console.error('Save failed:', err);
|
|
130
|
+
* }
|
|
131
|
+
* };
|
|
132
|
+
*
|
|
133
|
+
* return (
|
|
134
|
+
* <div>
|
|
135
|
+
* <TextField
|
|
136
|
+
* value={data?.title}
|
|
137
|
+
* onChange={(_, val) => handleSave({ ...data, title: val })}
|
|
138
|
+
* disabled={isWriting}
|
|
139
|
+
* />
|
|
140
|
+
* {isWriting && <Spinner label="Saving..." />}
|
|
141
|
+
* </div>
|
|
142
|
+
* );
|
|
143
|
+
* }
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* @example With folder namespace
|
|
147
|
+
* ```tsx
|
|
148
|
+
* // Store files in a dedicated folder
|
|
149
|
+
* const { data, write } = useSPFxOneDriveAppData<State>(
|
|
150
|
+
* 'state.json',
|
|
151
|
+
* 'my-app-v2' // Files stored in appRoot:/my-app-v2/state.json
|
|
152
|
+
* );
|
|
153
|
+
* ```
|
|
154
|
+
*
|
|
155
|
+
* @example Per-instance storage (multi-instance support)
|
|
156
|
+
* ```tsx
|
|
157
|
+
* // Each WebPart instance has its own data
|
|
158
|
+
* const { id } = useSPFxInstanceInfo();
|
|
159
|
+
* const { data, write } = useSPFxOneDriveAppData<Settings>(
|
|
160
|
+
* 'settings.json',
|
|
161
|
+
* id // Files stored in appRoot:/abc-123-guid/settings.json
|
|
162
|
+
* );
|
|
163
|
+
* ```
|
|
164
|
+
*
|
|
165
|
+
* @example Lazy loading (manual load)
|
|
166
|
+
* ```tsx
|
|
167
|
+
* const { data, load, isLoading, write } = useSPFxOneDriveAppData<Cache>(
|
|
168
|
+
* 'cache.json',
|
|
169
|
+
* 'my-app',
|
|
170
|
+
* false // Don't auto-fetch
|
|
171
|
+
* );
|
|
172
|
+
*
|
|
173
|
+
* return (
|
|
174
|
+
* <div>
|
|
175
|
+
* <button onClick={load} disabled={isLoading}>
|
|
176
|
+
* {isLoading ? 'Loading...' : 'Load Cache'}
|
|
177
|
+
* </button>
|
|
178
|
+
* {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
|
|
179
|
+
* </div>
|
|
180
|
+
* );
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* @example Multiple files in same namespace
|
|
184
|
+
* ```tsx
|
|
185
|
+
* function MyApp() {
|
|
186
|
+
* const config = useSPFxOneDriveAppData<Config>('config.json', 'myapp');
|
|
187
|
+
* const state = useSPFxOneDriveAppData<State>('state.json', 'myapp');
|
|
188
|
+
* const cache = useSPFxOneDriveAppData<Cache>('cache.json', 'myapp');
|
|
189
|
+
*
|
|
190
|
+
* // All files stored in appRoot:/myapp/
|
|
191
|
+
* // Easy to manage and clean up as a group
|
|
192
|
+
* }
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* @example Error handling and retry
|
|
196
|
+
* ```tsx
|
|
197
|
+
* function DataManager() {
|
|
198
|
+
* const { data, error, load, writeError, write, isReady } =
|
|
199
|
+
* useSPFxOneDriveAppData<MyData>('data.json');
|
|
200
|
+
*
|
|
201
|
+
* if (error) {
|
|
202
|
+
* return (
|
|
203
|
+
* <MessageBar
|
|
204
|
+
* messageBarType={MessageBarType.error}
|
|
205
|
+
* actions={<button onClick={load}>Retry</button>}
|
|
206
|
+
* >
|
|
207
|
+
* Load failed: {error.message}
|
|
208
|
+
* </MessageBar>
|
|
209
|
+
* );
|
|
210
|
+
* }
|
|
211
|
+
*
|
|
212
|
+
* if (writeError) {
|
|
213
|
+
* return (
|
|
214
|
+
* <MessageBar messageBarType={MessageBarType.warning}>
|
|
215
|
+
* Save failed: {writeError.message}
|
|
216
|
+
* </MessageBar>
|
|
217
|
+
* );
|
|
218
|
+
* }
|
|
219
|
+
*
|
|
220
|
+
* if (!isReady) return <Spinner />;
|
|
221
|
+
*
|
|
222
|
+
* return <DataDisplay data={data} onSave={write} />;
|
|
223
|
+
* }
|
|
224
|
+
* ```
|
|
225
|
+
*
|
|
226
|
+
* @example CRUD-like operations
|
|
227
|
+
* ```tsx
|
|
228
|
+
* interface TodoList {
|
|
229
|
+
* items: Array<{ id: string; text: string; done: boolean }>;
|
|
230
|
+
* }
|
|
231
|
+
*
|
|
232
|
+
* function TodoApp() {
|
|
233
|
+
* const { data, write, isLoading, isWriting } =
|
|
234
|
+
* useSPFxOneDriveAppData<TodoList>('todos.json', 'todo-app');
|
|
235
|
+
*
|
|
236
|
+
* const addTodo = async (text: string) => {
|
|
237
|
+
* const newItem = { id: crypto.randomUUID(), text, done: false };
|
|
238
|
+
* await write({
|
|
239
|
+
* items: [...(data?.items ?? []), newItem]
|
|
240
|
+
* });
|
|
241
|
+
* };
|
|
242
|
+
*
|
|
243
|
+
* const toggleTodo = async (id: string) => {
|
|
244
|
+
* await write({
|
|
245
|
+
* items: data?.items.map(item =>
|
|
246
|
+
* item.id === id ? { ...item, done: !item.done } : item
|
|
247
|
+
* ) ?? []
|
|
248
|
+
* });
|
|
249
|
+
* };
|
|
250
|
+
*
|
|
251
|
+
* const deleteTodo = async (id: string) => {
|
|
252
|
+
* await write({
|
|
253
|
+
* items: data?.items.filter(item => item.id !== id) ?? []
|
|
254
|
+
* });
|
|
255
|
+
* };
|
|
256
|
+
*
|
|
257
|
+
* if (isLoading) return <Spinner />;
|
|
258
|
+
*
|
|
259
|
+
* return (
|
|
260
|
+
* <div>
|
|
261
|
+
* <TodoList
|
|
262
|
+
* items={data?.items ?? []}
|
|
263
|
+
* onToggle={toggleTodo}
|
|
264
|
+
* onDelete={deleteTodo}
|
|
265
|
+
* />
|
|
266
|
+
* <AddTodoForm onAdd={addTodo} disabled={isWriting} />
|
|
267
|
+
* </div>
|
|
268
|
+
* );
|
|
269
|
+
* }
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
export function useSPFxOneDriveAppData(fileName, options) {
|
|
42
273
|
var _this = this;
|
|
43
274
|
var _a, _b;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
var
|
|
51
|
-
var
|
|
52
|
-
var
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
var
|
|
58
|
-
var
|
|
59
|
-
var
|
|
275
|
+
var _c = useSPFxMSGraphClient(), client = _c.client, isClientReady = _c.isReady, isClientInitializing = _c.isInitializing, clientInitError = _c.initError;
|
|
276
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
277
|
+
// OPTIONS (stabilized with useMemo to prevent unnecessary re-renders)
|
|
278
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
279
|
+
var resolvedOptions = useMemo(function () { return options !== null && options !== void 0 ? options : {}; }, [options]);
|
|
280
|
+
// Extract stable primitive values for dependency arrays
|
|
281
|
+
var folder = resolvedOptions.folder;
|
|
282
|
+
var shouldAutoFetch = (_a = resolvedOptions.autoFetch) !== null && _a !== void 0 ? _a : true;
|
|
283
|
+
var defaultValue = resolvedOptions.defaultValue;
|
|
284
|
+
var createIfMissing = (_b = resolvedOptions.createIfMissing) !== null && _b !== void 0 ? _b : false;
|
|
285
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
286
|
+
// STATE MANAGEMENT
|
|
287
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
288
|
+
var _d = useState(defaultValue), data = _d[0], setData = _d[1];
|
|
289
|
+
var _e = useState(false), isLoading = _e[0], setIsLoading = _e[1];
|
|
290
|
+
var _f = useState(undefined), error = _f[0], setError = _f[1];
|
|
291
|
+
var _g = useState(false), isWriting = _g[0], setIsWriting = _g[1];
|
|
292
|
+
var _h = useState(undefined), writeError = _h[0], setWriteError = _h[1];
|
|
293
|
+
var _j = useState(false), isNotFound = _j[0], setIsNotFound = _j[1];
|
|
294
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
295
|
+
// REFS (for cleanup and stable references)
|
|
296
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
60
297
|
// Track component mounted state to prevent memory leaks
|
|
61
|
-
var
|
|
298
|
+
var isMountedRef = useRef(true);
|
|
62
299
|
useEffect(function () {
|
|
63
|
-
isMounted.current = true;
|
|
64
300
|
return function () {
|
|
65
|
-
|
|
301
|
+
isMountedRef.current = false;
|
|
66
302
|
};
|
|
67
303
|
}, []);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
var basePath = '/me/drive/special/appRoot:';
|
|
74
|
-
if (folderName) {
|
|
75
|
-
// Sanitize folder name: only allow alphanumeric, hyphens, underscores
|
|
76
|
-
// This prevents path traversal (../) and other injection attacks
|
|
77
|
-
var safeFolderName = folderName.replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
78
|
-
return "".concat(basePath, "/").concat(safeFolderName, "/").concat(file, ":/content");
|
|
79
|
-
}
|
|
80
|
-
return "".concat(basePath, "/").concat(file, ":/content");
|
|
81
|
-
}, []);
|
|
82
|
-
var isNotFoundError = useCallback(function (err) {
|
|
83
|
-
var _a, _b, _c, _d, _e, _f;
|
|
84
|
-
var anyErr = err;
|
|
85
|
-
if ((anyErr === null || anyErr === void 0 ? void 0 : anyErr.statusCode) === 404 || (anyErr === null || anyErr === void 0 ? void 0 : anyErr.status) === 404)
|
|
86
|
-
return true;
|
|
87
|
-
var code = (_a = anyErr === null || anyErr === void 0 ? void 0 : anyErr.code) !== null && _a !== void 0 ? _a : (_c = (_b = anyErr === null || anyErr === void 0 ? void 0 : anyErr.body) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.code;
|
|
88
|
-
if (code && /itemnotfound/i.test(code))
|
|
89
|
-
return true;
|
|
90
|
-
var message = (_d = anyErr === null || anyErr === void 0 ? void 0 : anyErr.message) !== null && _d !== void 0 ? _d : (_f = (_e = anyErr === null || anyErr === void 0 ? void 0 : anyErr.body) === null || _e === void 0 ? void 0 : _e.error) === null || _f === void 0 ? void 0 : _f.message;
|
|
91
|
-
if (message && /(\b404\b|not found|itemnotfound)/i.test(message))
|
|
92
|
-
return true;
|
|
93
|
-
return false;
|
|
94
|
-
}, []);
|
|
304
|
+
// Track if createIfMissing write has been attempted (to prevent multiple writes)
|
|
305
|
+
var createAttemptedRef = useRef(false);
|
|
306
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
307
|
+
// WRITE CALLBACK (defined first, no dependency on load)
|
|
308
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
95
309
|
/**
|
|
96
310
|
* Write data to OneDrive file
|
|
97
311
|
* Creates file if it doesn't exist, updates if it does (upsert)
|
|
98
312
|
* Updates isWriting and writeError states
|
|
99
313
|
*/
|
|
100
314
|
var write = useCallback(function (content) { return __awaiter(_this, void 0, void 0, function () {
|
|
101
|
-
var apiPath, jsonContent, err_1,
|
|
315
|
+
var apiPath, jsonContent, err_1, writeErr;
|
|
102
316
|
return __generator(this, function (_a) {
|
|
103
317
|
switch (_a.label) {
|
|
104
318
|
case 0:
|
|
105
319
|
if (!client) {
|
|
320
|
+
if (isClientInitializing) {
|
|
321
|
+
throw new Error('Graph client is still initializing. Please wait and try again.');
|
|
322
|
+
}
|
|
323
|
+
if (clientInitError) {
|
|
324
|
+
throw new Error("Graph client initialization failed: ".concat(clientInitError.message));
|
|
325
|
+
}
|
|
106
326
|
throw new Error('Graph client not available. Cannot write file.');
|
|
107
327
|
}
|
|
108
328
|
if (!fileName) {
|
|
@@ -121,7 +341,7 @@ export function useSPFxOneDriveAppData(fileName, folderOrOptions, autoFetch) {
|
|
|
121
341
|
.put(jsonContent)];
|
|
122
342
|
case 2:
|
|
123
343
|
_a.sent();
|
|
124
|
-
if (
|
|
344
|
+
if (isMountedRef.current) {
|
|
125
345
|
// Update local data to reflect successful write
|
|
126
346
|
setData(content);
|
|
127
347
|
setIsNotFound(false);
|
|
@@ -131,50 +351,64 @@ export function useSPFxOneDriveAppData(fileName, folderOrOptions, autoFetch) {
|
|
|
131
351
|
return [3 /*break*/, 5];
|
|
132
352
|
case 3:
|
|
133
353
|
err_1 = _a.sent();
|
|
134
|
-
if (
|
|
135
|
-
|
|
136
|
-
setWriteError(
|
|
137
|
-
console.error('Failed to write file to OneDrive:',
|
|
354
|
+
if (isMountedRef.current) {
|
|
355
|
+
writeErr = err_1 instanceof Error ? err_1 : new Error(String(err_1));
|
|
356
|
+
setWriteError(writeErr);
|
|
357
|
+
console.error('Failed to write file to OneDrive:', writeErr);
|
|
138
358
|
}
|
|
139
359
|
// Re-throw to allow caller to handle
|
|
140
360
|
throw err_1;
|
|
141
361
|
case 4:
|
|
142
|
-
if (
|
|
362
|
+
if (isMountedRef.current) {
|
|
143
363
|
setIsWriting(false);
|
|
144
364
|
}
|
|
145
365
|
return [7 /*endfinally*/];
|
|
146
366
|
case 5: return [2 /*return*/];
|
|
147
367
|
}
|
|
148
368
|
});
|
|
149
|
-
}); }, [client, fileName, folder,
|
|
369
|
+
}); }, [client, fileName, folder, isClientInitializing, clientInitError]);
|
|
370
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
371
|
+
// LOAD CALLBACK (NO dependency on write - uses effect for createIfMissing)
|
|
372
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
150
373
|
/**
|
|
151
374
|
* Load file from OneDrive
|
|
152
375
|
* Updates data, isLoading, and error states
|
|
376
|
+
* Does NOT call write directly - createIfMissing is handled by separate effect
|
|
153
377
|
*/
|
|
154
378
|
var load = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
155
|
-
var apiPath, fileContent, err_2, notFound,
|
|
379
|
+
var apiPath, fileContent, err_2, notFound, loadError;
|
|
156
380
|
return __generator(this, function (_a) {
|
|
157
381
|
switch (_a.label) {
|
|
158
382
|
case 0:
|
|
159
383
|
if (!client) {
|
|
160
|
-
|
|
384
|
+
if (isClientInitializing) {
|
|
385
|
+
console.info('Graph client is still initializing. Skipping load - will auto-retry when ready.');
|
|
386
|
+
return [2 /*return*/];
|
|
387
|
+
}
|
|
388
|
+
if (clientInitError) {
|
|
389
|
+
console.error('Graph client initialization failed:', clientInitError.message);
|
|
390
|
+
return [2 /*return*/];
|
|
391
|
+
}
|
|
392
|
+
console.warn('Graph client not available. Skipping load.');
|
|
161
393
|
return [2 /*return*/];
|
|
162
394
|
}
|
|
163
395
|
if (!fileName) {
|
|
164
396
|
console.warn('fileName is required. Skipping load.');
|
|
165
397
|
return [2 /*return*/];
|
|
166
398
|
}
|
|
399
|
+
// Reset createAttempted flag when load is called (fresh attempt)
|
|
400
|
+
createAttemptedRef.current = false;
|
|
167
401
|
setIsLoading(true);
|
|
168
402
|
setError(undefined);
|
|
169
403
|
setIsNotFound(false);
|
|
170
404
|
_a.label = 1;
|
|
171
405
|
case 1:
|
|
172
|
-
_a.trys.push([1, 3,
|
|
406
|
+
_a.trys.push([1, 3, 4, 5]);
|
|
173
407
|
apiPath = buildApiPath(fileName, folder);
|
|
174
408
|
return [4 /*yield*/, client.api(apiPath).get()];
|
|
175
409
|
case 2:
|
|
176
410
|
fileContent = _a.sent();
|
|
177
|
-
if (
|
|
411
|
+
if (isMountedRef.current) {
|
|
178
412
|
// Parse JSON if response is string, otherwise use as-is
|
|
179
413
|
if (typeof fileContent === 'string') {
|
|
180
414
|
try {
|
|
@@ -189,60 +423,77 @@ export function useSPFxOneDriveAppData(fileName, folderOrOptions, autoFetch) {
|
|
|
189
423
|
}
|
|
190
424
|
setIsNotFound(false);
|
|
191
425
|
}
|
|
192
|
-
return [3 /*break*/,
|
|
426
|
+
return [3 /*break*/, 5];
|
|
193
427
|
case 3:
|
|
194
428
|
err_2 = _a.sent();
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
429
|
+
if (isMountedRef.current) {
|
|
430
|
+
notFound = isNotFoundError(err_2);
|
|
431
|
+
setIsNotFound(notFound);
|
|
432
|
+
if (notFound) {
|
|
433
|
+
// Missing file is treated as a non-error.
|
|
434
|
+
// Set data to defaultValue if provided, otherwise undefined
|
|
435
|
+
if (defaultValue !== undefined) {
|
|
436
|
+
setData(defaultValue);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
setData(undefined);
|
|
440
|
+
}
|
|
441
|
+
setError(undefined);
|
|
442
|
+
console.info('OneDrive file not found. isNotFound=true');
|
|
443
|
+
// NOTE: createIfMissing is handled by separate useEffect
|
|
444
|
+
return [2 /*return*/];
|
|
445
|
+
}
|
|
446
|
+
loadError = err_2 instanceof Error ? err_2 : new Error(String(err_2));
|
|
447
|
+
setError(loadError);
|
|
448
|
+
console.error('Failed to load file from OneDrive:', loadError);
|
|
449
|
+
}
|
|
450
|
+
return [3 /*break*/, 5];
|
|
203
451
|
case 4:
|
|
204
|
-
|
|
205
|
-
return [4 /*yield*/, write(defaultValue)];
|
|
206
|
-
case 5:
|
|
207
|
-
_a.sent();
|
|
208
|
-
return [3 /*break*/, 7];
|
|
209
|
-
case 6:
|
|
210
|
-
writeErr_1 = _a.sent();
|
|
211
|
-
// write() already updates writeError state
|
|
212
|
-
console.error('Failed to create missing file in OneDrive:', writeErr_1);
|
|
213
|
-
return [3 /*break*/, 7];
|
|
214
|
-
case 7: return [3 /*break*/, 9];
|
|
215
|
-
case 8:
|
|
216
|
-
setData(undefined);
|
|
217
|
-
_a.label = 9;
|
|
218
|
-
case 9:
|
|
219
|
-
setError(undefined);
|
|
220
|
-
console.info('OneDrive file not found. isNotFound=true');
|
|
221
|
-
return [2 /*return*/];
|
|
222
|
-
case 10:
|
|
223
|
-
error_2 = err_2 instanceof Error ? err_2 : new Error(String(err_2));
|
|
224
|
-
setError(error_2);
|
|
225
|
-
// Don't throw - allow component to handle error via state
|
|
226
|
-
console.error('Failed to load file from OneDrive:', error_2);
|
|
227
|
-
_a.label = 11;
|
|
228
|
-
case 11: return [3 /*break*/, 13];
|
|
229
|
-
case 12:
|
|
230
|
-
if (isMounted.current) {
|
|
452
|
+
if (isMountedRef.current) {
|
|
231
453
|
setIsLoading(false);
|
|
232
454
|
}
|
|
233
455
|
return [7 /*endfinally*/];
|
|
234
|
-
case
|
|
456
|
+
case 5: return [2 /*return*/];
|
|
235
457
|
}
|
|
236
458
|
});
|
|
237
|
-
}); }, [client, fileName, folder,
|
|
238
|
-
//
|
|
459
|
+
}); }, [client, fileName, folder, defaultValue, isClientInitializing, clientInitError]); // ← NO write, NO createIfMissing
|
|
460
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
461
|
+
// EFFECTS
|
|
462
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
463
|
+
// Auto-fetch on mount if enabled (wait for client to be ready)
|
|
239
464
|
useEffect(function () {
|
|
240
|
-
if (shouldAutoFetch &&
|
|
465
|
+
if (shouldAutoFetch && isClientReady && fileName) {
|
|
241
466
|
load().catch(function () {
|
|
242
467
|
// Error already handled in load() function
|
|
243
468
|
});
|
|
244
469
|
}
|
|
245
|
-
}, [shouldAutoFetch,
|
|
470
|
+
}, [shouldAutoFetch, isClientReady, fileName, load]);
|
|
471
|
+
// Separate effect for createIfMissing - reacts to isNotFound state
|
|
472
|
+
// This breaks the circular dependency: load → write
|
|
473
|
+
useEffect(function () {
|
|
474
|
+
// Guard conditions:
|
|
475
|
+
// 1. File must be not found
|
|
476
|
+
// 2. createIfMissing must be enabled
|
|
477
|
+
// 3. defaultValue must be provided
|
|
478
|
+
// 4. Must not be currently writing (prevent double-write)
|
|
479
|
+
// 5. Must not have already attempted create (prevent infinite loop)
|
|
480
|
+
// 6. Must not be currently loading (wait for load to complete)
|
|
481
|
+
if (isNotFound &&
|
|
482
|
+
createIfMissing &&
|
|
483
|
+
defaultValue !== undefined &&
|
|
484
|
+
!isWriting &&
|
|
485
|
+
!createAttemptedRef.current &&
|
|
486
|
+
!isLoading) {
|
|
487
|
+
createAttemptedRef.current = true;
|
|
488
|
+
write(defaultValue).catch(function (writeErr) {
|
|
489
|
+
// write() already updates writeError state
|
|
490
|
+
console.error('Failed to create missing file in OneDrive:', writeErr);
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}, [isNotFound, createIfMissing, defaultValue, isWriting, isLoading, write]);
|
|
494
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
495
|
+
// COMPUTED STATE & RETURN
|
|
496
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
246
497
|
// Computed state: ready when data loaded successfully
|
|
247
498
|
var isReady = !isLoading && !error && data !== undefined;
|
|
248
499
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSPFxOneDriveAppData.js","sourceRoot":"","sources":["../../src/hooks/useSPFxOneDriveAppData.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,6EAA6E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE7E,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useSPFxOneDriveAppData.js","sourceRoot":"","sources":["../../src/hooks/useSPFxOneDriveAppData.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,15 +6,16 @@ export interface SPFxSPHttpClientInfo {
|
|
|
6
6
|
/**
|
|
7
7
|
* Native SPHttpClient from SPFx.
|
|
8
8
|
* Provides access to SharePoint REST APIs with built-in authentication.
|
|
9
|
-
*
|
|
9
|
+
* Will be undefined if ServiceScope is not available.
|
|
10
10
|
*/
|
|
11
|
-
readonly client: SPHttpClient;
|
|
11
|
+
readonly client: SPHttpClient | undefined;
|
|
12
12
|
/**
|
|
13
13
|
* Invoke SharePoint REST API call with automatic state management.
|
|
14
14
|
* Tracks loading state and captures errors automatically.
|
|
15
15
|
*
|
|
16
16
|
* @param fn - Function that receives SPHttpClient and returns a promise
|
|
17
17
|
* @returns Promise with the result
|
|
18
|
+
* @throws Error if client is not available
|
|
18
19
|
*
|
|
19
20
|
* @example
|
|
20
21
|
* ```tsx
|
|
@@ -43,6 +44,21 @@ export interface SPFxSPHttpClientInfo {
|
|
|
43
44
|
readonly setBaseUrl: (url: string) => void;
|
|
44
45
|
/** Current base URL (site absolute URL) */
|
|
45
46
|
readonly baseUrl: string;
|
|
47
|
+
/**
|
|
48
|
+
* Computed state: true when client is ready for use.
|
|
49
|
+
* Equivalent to: client !== undefined
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* const { isReady, client, invoke } = useSPFxSPHttpClient();
|
|
54
|
+
*
|
|
55
|
+
* if (!isReady) return <Spinner label="Waiting for SPHttpClient..." />;
|
|
56
|
+
*
|
|
57
|
+
* // Safe to use client or invoke
|
|
58
|
+
* const data = await invoke(c => c.get(...).then(r => r.json()));
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
readonly isReady: boolean;
|
|
46
62
|
}
|
|
47
63
|
/**
|
|
48
64
|
* Hook to access SharePoint REST APIs with built-in state management
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSPFxSPHttpClient.d.ts","sourceRoot":"","sources":["../../src/hooks/useSPFxSPHttpClient.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"useSPFxSPHttpClient.d.ts","sourceRoot":"","sources":["../../src/hooks/useSPFxSPHttpClient.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC;IAE1C;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAE7E;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IAElC,8BAA8B;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAEhC,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAE3C,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+KG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,oBAAoB,CAsDjF"}
|