@apvee/spfx-react-toolkit 1.0.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/LICENSE +21 -0
- package/README.md +2012 -0
- package/lib/core/atoms.internal.d.ts +53 -0
- package/lib/core/atoms.internal.d.ts.map +1 -0
- package/lib/core/atoms.internal.js +35 -0
- package/lib/core/atoms.internal.js.map +1 -0
- package/lib/core/context.internal.d.ts +23 -0
- package/lib/core/context.internal.d.ts.map +1 -0
- package/lib/core/context.internal.js +34 -0
- package/lib/core/context.internal.js.map +1 -0
- package/lib/core/index.d.ts +6 -0
- package/lib/core/index.d.ts.map +1 -0
- package/lib/core/index.js +6 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/provider-application-customizer.d.ts +57 -0
- package/lib/core/provider-application-customizer.d.ts.map +1 -0
- package/lib/core/provider-application-customizer.js +45 -0
- package/lib/core/provider-application-customizer.js.map +1 -0
- package/lib/core/provider-base.internal.d.ts +20 -0
- package/lib/core/provider-base.internal.d.ts.map +1 -0
- package/lib/core/provider-base.internal.js +126 -0
- package/lib/core/provider-base.internal.js.map +1 -0
- package/lib/core/provider-field-customizer.d.ts +58 -0
- package/lib/core/provider-field-customizer.d.ts.map +1 -0
- package/lib/core/provider-field-customizer.js +46 -0
- package/lib/core/provider-field-customizer.js.map +1 -0
- package/lib/core/provider-listview-commandset.d.ts +60 -0
- package/lib/core/provider-listview-commandset.d.ts.map +1 -0
- package/lib/core/provider-listview-commandset.js +48 -0
- package/lib/core/provider-listview-commandset.js.map +1 -0
- package/lib/core/provider-webpart.d.ts +48 -0
- package/lib/core/provider-webpart.d.ts.map +1 -0
- package/lib/core/provider-webpart.js +36 -0
- package/lib/core/provider-webpart.js.map +1 -0
- package/lib/core/types.d.ts +84 -0
- package/lib/core/types.d.ts.map +1 -0
- package/lib/core/types.js +4 -0
- package/lib/core/types.js.map +1 -0
- package/lib/hooks/index.d.ts +34 -0
- package/lib/hooks/index.d.ts.map +1 -0
- package/lib/hooks/index.js +34 -0
- package/lib/hooks/index.js.map +1 -0
- package/lib/hooks/useSPFxAadHttpClient.d.ts +231 -0
- package/lib/hooks/useSPFxAadHttpClient.d.ts.map +1 -0
- package/lib/hooks/useSPFxAadHttpClient.js +299 -0
- package/lib/hooks/useSPFxAadHttpClient.js.map +1 -0
- package/lib/hooks/useSPFxContainerInfo.d.ts +41 -0
- package/lib/hooks/useSPFxContainerInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxContainerInfo.js +47 -0
- package/lib/hooks/useSPFxContainerInfo.js.map +1 -0
- package/lib/hooks/useSPFxContainerSize.d.ts +119 -0
- package/lib/hooks/useSPFxContainerSize.d.ts.map +1 -0
- package/lib/hooks/useSPFxContainerSize.js +150 -0
- package/lib/hooks/useSPFxContainerSize.js.map +1 -0
- package/lib/hooks/useSPFxContext.d.ts +14 -0
- package/lib/hooks/useSPFxContext.d.ts.map +1 -0
- package/lib/hooks/useSPFxContext.js +16 -0
- package/lib/hooks/useSPFxContext.js.map +1 -0
- package/lib/hooks/useSPFxCorrelationInfo.d.ts +51 -0
- package/lib/hooks/useSPFxCorrelationInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxCorrelationInfo.js +58 -0
- package/lib/hooks/useSPFxCorrelationInfo.js.map +1 -0
- package/lib/hooks/useSPFxCrossSitePermissions.d.ts +81 -0
- package/lib/hooks/useSPFxCrossSitePermissions.d.ts.map +1 -0
- package/lib/hooks/useSPFxCrossSitePermissions.js +132 -0
- package/lib/hooks/useSPFxCrossSitePermissions.js.map +1 -0
- package/lib/hooks/useSPFxDisplayMode.d.ts +61 -0
- package/lib/hooks/useSPFxDisplayMode.d.ts.map +1 -0
- package/lib/hooks/useSPFxDisplayMode.js +69 -0
- package/lib/hooks/useSPFxDisplayMode.js.map +1 -0
- package/lib/hooks/useSPFxEnvironmentInfo.d.ts +63 -0
- package/lib/hooks/useSPFxEnvironmentInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxEnvironmentInfo.js +91 -0
- package/lib/hooks/useSPFxEnvironmentInfo.js.map +1 -0
- package/lib/hooks/useSPFxFluent9ThemeInfo.d.ts +105 -0
- package/lib/hooks/useSPFxFluent9ThemeInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxFluent9ThemeInfo.js +136 -0
- package/lib/hooks/useSPFxFluent9ThemeInfo.js.map +1 -0
- package/lib/hooks/useSPFxHubSiteInfo.d.ts +80 -0
- package/lib/hooks/useSPFxHubSiteInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxHubSiteInfo.js +127 -0
- package/lib/hooks/useSPFxHubSiteInfo.js.map +1 -0
- package/lib/hooks/useSPFxInstanceInfo.d.ts +41 -0
- package/lib/hooks/useSPFxInstanceInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxInstanceInfo.js +40 -0
- package/lib/hooks/useSPFxInstanceInfo.js.map +1 -0
- package/lib/hooks/useSPFxListInfo.d.ts +64 -0
- package/lib/hooks/useSPFxListInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxListInfo.js +70 -0
- package/lib/hooks/useSPFxListInfo.js.map +1 -0
- package/lib/hooks/useSPFxLocaleInfo.d.ts +123 -0
- package/lib/hooks/useSPFxLocaleInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxLocaleInfo.js +109 -0
- package/lib/hooks/useSPFxLocaleInfo.js.map +1 -0
- package/lib/hooks/useSPFxLogger.d.ts +108 -0
- package/lib/hooks/useSPFxLogger.d.ts.map +1 -0
- package/lib/hooks/useSPFxLogger.js +117 -0
- package/lib/hooks/useSPFxLogger.js.map +1 -0
- package/lib/hooks/useSPFxMSGraphClient.d.ts +200 -0
- package/lib/hooks/useSPFxMSGraphClient.d.ts.map +1 -0
- package/lib/hooks/useSPFxMSGraphClient.js +264 -0
- package/lib/hooks/useSPFxMSGraphClient.js.map +1 -0
- package/lib/hooks/useSPFxOneDriveAppData.d.ts +264 -0
- package/lib/hooks/useSPFxOneDriveAppData.d.ts.map +1 -0
- package/lib/hooks/useSPFxOneDriveAppData.js +395 -0
- package/lib/hooks/useSPFxOneDriveAppData.js.map +1 -0
- package/lib/hooks/useSPFxPageContext.d.ts +37 -0
- package/lib/hooks/useSPFxPageContext.d.ts.map +1 -0
- package/lib/hooks/useSPFxPageContext.js +49 -0
- package/lib/hooks/useSPFxPageContext.js.map +1 -0
- package/lib/hooks/useSPFxPageType.d.ts +82 -0
- package/lib/hooks/useSPFxPageType.d.ts.map +1 -0
- package/lib/hooks/useSPFxPageType.js +137 -0
- package/lib/hooks/useSPFxPageType.js.map +1 -0
- package/lib/hooks/useSPFxPerformance.d.ts +72 -0
- package/lib/hooks/useSPFxPerformance.d.ts.map +1 -0
- package/lib/hooks/useSPFxPerformance.js +167 -0
- package/lib/hooks/useSPFxPerformance.js.map +1 -0
- package/lib/hooks/useSPFxPermissions.d.ts +61 -0
- package/lib/hooks/useSPFxPermissions.d.ts.map +1 -0
- package/lib/hooks/useSPFxPermissions.js +73 -0
- package/lib/hooks/useSPFxPermissions.js.map +1 -0
- package/lib/hooks/useSPFxPnP.d.ts +539 -0
- package/lib/hooks/useSPFxPnP.d.ts.map +1 -0
- package/lib/hooks/useSPFxPnP.js +533 -0
- package/lib/hooks/useSPFxPnP.js.map +1 -0
- package/lib/hooks/useSPFxPnPContext.d.ts +290 -0
- package/lib/hooks/useSPFxPnPContext.d.ts.map +1 -0
- package/lib/hooks/useSPFxPnPContext.js +340 -0
- package/lib/hooks/useSPFxPnPContext.js.map +1 -0
- package/lib/hooks/useSPFxPnPList.d.ts +545 -0
- package/lib/hooks/useSPFxPnPList.d.ts.map +1 -0
- package/lib/hooks/useSPFxPnPList.js +906 -0
- package/lib/hooks/useSPFxPnPList.js.map +1 -0
- package/lib/hooks/useSPFxPnPSearch.d.ts +540 -0
- package/lib/hooks/useSPFxPnPSearch.d.ts.map +1 -0
- package/lib/hooks/useSPFxPnPSearch.js +672 -0
- package/lib/hooks/useSPFxPnPSearch.js.map +1 -0
- package/lib/hooks/useSPFxProperties.d.ts +80 -0
- package/lib/hooks/useSPFxProperties.d.ts.map +1 -0
- package/lib/hooks/useSPFxProperties.js +95 -0
- package/lib/hooks/useSPFxProperties.js.map +1 -0
- package/lib/hooks/useSPFxSPHttpClient.d.ts +218 -0
- package/lib/hooks/useSPFxSPHttpClient.d.ts.map +1 -0
- package/lib/hooks/useSPFxSPHttpClient.js +287 -0
- package/lib/hooks/useSPFxSPHttpClient.js.map +1 -0
- package/lib/hooks/useSPFxServiceScope.d.ts +107 -0
- package/lib/hooks/useSPFxServiceScope.d.ts.map +1 -0
- package/lib/hooks/useSPFxServiceScope.js +105 -0
- package/lib/hooks/useSPFxServiceScope.js.map +1 -0
- package/lib/hooks/useSPFxSiteInfo.d.ts +116 -0
- package/lib/hooks/useSPFxSiteInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxSiteInfo.js +109 -0
- package/lib/hooks/useSPFxSiteInfo.js.map +1 -0
- package/lib/hooks/useSPFxStorage.d.ts +81 -0
- package/lib/hooks/useSPFxStorage.d.ts.map +1 -0
- package/lib/hooks/useSPFxStorage.js +140 -0
- package/lib/hooks/useSPFxStorage.js.map +1 -0
- package/lib/hooks/useSPFxTeams.d.ts +63 -0
- package/lib/hooks/useSPFxTeams.d.ts.map +1 -0
- package/lib/hooks/useSPFxTeams.js +198 -0
- package/lib/hooks/useSPFxTeams.js.map +1 -0
- package/lib/hooks/useSPFxTenantProperty.d.ts +389 -0
- package/lib/hooks/useSPFxTenantProperty.d.ts.map +1 -0
- package/lib/hooks/useSPFxTenantProperty.js +683 -0
- package/lib/hooks/useSPFxTenantProperty.js.map +1 -0
- package/lib/hooks/useSPFxThemeInfo.d.ts +27 -0
- package/lib/hooks/useSPFxThemeInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxThemeInfo.js +33 -0
- package/lib/hooks/useSPFxThemeInfo.js.map +1 -0
- package/lib/hooks/useSPFxUserInfo.d.ts +47 -0
- package/lib/hooks/useSPFxUserInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxUserInfo.js +47 -0
- package/lib/hooks/useSPFxUserInfo.js.map +1 -0
- package/lib/hooks/useSPFxUserPhoto.d.ts +270 -0
- package/lib/hooks/useSPFxUserPhoto.d.ts.map +1 -0
- package/lib/hooks/useSPFxUserPhoto.js +346 -0
- package/lib/hooks/useSPFxUserPhoto.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +3 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/resize-observer.internal.d.ts +10 -0
- package/lib/utils/resize-observer.internal.d.ts.map +1 -0
- package/lib/utils/resize-observer.internal.js +34 -0
- package/lib/utils/resize-observer.internal.js.map +1 -0
- package/lib/utils/theme-subscription.internal.d.ts +11 -0
- package/lib/utils/theme-subscription.internal.d.ts.map +1 -0
- package/lib/utils/theme-subscription.internal.js +58 -0
- package/lib/utils/theme-subscription.internal.js.map +1 -0
- package/lib/utils/type-guards.internal.d.ts +35 -0
- package/lib/utils/type-guards.internal.d.ts.map +1 -0
- package/lib/utils/type-guards.internal.js +88 -0
- package/lib/utils/type-guards.internal.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.d.ts +13 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.d.ts.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.js +67 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.manifest.json +21 -0
- package/lib/webparts/spFxReactToolkitTest/assets/welcome-dark.png +0 -0
- package/lib/webparts/spFxReactToolkitTest/assets/welcome-light.png +0 -0
- package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.d.ts +8 -0
- package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.d.ts.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.js +2 -0
- package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts +8 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js +1351 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.css +2 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.d.ts +18 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.d.ts.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.js +19 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/loc/en-us.js +16 -0
- package/package.json +95 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return type for useSPFxOneDriveAppData hook
|
|
3
|
+
*/
|
|
4
|
+
export interface SPFxOneDriveAppDataResult<T> {
|
|
5
|
+
/**
|
|
6
|
+
* The loaded data from OneDrive.
|
|
7
|
+
* Undefined if not loaded yet or on error.
|
|
8
|
+
*/
|
|
9
|
+
readonly data: T | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Loading state for read operations.
|
|
12
|
+
* True during initial load or manual load() calls.
|
|
13
|
+
*/
|
|
14
|
+
readonly isLoading: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Last error from read operations.
|
|
17
|
+
* Cleared on successful load or write.
|
|
18
|
+
*/
|
|
19
|
+
readonly error: Error | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Loading state for write operations.
|
|
22
|
+
* True during write() calls.
|
|
23
|
+
*/
|
|
24
|
+
readonly isWriting: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Last error from write operations.
|
|
27
|
+
* Cleared on successful write or load.
|
|
28
|
+
*/
|
|
29
|
+
readonly writeError: Error | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Manually load/reload the file from OneDrive.
|
|
32
|
+
* Updates data, isLoading, and error states.
|
|
33
|
+
*
|
|
34
|
+
* @returns Promise that resolves when load completes
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* const { data, load } = useSPFxOneDriveAppData<Config>('config.json', undefined, false);
|
|
39
|
+
*
|
|
40
|
+
* // Load on button click
|
|
41
|
+
* <button onClick={load}>Refresh</button>
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
readonly load: () => Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Write data to OneDrive file.
|
|
47
|
+
* Creates file if it doesn't exist, updates if it does.
|
|
48
|
+
* Updates isWriting and writeError states.
|
|
49
|
+
*
|
|
50
|
+
* @param content - Data to write (will be JSON.stringify'd)
|
|
51
|
+
* @returns Promise that resolves when write completes
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* const { write, isWriting } = useSPFxOneDriveAppData<Config>('config.json');
|
|
56
|
+
*
|
|
57
|
+
* const handleSave = async () => {
|
|
58
|
+
* await write({ theme: 'dark', language: 'en' });
|
|
59
|
+
* };
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
readonly write: (content: T) => Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Computed state: true if data is loaded successfully.
|
|
65
|
+
* Equivalent to: !isLoading && !error && data !== undefined
|
|
66
|
+
*
|
|
67
|
+
* Useful for conditional rendering:
|
|
68
|
+
* ```tsx
|
|
69
|
+
* if (!isReady) return <Spinner />;
|
|
70
|
+
* return <div>{data.title}</div>;
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
readonly isReady: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Hook to manage JSON files in user's OneDrive appRoot folder
|
|
77
|
+
*
|
|
78
|
+
* Provides unified read/write operations for JSON data stored in OneDrive's special
|
|
79
|
+
* appRoot folder (accessible per-app, user-scoped storage).
|
|
80
|
+
*
|
|
81
|
+
* Features:
|
|
82
|
+
* - Automatic JSON serialization/deserialization
|
|
83
|
+
* - Separate loading states for read/write operations
|
|
84
|
+
* - Optional auto-fetch on mount
|
|
85
|
+
* - Folder/namespace support for file organization
|
|
86
|
+
* - Type-safe with TypeScript generics
|
|
87
|
+
* - Memory leak safe with mounted state tracking
|
|
88
|
+
* - Error handling for both read and write operations
|
|
89
|
+
*
|
|
90
|
+
* Requirements:
|
|
91
|
+
* - Microsoft Graph permissions: Files.ReadWrite or Files.ReadWrite.AppFolder
|
|
92
|
+
* - User must be authenticated
|
|
93
|
+
*
|
|
94
|
+
* @param fileName - Name of the JSON file (e.g., 'config.json', 'settings.json')
|
|
95
|
+
* @param folder - Optional folder/namespace identifier for file organization.
|
|
96
|
+
* Will be sanitized to prevent path traversal.
|
|
97
|
+
* Examples: 'my-app', instanceId (GUID), 'config-v2'
|
|
98
|
+
* @param autoFetch - Whether to automatically load file on mount. Default: true
|
|
99
|
+
*
|
|
100
|
+
* @returns Object with data, loading states, error states, and read/write functions
|
|
101
|
+
*
|
|
102
|
+
* @example Basic usage - auto-fetch from root
|
|
103
|
+
* ```tsx
|
|
104
|
+
* import type { MyConfig } from './types';
|
|
105
|
+
*
|
|
106
|
+
* function ConfigPanel() {
|
|
107
|
+
* const { data, isLoading, error, write, isWriting } =
|
|
108
|
+
* useSPFxOneDriveAppData<MyConfig>('config.json');
|
|
109
|
+
*
|
|
110
|
+
* if (isLoading) return <Spinner label="Loading configuration..." />;
|
|
111
|
+
* if (error) return <MessageBar messageBarType={MessageBarType.error}>
|
|
112
|
+
* Failed to load: {error.message}
|
|
113
|
+
* </MessageBar>;
|
|
114
|
+
*
|
|
115
|
+
* const handleSave = async (newConfig: MyConfig) => {
|
|
116
|
+
* try {
|
|
117
|
+
* await write(newConfig);
|
|
118
|
+
* console.log('Saved successfully!');
|
|
119
|
+
* } catch (err) {
|
|
120
|
+
* console.error('Save failed:', err);
|
|
121
|
+
* }
|
|
122
|
+
* };
|
|
123
|
+
*
|
|
124
|
+
* return (
|
|
125
|
+
* <div>
|
|
126
|
+
* <TextField
|
|
127
|
+
* value={data?.title}
|
|
128
|
+
* onChange={(_, val) => handleSave({ ...data, title: val })}
|
|
129
|
+
* disabled={isWriting}
|
|
130
|
+
* />
|
|
131
|
+
* {isWriting && <Spinner label="Saving..." />}
|
|
132
|
+
* </div>
|
|
133
|
+
* );
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* @example With folder namespace
|
|
138
|
+
* ```tsx
|
|
139
|
+
* // Store files in a dedicated folder
|
|
140
|
+
* const { data, write } = useSPFxOneDriveAppData<State>(
|
|
141
|
+
* 'state.json',
|
|
142
|
+
* 'my-app-v2' // Files stored in appRoot:/my-app-v2/state.json
|
|
143
|
+
* );
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* @example Per-instance storage (multi-instance support)
|
|
147
|
+
* ```tsx
|
|
148
|
+
* // Each WebPart instance has its own data
|
|
149
|
+
* const { id } = useSPFxInstanceInfo();
|
|
150
|
+
* const { data, write } = useSPFxOneDriveAppData<Settings>(
|
|
151
|
+
* 'settings.json',
|
|
152
|
+
* id // Files stored in appRoot:/abc-123-guid/settings.json
|
|
153
|
+
* );
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* @example Lazy loading (manual load)
|
|
157
|
+
* ```tsx
|
|
158
|
+
* const { data, load, isLoading, write } = useSPFxOneDriveAppData<Cache>(
|
|
159
|
+
* 'cache.json',
|
|
160
|
+
* 'my-app',
|
|
161
|
+
* false // Don't auto-fetch
|
|
162
|
+
* );
|
|
163
|
+
*
|
|
164
|
+
* return (
|
|
165
|
+
* <div>
|
|
166
|
+
* <button onClick={load} disabled={isLoading}>
|
|
167
|
+
* {isLoading ? 'Loading...' : 'Load Cache'}
|
|
168
|
+
* </button>
|
|
169
|
+
* {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
|
|
170
|
+
* </div>
|
|
171
|
+
* );
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* @example Multiple files in same namespace
|
|
175
|
+
* ```tsx
|
|
176
|
+
* function MyApp() {
|
|
177
|
+
* const config = useSPFxOneDriveAppData<Config>('config.json', 'myapp');
|
|
178
|
+
* const state = useSPFxOneDriveAppData<State>('state.json', 'myapp');
|
|
179
|
+
* const cache = useSPFxOneDriveAppData<Cache>('cache.json', 'myapp');
|
|
180
|
+
*
|
|
181
|
+
* // All files stored in appRoot:/myapp/
|
|
182
|
+
* // Easy to manage and clean up as a group
|
|
183
|
+
* }
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @example Error handling and retry
|
|
187
|
+
* ```tsx
|
|
188
|
+
* function DataManager() {
|
|
189
|
+
* const { data, error, load, writeError, write, isReady } =
|
|
190
|
+
* useSPFxOneDriveAppData<MyData>('data.json');
|
|
191
|
+
*
|
|
192
|
+
* if (error) {
|
|
193
|
+
* return (
|
|
194
|
+
* <MessageBar
|
|
195
|
+
* messageBarType={MessageBarType.error}
|
|
196
|
+
* actions={<button onClick={load}>Retry</button>}
|
|
197
|
+
* >
|
|
198
|
+
* Load failed: {error.message}
|
|
199
|
+
* </MessageBar>
|
|
200
|
+
* );
|
|
201
|
+
* }
|
|
202
|
+
*
|
|
203
|
+
* if (writeError) {
|
|
204
|
+
* return (
|
|
205
|
+
* <MessageBar messageBarType={MessageBarType.warning}>
|
|
206
|
+
* Save failed: {writeError.message}
|
|
207
|
+
* </MessageBar>
|
|
208
|
+
* );
|
|
209
|
+
* }
|
|
210
|
+
*
|
|
211
|
+
* if (!isReady) return <Spinner />;
|
|
212
|
+
*
|
|
213
|
+
* return <DataDisplay data={data} onSave={write} />;
|
|
214
|
+
* }
|
|
215
|
+
* ```
|
|
216
|
+
*
|
|
217
|
+
* @example CRUD-like operations
|
|
218
|
+
* ```tsx
|
|
219
|
+
* interface TodoList {
|
|
220
|
+
* items: Array<{ id: string; text: string; done: boolean }>;
|
|
221
|
+
* }
|
|
222
|
+
*
|
|
223
|
+
* function TodoApp() {
|
|
224
|
+
* const { data, write, isLoading, isWriting } =
|
|
225
|
+
* useSPFxOneDriveAppData<TodoList>('todos.json', 'todo-app');
|
|
226
|
+
*
|
|
227
|
+
* const addTodo = async (text: string) => {
|
|
228
|
+
* const newItem = { id: crypto.randomUUID(), text, done: false };
|
|
229
|
+
* await write({
|
|
230
|
+
* items: [...(data?.items ?? []), newItem]
|
|
231
|
+
* });
|
|
232
|
+
* };
|
|
233
|
+
*
|
|
234
|
+
* const toggleTodo = async (id: string) => {
|
|
235
|
+
* await write({
|
|
236
|
+
* items: data?.items.map(item =>
|
|
237
|
+
* item.id === id ? { ...item, done: !item.done } : item
|
|
238
|
+
* ) ?? []
|
|
239
|
+
* });
|
|
240
|
+
* };
|
|
241
|
+
*
|
|
242
|
+
* const deleteTodo = async (id: string) => {
|
|
243
|
+
* await write({
|
|
244
|
+
* items: data?.items.filter(item => item.id !== id) ?? []
|
|
245
|
+
* });
|
|
246
|
+
* };
|
|
247
|
+
*
|
|
248
|
+
* if (isLoading) return <Spinner />;
|
|
249
|
+
*
|
|
250
|
+
* return (
|
|
251
|
+
* <div>
|
|
252
|
+
* <TodoList
|
|
253
|
+
* items={data?.items ?? []}
|
|
254
|
+
* onToggle={toggleTodo}
|
|
255
|
+
* onDelete={deleteTodo}
|
|
256
|
+
* />
|
|
257
|
+
* <AddTodoForm onAdd={addTodo} disabled={isWriting} />
|
|
258
|
+
* </div>
|
|
259
|
+
* );
|
|
260
|
+
* }
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
export declare function useSPFxOneDriveAppData<T = unknown>(fileName: string, folder?: string, autoFetch?: boolean): SPFxOneDriveAppDataResult<T>;
|
|
264
|
+
//# sourceMappingURL=useSPFxOneDriveAppData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSPFxOneDriveAppData.d.ts","sourceRoot":"","sources":["../../src/hooks/useSPFxOneDriveAppData.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IAElC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,KAAK,GAAG,SAAS,CAAC;IAEvC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2LG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,GAAG,OAAO,EAChD,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,GAAE,OAAc,GACxB,yBAAyB,CAAC,CAAC,CAAC,CA4J9B"}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
// useSPFxOneDriveAppData.ts
|
|
2
|
+
// Hook to manage JSON files in OneDrive appRoot folder with state management
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
13
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
14
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
15
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
16
|
+
function step(op) {
|
|
17
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
18
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
19
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
20
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
21
|
+
switch (op[0]) {
|
|
22
|
+
case 0: case 1: t = op; break;
|
|
23
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
24
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
25
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
26
|
+
default:
|
|
27
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
28
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
29
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
30
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
31
|
+
if (t[2]) _.ops.pop();
|
|
32
|
+
_.trys.pop(); continue;
|
|
33
|
+
}
|
|
34
|
+
op = body.call(thisArg, _);
|
|
35
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
36
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
40
|
+
import { useSPFxMSGraphClient } from './useSPFxMSGraphClient';
|
|
41
|
+
/**
|
|
42
|
+
* Hook to manage JSON files in user's OneDrive appRoot folder
|
|
43
|
+
*
|
|
44
|
+
* Provides unified read/write operations for JSON data stored in OneDrive's special
|
|
45
|
+
* appRoot folder (accessible per-app, user-scoped storage).
|
|
46
|
+
*
|
|
47
|
+
* Features:
|
|
48
|
+
* - Automatic JSON serialization/deserialization
|
|
49
|
+
* - Separate loading states for read/write operations
|
|
50
|
+
* - Optional auto-fetch on mount
|
|
51
|
+
* - Folder/namespace support for file organization
|
|
52
|
+
* - Type-safe with TypeScript generics
|
|
53
|
+
* - Memory leak safe with mounted state tracking
|
|
54
|
+
* - Error handling for both read and write operations
|
|
55
|
+
*
|
|
56
|
+
* Requirements:
|
|
57
|
+
* - Microsoft Graph permissions: Files.ReadWrite or Files.ReadWrite.AppFolder
|
|
58
|
+
* - User must be authenticated
|
|
59
|
+
*
|
|
60
|
+
* @param fileName - Name of the JSON file (e.g., 'config.json', 'settings.json')
|
|
61
|
+
* @param folder - Optional folder/namespace identifier for file organization.
|
|
62
|
+
* Will be sanitized to prevent path traversal.
|
|
63
|
+
* Examples: 'my-app', instanceId (GUID), 'config-v2'
|
|
64
|
+
* @param autoFetch - Whether to automatically load file on mount. Default: true
|
|
65
|
+
*
|
|
66
|
+
* @returns Object with data, loading states, error states, and read/write functions
|
|
67
|
+
*
|
|
68
|
+
* @example Basic usage - auto-fetch from root
|
|
69
|
+
* ```tsx
|
|
70
|
+
* import type { MyConfig } from './types';
|
|
71
|
+
*
|
|
72
|
+
* function ConfigPanel() {
|
|
73
|
+
* const { data, isLoading, error, write, isWriting } =
|
|
74
|
+
* useSPFxOneDriveAppData<MyConfig>('config.json');
|
|
75
|
+
*
|
|
76
|
+
* if (isLoading) return <Spinner label="Loading configuration..." />;
|
|
77
|
+
* if (error) return <MessageBar messageBarType={MessageBarType.error}>
|
|
78
|
+
* Failed to load: {error.message}
|
|
79
|
+
* </MessageBar>;
|
|
80
|
+
*
|
|
81
|
+
* const handleSave = async (newConfig: MyConfig) => {
|
|
82
|
+
* try {
|
|
83
|
+
* await write(newConfig);
|
|
84
|
+
* console.log('Saved successfully!');
|
|
85
|
+
* } catch (err) {
|
|
86
|
+
* console.error('Save failed:', err);
|
|
87
|
+
* }
|
|
88
|
+
* };
|
|
89
|
+
*
|
|
90
|
+
* return (
|
|
91
|
+
* <div>
|
|
92
|
+
* <TextField
|
|
93
|
+
* value={data?.title}
|
|
94
|
+
* onChange={(_, val) => handleSave({ ...data, title: val })}
|
|
95
|
+
* disabled={isWriting}
|
|
96
|
+
* />
|
|
97
|
+
* {isWriting && <Spinner label="Saving..." />}
|
|
98
|
+
* </div>
|
|
99
|
+
* );
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @example With folder namespace
|
|
104
|
+
* ```tsx
|
|
105
|
+
* // Store files in a dedicated folder
|
|
106
|
+
* const { data, write } = useSPFxOneDriveAppData<State>(
|
|
107
|
+
* 'state.json',
|
|
108
|
+
* 'my-app-v2' // Files stored in appRoot:/my-app-v2/state.json
|
|
109
|
+
* );
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @example Per-instance storage (multi-instance support)
|
|
113
|
+
* ```tsx
|
|
114
|
+
* // Each WebPart instance has its own data
|
|
115
|
+
* const { id } = useSPFxInstanceInfo();
|
|
116
|
+
* const { data, write } = useSPFxOneDriveAppData<Settings>(
|
|
117
|
+
* 'settings.json',
|
|
118
|
+
* id // Files stored in appRoot:/abc-123-guid/settings.json
|
|
119
|
+
* );
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @example Lazy loading (manual load)
|
|
123
|
+
* ```tsx
|
|
124
|
+
* const { data, load, isLoading, write } = useSPFxOneDriveAppData<Cache>(
|
|
125
|
+
* 'cache.json',
|
|
126
|
+
* 'my-app',
|
|
127
|
+
* false // Don't auto-fetch
|
|
128
|
+
* );
|
|
129
|
+
*
|
|
130
|
+
* return (
|
|
131
|
+
* <div>
|
|
132
|
+
* <button onClick={load} disabled={isLoading}>
|
|
133
|
+
* {isLoading ? 'Loading...' : 'Load Cache'}
|
|
134
|
+
* </button>
|
|
135
|
+
* {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
|
|
136
|
+
* </div>
|
|
137
|
+
* );
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* @example Multiple files in same namespace
|
|
141
|
+
* ```tsx
|
|
142
|
+
* function MyApp() {
|
|
143
|
+
* const config = useSPFxOneDriveAppData<Config>('config.json', 'myapp');
|
|
144
|
+
* const state = useSPFxOneDriveAppData<State>('state.json', 'myapp');
|
|
145
|
+
* const cache = useSPFxOneDriveAppData<Cache>('cache.json', 'myapp');
|
|
146
|
+
*
|
|
147
|
+
* // All files stored in appRoot:/myapp/
|
|
148
|
+
* // Easy to manage and clean up as a group
|
|
149
|
+
* }
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* @example Error handling and retry
|
|
153
|
+
* ```tsx
|
|
154
|
+
* function DataManager() {
|
|
155
|
+
* const { data, error, load, writeError, write, isReady } =
|
|
156
|
+
* useSPFxOneDriveAppData<MyData>('data.json');
|
|
157
|
+
*
|
|
158
|
+
* if (error) {
|
|
159
|
+
* return (
|
|
160
|
+
* <MessageBar
|
|
161
|
+
* messageBarType={MessageBarType.error}
|
|
162
|
+
* actions={<button onClick={load}>Retry</button>}
|
|
163
|
+
* >
|
|
164
|
+
* Load failed: {error.message}
|
|
165
|
+
* </MessageBar>
|
|
166
|
+
* );
|
|
167
|
+
* }
|
|
168
|
+
*
|
|
169
|
+
* if (writeError) {
|
|
170
|
+
* return (
|
|
171
|
+
* <MessageBar messageBarType={MessageBarType.warning}>
|
|
172
|
+
* Save failed: {writeError.message}
|
|
173
|
+
* </MessageBar>
|
|
174
|
+
* );
|
|
175
|
+
* }
|
|
176
|
+
*
|
|
177
|
+
* if (!isReady) return <Spinner />;
|
|
178
|
+
*
|
|
179
|
+
* return <DataDisplay data={data} onSave={write} />;
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* @example CRUD-like operations
|
|
184
|
+
* ```tsx
|
|
185
|
+
* interface TodoList {
|
|
186
|
+
* items: Array<{ id: string; text: string; done: boolean }>;
|
|
187
|
+
* }
|
|
188
|
+
*
|
|
189
|
+
* function TodoApp() {
|
|
190
|
+
* const { data, write, isLoading, isWriting } =
|
|
191
|
+
* useSPFxOneDriveAppData<TodoList>('todos.json', 'todo-app');
|
|
192
|
+
*
|
|
193
|
+
* const addTodo = async (text: string) => {
|
|
194
|
+
* const newItem = { id: crypto.randomUUID(), text, done: false };
|
|
195
|
+
* await write({
|
|
196
|
+
* items: [...(data?.items ?? []), newItem]
|
|
197
|
+
* });
|
|
198
|
+
* };
|
|
199
|
+
*
|
|
200
|
+
* const toggleTodo = async (id: string) => {
|
|
201
|
+
* await write({
|
|
202
|
+
* items: data?.items.map(item =>
|
|
203
|
+
* item.id === id ? { ...item, done: !item.done } : item
|
|
204
|
+
* ) ?? []
|
|
205
|
+
* });
|
|
206
|
+
* };
|
|
207
|
+
*
|
|
208
|
+
* const deleteTodo = async (id: string) => {
|
|
209
|
+
* await write({
|
|
210
|
+
* items: data?.items.filter(item => item.id !== id) ?? []
|
|
211
|
+
* });
|
|
212
|
+
* };
|
|
213
|
+
*
|
|
214
|
+
* if (isLoading) return <Spinner />;
|
|
215
|
+
*
|
|
216
|
+
* return (
|
|
217
|
+
* <div>
|
|
218
|
+
* <TodoList
|
|
219
|
+
* items={data?.items ?? []}
|
|
220
|
+
* onToggle={toggleTodo}
|
|
221
|
+
* onDelete={deleteTodo}
|
|
222
|
+
* />
|
|
223
|
+
* <AddTodoForm onAdd={addTodo} disabled={isWriting} />
|
|
224
|
+
* </div>
|
|
225
|
+
* );
|
|
226
|
+
* }
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
export function useSPFxOneDriveAppData(fileName, folder, autoFetch) {
|
|
230
|
+
var _this = this;
|
|
231
|
+
if (autoFetch === void 0) { autoFetch = true; }
|
|
232
|
+
var client = useSPFxMSGraphClient().client;
|
|
233
|
+
// State management
|
|
234
|
+
var _a = useState(undefined), data = _a[0], setData = _a[1];
|
|
235
|
+
var _b = useState(false), isLoading = _b[0], setIsLoading = _b[1];
|
|
236
|
+
var _c = useState(undefined), error = _c[0], setError = _c[1];
|
|
237
|
+
var _d = useState(false), isWriting = _d[0], setIsWriting = _d[1];
|
|
238
|
+
var _e = useState(undefined), writeError = _e[0], setWriteError = _e[1];
|
|
239
|
+
// Track component mounted state to prevent memory leaks
|
|
240
|
+
var isMounted = useRef(true);
|
|
241
|
+
useEffect(function () {
|
|
242
|
+
isMounted.current = true;
|
|
243
|
+
return function () {
|
|
244
|
+
isMounted.current = false;
|
|
245
|
+
};
|
|
246
|
+
}, []);
|
|
247
|
+
/**
|
|
248
|
+
* Build Graph API path with optional folder namespace
|
|
249
|
+
* Sanitizes folder name to prevent path traversal attacks
|
|
250
|
+
*/
|
|
251
|
+
var buildApiPath = useCallback(function (file, folderName) {
|
|
252
|
+
var basePath = '/me/drive/special/appRoot:';
|
|
253
|
+
if (folderName) {
|
|
254
|
+
// Sanitize folder name: only allow alphanumeric, hyphens, underscores
|
|
255
|
+
// This prevents path traversal (../) and other injection attacks
|
|
256
|
+
var safeFolderName = folderName.replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
257
|
+
return "".concat(basePath, "/").concat(safeFolderName, "/").concat(file, ":/content");
|
|
258
|
+
}
|
|
259
|
+
return "".concat(basePath, "/").concat(file, ":/content");
|
|
260
|
+
}, []);
|
|
261
|
+
/**
|
|
262
|
+
* Load file from OneDrive
|
|
263
|
+
* Updates data, isLoading, and error states
|
|
264
|
+
*/
|
|
265
|
+
var load = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
266
|
+
var apiPath, fileContent, err_1, error_1;
|
|
267
|
+
return __generator(this, function (_a) {
|
|
268
|
+
switch (_a.label) {
|
|
269
|
+
case 0:
|
|
270
|
+
if (!client) {
|
|
271
|
+
console.warn('Graph client not available yet. Skipping load.');
|
|
272
|
+
return [2 /*return*/];
|
|
273
|
+
}
|
|
274
|
+
if (!fileName) {
|
|
275
|
+
console.warn('fileName is required. Skipping load.');
|
|
276
|
+
return [2 /*return*/];
|
|
277
|
+
}
|
|
278
|
+
setIsLoading(true);
|
|
279
|
+
setError(undefined);
|
|
280
|
+
_a.label = 1;
|
|
281
|
+
case 1:
|
|
282
|
+
_a.trys.push([1, 3, 4, 5]);
|
|
283
|
+
apiPath = buildApiPath(fileName, folder);
|
|
284
|
+
return [4 /*yield*/, client.api(apiPath).get()];
|
|
285
|
+
case 2:
|
|
286
|
+
fileContent = _a.sent();
|
|
287
|
+
if (isMounted.current) {
|
|
288
|
+
// Parse JSON if response is string, otherwise use as-is
|
|
289
|
+
if (typeof fileContent === 'string') {
|
|
290
|
+
try {
|
|
291
|
+
setData(JSON.parse(fileContent));
|
|
292
|
+
}
|
|
293
|
+
catch (parseError) {
|
|
294
|
+
throw new Error("Failed to parse JSON: ".concat(parseError instanceof Error ? parseError.message : 'Unknown error'));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
setData(fileContent);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return [3 /*break*/, 5];
|
|
302
|
+
case 3:
|
|
303
|
+
err_1 = _a.sent();
|
|
304
|
+
if (isMounted.current) {
|
|
305
|
+
error_1 = err_1 instanceof Error ? err_1 : new Error(String(err_1));
|
|
306
|
+
setError(error_1);
|
|
307
|
+
// Don't throw - allow component to handle error via state
|
|
308
|
+
console.error('Failed to load file from OneDrive:', error_1);
|
|
309
|
+
}
|
|
310
|
+
return [3 /*break*/, 5];
|
|
311
|
+
case 4:
|
|
312
|
+
if (isMounted.current) {
|
|
313
|
+
setIsLoading(false);
|
|
314
|
+
}
|
|
315
|
+
return [7 /*endfinally*/];
|
|
316
|
+
case 5: return [2 /*return*/];
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}); }, [client, fileName, folder, buildApiPath]);
|
|
320
|
+
/**
|
|
321
|
+
* Write data to OneDrive file
|
|
322
|
+
* Creates file if it doesn't exist, updates if it does (upsert)
|
|
323
|
+
* Updates isWriting and writeError states
|
|
324
|
+
*/
|
|
325
|
+
var write = useCallback(function (content) { return __awaiter(_this, void 0, void 0, function () {
|
|
326
|
+
var apiPath, jsonContent, err_2, error_2;
|
|
327
|
+
return __generator(this, function (_a) {
|
|
328
|
+
switch (_a.label) {
|
|
329
|
+
case 0:
|
|
330
|
+
if (!client) {
|
|
331
|
+
throw new Error('Graph client not available. Cannot write file.');
|
|
332
|
+
}
|
|
333
|
+
if (!fileName) {
|
|
334
|
+
throw new Error('fileName is required. Cannot write file.');
|
|
335
|
+
}
|
|
336
|
+
setIsWriting(true);
|
|
337
|
+
setWriteError(undefined);
|
|
338
|
+
_a.label = 1;
|
|
339
|
+
case 1:
|
|
340
|
+
_a.trys.push([1, 3, 4, 5]);
|
|
341
|
+
apiPath = buildApiPath(fileName, folder);
|
|
342
|
+
jsonContent = JSON.stringify(content);
|
|
343
|
+
return [4 /*yield*/, client
|
|
344
|
+
.api(apiPath)
|
|
345
|
+
.header('Content-Type', 'application/json')
|
|
346
|
+
.put(jsonContent)];
|
|
347
|
+
case 2:
|
|
348
|
+
_a.sent();
|
|
349
|
+
if (isMounted.current) {
|
|
350
|
+
// Update local data to reflect successful write
|
|
351
|
+
setData(content);
|
|
352
|
+
// Clear read error if write succeeds (fresh state)
|
|
353
|
+
setError(undefined);
|
|
354
|
+
}
|
|
355
|
+
return [3 /*break*/, 5];
|
|
356
|
+
case 3:
|
|
357
|
+
err_2 = _a.sent();
|
|
358
|
+
if (isMounted.current) {
|
|
359
|
+
error_2 = err_2 instanceof Error ? err_2 : new Error(String(err_2));
|
|
360
|
+
setWriteError(error_2);
|
|
361
|
+
console.error('Failed to write file to OneDrive:', error_2);
|
|
362
|
+
}
|
|
363
|
+
// Re-throw to allow caller to handle
|
|
364
|
+
throw err_2;
|
|
365
|
+
case 4:
|
|
366
|
+
if (isMounted.current) {
|
|
367
|
+
setIsWriting(false);
|
|
368
|
+
}
|
|
369
|
+
return [7 /*endfinally*/];
|
|
370
|
+
case 5: return [2 /*return*/];
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}); }, [client, fileName, folder, buildApiPath]);
|
|
374
|
+
// Auto-fetch on mount if enabled
|
|
375
|
+
useEffect(function () {
|
|
376
|
+
if (autoFetch && client && fileName) {
|
|
377
|
+
load().catch(function () {
|
|
378
|
+
// Error already handled in load() function
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}, [autoFetch, client, fileName, load]);
|
|
382
|
+
// Computed state: ready when data loaded successfully
|
|
383
|
+
var isReady = !isLoading && !error && data !== undefined;
|
|
384
|
+
return {
|
|
385
|
+
data: data,
|
|
386
|
+
isLoading: isLoading,
|
|
387
|
+
error: error,
|
|
388
|
+
isWriting: isWriting,
|
|
389
|
+
writeError: writeError,
|
|
390
|
+
load: load,
|
|
391
|
+
write: write,
|
|
392
|
+
isReady: isReady,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
//# sourceMappingURL=useSPFxOneDriveAppData.js.map
|
|
@@ -0,0 +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;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAoF9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2LG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAgB,EAChB,MAAe,EACf,SAAyB;IAH3B,iBAgKC;IA7JC,0BAAA,EAAA,gBAAyB;IAEjB,IAAA,MAAM,GAAK,oBAAoB,EAAE,OAA3B,CAA4B;IAE1C,mBAAmB;IACb,IAAA,KAAkB,QAAQ,CAAgB,SAAS,CAAC,EAAnD,IAAI,QAAA,EAAE,OAAO,QAAsC,CAAC;IACrD,IAAA,KAA4B,QAAQ,CAAU,KAAK,CAAC,EAAnD,SAAS,QAAA,EAAE,YAAY,QAA4B,CAAC;IACrD,IAAA,KAAoB,QAAQ,CAAoB,SAAS,CAAC,EAAzD,KAAK,QAAA,EAAE,QAAQ,QAA0C,CAAC;IAC3D,IAAA,KAA4B,QAAQ,CAAU,KAAK,CAAC,EAAnD,SAAS,QAAA,EAAE,YAAY,QAA4B,CAAC;IACrD,IAAA,KAA8B,QAAQ,CAAoB,SAAS,CAAC,EAAnE,UAAU,QAAA,EAAE,aAAa,QAA0C,CAAC;IAE3E,wDAAwD;IACxD,IAAM,SAAS,GAAG,MAAM,CAAU,IAAI,CAAC,CAAC;IAExC,SAAS,CAAC;QACR,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,OAAO;YACL,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP;;;OAGG;IACH,IAAM,YAAY,GAAG,WAAW,CAAC,UAAC,IAAY,EAAE,UAAmB;QACjE,IAAM,QAAQ,GAAG,4BAA4B,CAAC;QAE9C,IAAI,UAAU,EAAE,CAAC;YACf,sEAAsE;YACtE,iEAAiE;YACjE,IAAM,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;YAClE,OAAO,UAAG,QAAQ,cAAI,cAAc,cAAI,IAAI,cAAW,CAAC;QAC1D,CAAC;QAED,OAAO,UAAG,QAAQ,cAAI,IAAI,cAAW,CAAC;IACxC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP;;;OAGG;IACH,IAAM,IAAI,GAAG,WAAW,CAAC;;;;;oBACvB,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;wBAC/D,sBAAO;oBACT,CAAC;oBAED,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACd,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;wBACrD,sBAAO;oBACT,CAAC;oBAED,YAAY,CAAC,IAAI,CAAC,CAAC;oBACnB,QAAQ,CAAC,SAAS,CAAC,CAAC;;;;oBAGZ,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAC3B,qBAAM,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAA;;oBAA7C,WAAW,GAAG,SAA+B;oBAEnD,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBACtB,wDAAwD;wBACxD,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;4BACpC,IAAI,CAAC;gCACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAM,CAAC,CAAC;4BACxC,CAAC;4BAAC,OAAO,UAAU,EAAE,CAAC;gCACpB,MAAM,IAAI,KAAK,CAAC,gCAAyB,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAE,CAAC,CAAC;4BACjH,CAAC;wBACH,CAAC;6BAAM,CAAC;4BACN,OAAO,CAAC,WAAgB,CAAC,CAAC;wBAC5B,CAAC;oBACH,CAAC;;;;oBAED,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBAChB,UAAQ,KAAG,YAAY,KAAK,CAAC,CAAC,CAAC,KAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAG,CAAC,CAAC,CAAC;wBAClE,QAAQ,CAAC,OAAK,CAAC,CAAC;wBAChB,0DAA0D;wBAC1D,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,OAAK,CAAC,CAAC;oBAC7D,CAAC;;;oBAED,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBACtB,YAAY,CAAC,KAAK,CAAC,CAAC;oBACtB,CAAC;;;;;SAEJ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAE7C;;;;OAIG;IACH,IAAM,KAAK,GAAG,WAAW,CAAC,UAAO,OAAU;;;;;oBACzC,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;oBACpE,CAAC;oBAED,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACd,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;oBAC9D,CAAC;oBAED,YAAY,CAAC,IAAI,CAAC,CAAC;oBACnB,aAAa,CAAC,SAAS,CAAC,CAAC;;;;oBAGjB,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAGzC,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;oBAE5C,qBAAM,MAAM;6BACT,GAAG,CAAC,OAAO,CAAC;6BACZ,MAAM,CAAC,cAAc,EAAE,kBAAkB,CAAC;6BAC1C,GAAG,CAAC,WAAW,CAAC,EAAA;;oBAHnB,SAGmB,CAAC;oBAEpB,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBACtB,gDAAgD;wBAChD,OAAO,CAAC,OAAO,CAAC,CAAC;wBACjB,mDAAmD;wBACnD,QAAQ,CAAC,SAAS,CAAC,CAAC;oBACtB,CAAC;;;;oBAED,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBAChB,UAAQ,KAAG,YAAY,KAAK,CAAC,CAAC,CAAC,KAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAG,CAAC,CAAC,CAAC;wBAClE,aAAa,CAAC,OAAK,CAAC,CAAC;wBACrB,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,OAAK,CAAC,CAAC;oBAC5D,CAAC;oBACD,qCAAqC;oBACrC,MAAM,KAAG,CAAC;;oBAEV,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBACtB,YAAY,CAAC,KAAK,CAAC,CAAC;oBACtB,CAAC;;;;;SAEJ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAE7C,iCAAiC;IACjC,SAAS,CAAC;QACR,IAAI,SAAS,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;YACpC,IAAI,EAAE,CAAC,KAAK,CAAC;gBACX,2CAA2C;YAC7C,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAExC,sDAAsD;IACtD,IAAM,OAAO,GAAG,CAAC,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,SAAS,CAAC;IAE3D,OAAO;QACL,IAAI,MAAA;QACJ,SAAS,WAAA;QACT,KAAK,OAAA;QACL,SAAS,WAAA;QACT,UAAU,YAAA;QACV,IAAI,MAAA;QACJ,KAAK,OAAA;QACL,OAAO,SAAA;KACR,CAAC;AACJ,CAAC"}
|