@contember/react-client 0.7.0-alpha.20
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 +186 -0
- package/dist/development/ClientError.js +5 -0
- package/dist/development/ClientError.js.map +1 -0
- package/dist/development/ContemberClient.js +30 -0
- package/dist/development/ContemberClient.js.map +1 -0
- package/dist/development/apiRequest/apiRequestReducer.js +33 -0
- package/dist/development/apiRequest/apiRequestReducer.js.map +1 -0
- package/dist/development/apiRequest/useApiRequest.js +43 -0
- package/dist/development/apiRequest/useApiRequest.js.map +1 -0
- package/dist/development/auth/SessionTokenContext.js +6 -0
- package/dist/development/auth/SessionTokenContext.js.map +1 -0
- package/dist/development/auth/useLoginRequest.js +18 -0
- package/dist/development/auth/useLoginRequest.js.map +1 -0
- package/dist/development/auth/useSessionToken.js +7 -0
- package/dist/development/auth/useSessionToken.js.map +1 -0
- package/dist/development/components/RichTextRenderer/ElementRenderer.js +25 -0
- package/dist/development/components/RichTextRenderer/ElementRenderer.js.map +1 -0
- package/dist/development/components/RichTextRenderer/LeafRenderer.js +21 -0
- package/dist/development/components/RichTextRenderer/LeafRenderer.js.map +1 -0
- package/dist/development/components/RichTextRenderer/RenderElementFallback.js +107 -0
- package/dist/development/components/RichTextRenderer/RenderElementFallback.js.map +1 -0
- package/dist/development/components/RichTextRenderer/RenderLeafFallback.js +36 -0
- package/dist/development/components/RichTextRenderer/RenderLeafFallback.js.map +1 -0
- package/dist/development/components/RichTextRenderer/RichTextRenderMetadataContext.js +14 -0
- package/dist/development/components/RichTextRenderer/RichTextRenderMetadataContext.js.map +1 -0
- package/dist/development/components/RichTextRenderer/RichTextRenderer.js +91 -0
- package/dist/development/components/RichTextRenderer/RichTextRenderer.js.map +1 -0
- package/dist/development/components/RichTextRenderer/RichTextRendererError.js +5 -0
- package/dist/development/components/RichTextRenderer/RichTextRendererError.js.map +1 -0
- package/dist/development/components/RichTextRenderer/defaultDeserialize.js +13 -0
- package/dist/development/components/RichTextRenderer/defaultDeserialize.js.map +1 -0
- package/dist/development/components/RichTextRenderer/renderChildren.js +29 -0
- package/dist/development/components/RichTextRenderer/renderChildren.js.map +1 -0
- package/dist/development/components/RichTextRenderer/resolveRichTextElementMetadata.js +27 -0
- package/dist/development/components/RichTextRenderer/resolveRichTextElementMetadata.js.map +1 -0
- package/dist/development/config/ApiBaseUrlContext.js +6 -0
- package/dist/development/config/ApiBaseUrlContext.js.map +1 -0
- package/dist/development/config/LoginTokenContext.js +6 -0
- package/dist/development/config/LoginTokenContext.js.map +1 -0
- package/dist/development/config/useApiBaseUrl.js +7 -0
- package/dist/development/config/useApiBaseUrl.js.map +1 -0
- package/dist/development/config/useLoginToken.js +7 -0
- package/dist/development/config/useLoginToken.js.map +1 -0
- package/dist/development/content/useContentApiRequest.js +7 -0
- package/dist/development/content/useContentApiRequest.js.map +1 -0
- package/dist/development/content/useContentGraphQlClient.js +7 -0
- package/dist/development/content/useContentGraphQlClient.js.map +1 -0
- package/dist/development/content/useCurrentContentGraphQlClient.js +19 -0
- package/dist/development/content/useCurrentContentGraphQlClient.js.map +1 -0
- package/dist/development/index.js +31 -0
- package/dist/development/index.js.map +1 -0
- package/dist/development/project/ProjectSlugContext.js +6 -0
- package/dist/development/project/ProjectSlugContext.js.map +1 -0
- package/dist/development/project/StageSlugContext.js +6 -0
- package/dist/development/project/StageSlugContext.js.map +1 -0
- package/dist/development/project/useProjectSlug.js +7 -0
- package/dist/development/project/useProjectSlug.js.map +1 -0
- package/dist/development/project/useStageSlug.js +7 -0
- package/dist/development/project/useStageSlug.js.map +1 -0
- package/dist/development/system/useCurrentSystemGraphQlClient.js +14 -0
- package/dist/development/system/useCurrentSystemGraphQlClient.js.map +1 -0
- package/dist/development/system/useDiffQuery.js +17 -0
- package/dist/development/system/useDiffQuery.js.map +1 -0
- package/dist/development/system/useReleaseTreeMutation.js +17 -0
- package/dist/development/system/useReleaseTreeMutation.js.map +1 -0
- package/dist/development/system/useSystemApiRequest.js +7 -0
- package/dist/development/system/useSystemApiRequest.js.map +1 -0
- package/dist/development/system/useSystemGraphQlClient.js +7 -0
- package/dist/development/system/useSystemGraphQlClient.js.map +1 -0
- package/dist/development/tenant/useTenantApiRequest.js +7 -0
- package/dist/development/tenant/useTenantApiRequest.js.map +1 -0
- package/dist/development/tenant/useTenantGraphQlClient.js +7 -0
- package/dist/development/tenant/useTenantGraphQlClient.js.map +1 -0
- package/dist/development/upload/fileUploadReducer.js +162 -0
- package/dist/development/upload/fileUploadReducer.js.map +1 -0
- package/dist/development/upload/toFileId.js +9 -0
- package/dist/development/upload/toFileId.js.map +1 -0
- package/dist/development/upload/useFileUpload.js +192 -0
- package/dist/development/upload/useFileUpload.js.map +1 -0
- package/dist/development/useGraphQlClient.js +13 -0
- package/dist/development/useGraphQlClient.js.map +1 -0
- package/dist/development/utils/assertNever.js +6 -0
- package/dist/development/utils/assertNever.js.map +1 -0
- package/dist/production/ClientError.js +4 -0
- package/dist/production/ClientError.js.map +1 -0
- package/dist/production/ContemberClient.js +28 -0
- package/dist/production/ContemberClient.js.map +1 -0
- package/dist/production/apiRequest/apiRequestReducer.js +32 -0
- package/dist/production/apiRequest/apiRequestReducer.js.map +1 -0
- package/dist/production/apiRequest/useApiRequest.js +41 -0
- package/dist/production/apiRequest/useApiRequest.js.map +1 -0
- package/dist/production/auth/SessionTokenContext.js +4 -0
- package/dist/production/auth/SessionTokenContext.js.map +1 -0
- package/dist/production/auth/useLoginRequest.js +16 -0
- package/dist/production/auth/useLoginRequest.js.map +1 -0
- package/dist/production/auth/useSessionToken.js +5 -0
- package/dist/production/auth/useSessionToken.js.map +1 -0
- package/dist/production/components/RichTextRenderer/ElementRenderer.js +23 -0
- package/dist/production/components/RichTextRenderer/ElementRenderer.js.map +1 -0
- package/dist/production/components/RichTextRenderer/LeafRenderer.js +19 -0
- package/dist/production/components/RichTextRenderer/LeafRenderer.js.map +1 -0
- package/dist/production/components/RichTextRenderer/RenderElementFallback.js +104 -0
- package/dist/production/components/RichTextRenderer/RenderElementFallback.js.map +1 -0
- package/dist/production/components/RichTextRenderer/RenderLeafFallback.js +34 -0
- package/dist/production/components/RichTextRenderer/RenderLeafFallback.js.map +1 -0
- package/dist/production/components/RichTextRenderer/RichTextRenderMetadataContext.js +12 -0
- package/dist/production/components/RichTextRenderer/RichTextRenderMetadataContext.js.map +1 -0
- package/dist/production/components/RichTextRenderer/RichTextRenderer.js +89 -0
- package/dist/production/components/RichTextRenderer/RichTextRenderer.js.map +1 -0
- package/dist/production/components/RichTextRenderer/RichTextRendererError.js +4 -0
- package/dist/production/components/RichTextRenderer/RichTextRendererError.js.map +1 -0
- package/dist/production/components/RichTextRenderer/defaultDeserialize.js +12 -0
- package/dist/production/components/RichTextRenderer/defaultDeserialize.js.map +1 -0
- package/dist/production/components/RichTextRenderer/renderChildren.js +27 -0
- package/dist/production/components/RichTextRenderer/renderChildren.js.map +1 -0
- package/dist/production/components/RichTextRenderer/resolveRichTextElementMetadata.js +25 -0
- package/dist/production/components/RichTextRenderer/resolveRichTextElementMetadata.js.map +1 -0
- package/dist/production/config/ApiBaseUrlContext.js +4 -0
- package/dist/production/config/ApiBaseUrlContext.js.map +1 -0
- package/dist/production/config/LoginTokenContext.js +4 -0
- package/dist/production/config/LoginTokenContext.js.map +1 -0
- package/dist/production/config/useApiBaseUrl.js +5 -0
- package/dist/production/config/useApiBaseUrl.js.map +1 -0
- package/dist/production/config/useLoginToken.js +5 -0
- package/dist/production/config/useLoginToken.js.map +1 -0
- package/dist/production/content/useContentApiRequest.js +5 -0
- package/dist/production/content/useContentApiRequest.js.map +1 -0
- package/dist/production/content/useContentGraphQlClient.js +5 -0
- package/dist/production/content/useContentGraphQlClient.js.map +1 -0
- package/dist/production/content/useCurrentContentGraphQlClient.js +17 -0
- package/dist/production/content/useCurrentContentGraphQlClient.js.map +1 -0
- package/dist/production/index.js +31 -0
- package/dist/production/index.js.map +1 -0
- package/dist/production/project/ProjectSlugContext.js +4 -0
- package/dist/production/project/ProjectSlugContext.js.map +1 -0
- package/dist/production/project/StageSlugContext.js +4 -0
- package/dist/production/project/StageSlugContext.js.map +1 -0
- package/dist/production/project/useProjectSlug.js +5 -0
- package/dist/production/project/useProjectSlug.js.map +1 -0
- package/dist/production/project/useStageSlug.js +5 -0
- package/dist/production/project/useStageSlug.js.map +1 -0
- package/dist/production/system/useCurrentSystemGraphQlClient.js +12 -0
- package/dist/production/system/useCurrentSystemGraphQlClient.js.map +1 -0
- package/dist/production/system/useDiffQuery.js +15 -0
- package/dist/production/system/useDiffQuery.js.map +1 -0
- package/dist/production/system/useReleaseTreeMutation.js +15 -0
- package/dist/production/system/useReleaseTreeMutation.js.map +1 -0
- package/dist/production/system/useSystemApiRequest.js +5 -0
- package/dist/production/system/useSystemApiRequest.js.map +1 -0
- package/dist/production/system/useSystemGraphQlClient.js +5 -0
- package/dist/production/system/useSystemGraphQlClient.js.map +1 -0
- package/dist/production/tenant/useTenantApiRequest.js +5 -0
- package/dist/production/tenant/useTenantApiRequest.js.map +1 -0
- package/dist/production/tenant/useTenantGraphQlClient.js +5 -0
- package/dist/production/tenant/useTenantGraphQlClient.js.map +1 -0
- package/dist/production/upload/fileUploadReducer.js +160 -0
- package/dist/production/upload/fileUploadReducer.js.map +1 -0
- package/dist/production/upload/toFileId.js +8 -0
- package/dist/production/upload/toFileId.js.map +1 -0
- package/dist/production/upload/useFileUpload.js +190 -0
- package/dist/production/upload/useFileUpload.js.map +1 -0
- package/dist/production/useGraphQlClient.js +11 -0
- package/dist/production/useGraphQlClient.js.map +1 -0
- package/dist/production/utils/assertNever.js +5 -0
- package/dist/production/utils/assertNever.js.map +1 -0
- package/dist/react-client.d.ts +370 -0
- package/package.json +31 -0
- package/readme.md +22 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCurrentSystemGraphQlClient.js","sources":["../../../src/system/useCurrentSystemGraphQlClient.ts"],"sourcesContent":["import type { GraphQlClient } from '@contember/client'\nimport { ClientError } from '../ClientError'\nimport { useProjectSlug } from '../project'\nimport { useSystemGraphQlClient } from './useSystemGraphQlClient'\n\nexport const useCurrentSystemGraphQlClient = (): GraphQlClient => {\n\tconst projectSlug = useProjectSlug()\n\n\tif (projectSlug === undefined) {\n\t\tthrow new ClientError(`Cannot contact the system API: undefined project slug.`)\n\t}\n\treturn useSystemGraphQlClient(projectSlug)\n}\n"],"names":[],"mappings":";;;;MAKa,gCAAgC,MAAqB;AACjE,QAAM,cAAc;AAEpB,MAAI,gBAAgB,QAAW;AAC9B,UAAM,IAAI,YAAY;AAAA;AAEvB,SAAO,uBAAuB;AAAA;;;;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { diffQuery } from '@contember/client';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { useSystemApiRequest } from './useSystemApiRequest.js';
|
|
4
|
+
import { useStageSlug } from '../project/useStageSlug.js';
|
|
5
|
+
|
|
6
|
+
const useDiffQuery = () => {
|
|
7
|
+
const [requestState, sendRequest] = useSystemApiRequest();
|
|
8
|
+
const stage = useStageSlug();
|
|
9
|
+
const sendQuery = useCallback((treeFilter) => sendRequest(diffQuery, {
|
|
10
|
+
stage,
|
|
11
|
+
filter: treeFilter
|
|
12
|
+
}), [stage, sendRequest]);
|
|
13
|
+
return [requestState, sendQuery];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export { useDiffQuery };
|
|
17
|
+
//# sourceMappingURL=useDiffQuery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDiffQuery.js","sources":["../../../src/system/useDiffQuery.ts"],"sourcesContent":["import { diffQuery, DiffQueryResponse, TreeFilter } from '@contember/client'\nimport { useCallback } from 'react'\nimport type { ApiRequestState } from '../apiRequest'\nimport { useStageSlug } from '../project'\nimport { useSystemApiRequest } from './useSystemApiRequest'\n\nexport const useDiffQuery = (): [\n\tApiRequestState<DiffQueryResponse>,\n\t(treeFilter: TreeFilter[]) => Promise<DiffQueryResponse>,\n] => {\n\tconst [requestState, sendRequest] = useSystemApiRequest<DiffQueryResponse>()\n\tconst stage = useStageSlug()\n\tconst sendQuery = useCallback(\n\t\t(treeFilter: TreeFilter[]) =>\n\t\t\tsendRequest(diffQuery, {\n\t\t\t\tstage,\n\t\t\t\tfilter: treeFilter,\n\t\t\t}),\n\t\t[stage, sendRequest],\n\t)\n\n\treturn [requestState, sendQuery]\n}\n"],"names":[],"mappings":";;;;;MAMa,eAAe,MAGvB;AACJ,QAAM,CAAC,cAAc,eAAe;AACpC,QAAM,QAAQ;AACd,QAAM,YAAY,YACjB,CAAC,eACA,YAAY,WAAW;AAAA,IACtB;AAAA,IACA,QAAQ;AAAA,MAEV,CAAC,OAAO;AAGT,SAAO,CAAC,cAAc;AAAA;;;;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { releaseTreeMutation } from '@contember/client';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { useSystemApiRequest } from './useSystemApiRequest.js';
|
|
4
|
+
import { useStageSlug } from '../project/useStageSlug.js';
|
|
5
|
+
|
|
6
|
+
const useReleaseTreeMutation = () => {
|
|
7
|
+
const [requestState, sendRequest] = useSystemApiRequest();
|
|
8
|
+
const stage = useStageSlug();
|
|
9
|
+
const sendMutation = useCallback((treeFilter) => sendRequest(releaseTreeMutation, {
|
|
10
|
+
stage,
|
|
11
|
+
filter: treeFilter
|
|
12
|
+
}), [stage, sendRequest]);
|
|
13
|
+
return [requestState, sendMutation];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export { useReleaseTreeMutation };
|
|
17
|
+
//# sourceMappingURL=useReleaseTreeMutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReleaseTreeMutation.js","sources":["../../../src/system/useReleaseTreeMutation.ts"],"sourcesContent":["import { releaseTreeMutation, ReleaseTreeMutationResponse, TreeFilter } from '@contember/client'\nimport { useCallback } from 'react'\nimport type { ApiRequestState } from '../apiRequest'\nimport { useStageSlug } from '../project'\nimport { useSystemApiRequest } from './useSystemApiRequest'\n\nexport const useReleaseTreeMutation = (): [\n\tApiRequestState<ReleaseTreeMutationResponse>,\n\t(treeFilter: TreeFilter[]) => Promise<ReleaseTreeMutationResponse>,\n] => {\n\tconst [requestState, sendRequest] = useSystemApiRequest<ReleaseTreeMutationResponse>()\n\tconst stage = useStageSlug()\n\tconst sendMutation = useCallback(\n\t\t(treeFilter: TreeFilter[]) =>\n\t\t\tsendRequest(releaseTreeMutation, {\n\t\t\t\tstage,\n\t\t\t\tfilter: treeFilter,\n\t\t\t}),\n\t\t[stage, sendRequest],\n\t)\n\n\treturn [requestState, sendMutation]\n}\n"],"names":[],"mappings":";;;;;MAMa,yBAAyB,MAGjC;AACJ,QAAM,CAAC,cAAc,eAAe;AACpC,QAAM,QAAQ;AACd,QAAM,eAAe,YACpB,CAAC,eACA,YAAY,qBAAqB;AAAA,IAChC;AAAA,IACA,QAAQ;AAAA,MAEV,CAAC,OAAO;AAGT,SAAO,CAAC,cAAc;AAAA;;;;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { useCurrentSystemGraphQlClient } from './useCurrentSystemGraphQlClient.js';
|
|
2
|
+
import { useApiRequest } from '../apiRequest/useApiRequest.js';
|
|
3
|
+
|
|
4
|
+
const useSystemApiRequest = () => useApiRequest(useCurrentSystemGraphQlClient());
|
|
5
|
+
|
|
6
|
+
export { useSystemApiRequest };
|
|
7
|
+
//# sourceMappingURL=useSystemApiRequest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSystemApiRequest.js","sources":["../../../src/system/useSystemApiRequest.ts"],"sourcesContent":["import type { UseApiRequestResult } from '../apiRequest'\nimport { useApiRequest } from '../apiRequest'\nimport { useCurrentSystemGraphQlClient } from './useCurrentSystemGraphQlClient'\n\nexport const useSystemApiRequest = <SuccessData>(): UseApiRequestResult<SuccessData> =>\n\tuseApiRequest<SuccessData>(useCurrentSystemGraphQlClient())\n"],"names":[],"mappings":";;;MAIa,sBAAsB,MAClC,cAA2B;;;;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { formatSystemApiRelativeUrl } from '@contember/client';
|
|
2
|
+
import { useGraphQlClient } from '../useGraphQlClient.js';
|
|
3
|
+
|
|
4
|
+
const useSystemGraphQlClient = (projectSlug) => useGraphQlClient(formatSystemApiRelativeUrl(projectSlug));
|
|
5
|
+
|
|
6
|
+
export { useSystemGraphQlClient };
|
|
7
|
+
//# sourceMappingURL=useSystemGraphQlClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSystemGraphQlClient.js","sources":["../../../src/system/useSystemGraphQlClient.ts"],"sourcesContent":["import { formatSystemApiRelativeUrl } from '@contember/client'\nimport { useGraphQlClient } from '../useGraphQlClient'\n\nexport const useSystemGraphQlClient = (projectSlug: string) => useGraphQlClient(formatSystemApiRelativeUrl(projectSlug))\n"],"names":[],"mappings":";;;MAGa,yBAAyB,CAAC,gBAAwB,iBAAiB,2BAA2B;;;;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { useTenantGraphQlClient } from './useTenantGraphQlClient.js';
|
|
2
|
+
import { useApiRequest } from '../apiRequest/useApiRequest.js';
|
|
3
|
+
|
|
4
|
+
const useTenantApiRequest = () => useApiRequest(useTenantGraphQlClient());
|
|
5
|
+
|
|
6
|
+
export { useTenantApiRequest };
|
|
7
|
+
//# sourceMappingURL=useTenantApiRequest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTenantApiRequest.js","sources":["../../../src/tenant/useTenantApiRequest.ts"],"sourcesContent":["import type { UseApiRequestResult } from '../apiRequest'\nimport { useApiRequest } from '../apiRequest'\nimport { useTenantGraphQlClient } from './useTenantGraphQlClient'\n\nexport const useTenantApiRequest = <SuccessData>(): UseApiRequestResult<SuccessData> =>\n\tuseApiRequest<SuccessData>(useTenantGraphQlClient())\n"],"names":[],"mappings":";;;MAIa,sBAAsB,MAClC,cAA2B;;;;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { tenantApiRelativeUrl } from '@contember/client';
|
|
2
|
+
import { useGraphQlClient } from '../useGraphQlClient.js';
|
|
3
|
+
|
|
4
|
+
const useTenantGraphQlClient = () => useGraphQlClient(tenantApiRelativeUrl);
|
|
5
|
+
|
|
6
|
+
export { useTenantGraphQlClient };
|
|
7
|
+
//# sourceMappingURL=useTenantGraphQlClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTenantGraphQlClient.js","sources":["../../../src/tenant/useTenantGraphQlClient.ts"],"sourcesContent":["import { tenantApiRelativeUrl } from '@contember/client'\nimport { useGraphQlClient } from '../useGraphQlClient'\n\nexport const useTenantGraphQlClient = () => useGraphQlClient(tenantApiRelativeUrl)\n"],"names":[],"mappings":";;;MAGa,yBAAyB,MAAM,iBAAiB;;;;"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { FileUploadError } from '@contember/client';
|
|
2
|
+
import { toFileId } from './toFileId.js';
|
|
3
|
+
import { assertNever } from '../utils/assertNever.js';
|
|
4
|
+
|
|
5
|
+
const initializeFileUploadState = () => ({
|
|
6
|
+
lastUpdateTime: 0,
|
|
7
|
+
fileIdByFile: new WeakMap(),
|
|
8
|
+
liveState: new Map(),
|
|
9
|
+
publicState: new Map(),
|
|
10
|
+
isLiveStateDirty: false
|
|
11
|
+
});
|
|
12
|
+
const fileUploadReducer = (previousState, action) => {
|
|
13
|
+
const publishNewState = () => ({
|
|
14
|
+
publicState: previousState.liveState,
|
|
15
|
+
fileIdByFile: previousState.fileIdByFile,
|
|
16
|
+
lastUpdateTime: previousState.lastUpdateTime,
|
|
17
|
+
isLiveStateDirty: false,
|
|
18
|
+
liveState: new Map(previousState.liveState)
|
|
19
|
+
});
|
|
20
|
+
const getNewDirtyState = () => ({
|
|
21
|
+
fileIdByFile: previousState.fileIdByFile,
|
|
22
|
+
liveState: previousState.liveState,
|
|
23
|
+
publicState: previousState.publicState,
|
|
24
|
+
isLiveStateDirty: true,
|
|
25
|
+
lastUpdateTime: Date.now()
|
|
26
|
+
});
|
|
27
|
+
switch (action.type) {
|
|
28
|
+
case "publishNewestState": {
|
|
29
|
+
return publishNewState();
|
|
30
|
+
}
|
|
31
|
+
case "initialize": {
|
|
32
|
+
for (const [fileId, metadata] of action.files) {
|
|
33
|
+
previousState.liveState.set(fileId, {
|
|
34
|
+
readyState: "initializing",
|
|
35
|
+
abortController: metadata.abortController,
|
|
36
|
+
previewUrl: metadata.previewUrl,
|
|
37
|
+
file: metadata.file
|
|
38
|
+
});
|
|
39
|
+
previousState.fileIdByFile.set(metadata.file, fileId);
|
|
40
|
+
}
|
|
41
|
+
return publishNewState();
|
|
42
|
+
}
|
|
43
|
+
case "startUploading": {
|
|
44
|
+
for (const [fileOrId, metadata] of action.files) {
|
|
45
|
+
const fileId = toFileId(previousState, fileOrId);
|
|
46
|
+
const fileState = previousState.liveState.get(fileId);
|
|
47
|
+
if (fileState === void 0 || fileState.readyState !== "initializing") {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
previousState.liveState.set(fileId, {
|
|
51
|
+
readyState: "uploading",
|
|
52
|
+
abortController: fileState.abortController,
|
|
53
|
+
file: fileState.file,
|
|
54
|
+
metadata: metadata.metadata,
|
|
55
|
+
previewUrl: fileState.previewUrl,
|
|
56
|
+
progress: void 0,
|
|
57
|
+
uploader: metadata.uploader
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return publishNewState();
|
|
61
|
+
}
|
|
62
|
+
case "finishSuccessfully": {
|
|
63
|
+
for (const [fileOrId, result] of action.result) {
|
|
64
|
+
const fileId = toFileId(previousState, fileOrId);
|
|
65
|
+
const previousFileState = previousState.liveState.get(fileId);
|
|
66
|
+
if (previousFileState === void 0 || previousFileState.readyState !== "uploading") {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
previousState.liveState.set(fileId, {
|
|
70
|
+
readyState: "success",
|
|
71
|
+
file: previousFileState.file,
|
|
72
|
+
metadata: previousFileState.metadata,
|
|
73
|
+
previewUrl: previousFileState.previewUrl,
|
|
74
|
+
result,
|
|
75
|
+
uploader: previousFileState.uploader
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return getNewDirtyState();
|
|
79
|
+
}
|
|
80
|
+
case "finishWithError": {
|
|
81
|
+
for (const errorSpec of action.error) {
|
|
82
|
+
let fileOrId;
|
|
83
|
+
let rawError;
|
|
84
|
+
if (Array.isArray(errorSpec)) {
|
|
85
|
+
[fileOrId, rawError] = errorSpec;
|
|
86
|
+
} else {
|
|
87
|
+
fileOrId = errorSpec;
|
|
88
|
+
rawError = void 0;
|
|
89
|
+
}
|
|
90
|
+
const errors = [];
|
|
91
|
+
if (rawError instanceof FileUploadError) {
|
|
92
|
+
errors.push(rawError);
|
|
93
|
+
} else if (Array.isArray(rawError)) {
|
|
94
|
+
for (const error of rawError) {
|
|
95
|
+
if (error instanceof FileUploadError) {
|
|
96
|
+
errors.push(error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const fileId = toFileId(previousState, fileOrId);
|
|
101
|
+
const previousFileState = previousState.liveState.get(fileId);
|
|
102
|
+
if (previousFileState === void 0 || previousFileState.readyState !== "initializing" && previousFileState.readyState !== "uploading") {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const uploader = previousFileState.readyState === "uploading" ? previousFileState.uploader : void 0;
|
|
106
|
+
const metadata = previousFileState.readyState === "uploading" ? previousFileState.metadata : void 0;
|
|
107
|
+
previousState.liveState.set(fileId, {
|
|
108
|
+
readyState: "error",
|
|
109
|
+
errors: errors.length ? errors : void 0,
|
|
110
|
+
rawError,
|
|
111
|
+
file: previousFileState.file,
|
|
112
|
+
metadata,
|
|
113
|
+
previewUrl: previousFileState.previewUrl,
|
|
114
|
+
uploader
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return getNewDirtyState();
|
|
118
|
+
}
|
|
119
|
+
case "purge": {
|
|
120
|
+
let atLeastOnePurged = false;
|
|
121
|
+
for (const fileOrId of action.files) {
|
|
122
|
+
const fileId = toFileId(previousState, fileOrId);
|
|
123
|
+
const fileState = previousState.liveState.get(fileId);
|
|
124
|
+
if (fileState === void 0) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
atLeastOnePurged = true;
|
|
128
|
+
if (fileState.readyState === "initializing" || fileState.readyState === "uploading") {
|
|
129
|
+
fileState.abortController.abort();
|
|
130
|
+
}
|
|
131
|
+
previousState.liveState.delete(fileId);
|
|
132
|
+
}
|
|
133
|
+
if (atLeastOnePurged) {
|
|
134
|
+
return getNewDirtyState();
|
|
135
|
+
}
|
|
136
|
+
return previousState;
|
|
137
|
+
}
|
|
138
|
+
case "updateUploadProgress": {
|
|
139
|
+
for (const [fileOrId, { progress }] of action.progress) {
|
|
140
|
+
const fileId = toFileId(previousState, fileOrId);
|
|
141
|
+
const previousFileState = previousState.liveState.get(fileId);
|
|
142
|
+
if (progress === void 0 || previousFileState === void 0 || previousFileState.readyState !== "uploading") {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
previousState.liveState.set(fileId, {
|
|
146
|
+
readyState: "uploading",
|
|
147
|
+
file: previousFileState.file,
|
|
148
|
+
uploader: previousFileState.uploader,
|
|
149
|
+
abortController: previousFileState.abortController,
|
|
150
|
+
previewUrl: previousFileState.previewUrl,
|
|
151
|
+
metadata: previousFileState.metadata,
|
|
152
|
+
progress
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return getNewDirtyState();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
assertNever();
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export { fileUploadReducer, initializeFileUploadState };
|
|
162
|
+
//# sourceMappingURL=fileUploadReducer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileUploadReducer.js","sources":["../../../src/upload/fileUploadReducer.ts"],"sourcesContent":["import { FileUploadError } from '@contember/client'\nimport { assertNever } from '../utils'\nimport type { FileId } from './FileId'\nimport type { FileUploadAction } from './FileUploadAction'\nimport type { FileUploadMultiTemporalState } from './FileUploadMultiTemporalState'\nimport { toFileId } from './toFileId'\n\nexport const initializeFileUploadState = <Result = unknown, Metadata = undefined>(): FileUploadMultiTemporalState<\n\tResult,\n\tMetadata\n> => ({\n\tlastUpdateTime: 0,\n\tfileIdByFile: new WeakMap<File, FileId>(),\n\tliveState: new Map(),\n\tpublicState: new Map(),\n\tisLiveStateDirty: false,\n})\n\nexport const fileUploadReducer = <Result = unknown, Metadata = undefined>(\n\tpreviousState: FileUploadMultiTemporalState<Result, Metadata>,\n\taction: FileUploadAction<Result, Metadata>,\n): FileUploadMultiTemporalState<Result, Metadata> => {\n\tconst publishNewState = (): FileUploadMultiTemporalState<Result, Metadata> => ({\n\t\tpublicState: previousState.liveState,\n\t\tfileIdByFile: previousState.fileIdByFile,\n\t\tlastUpdateTime: previousState.lastUpdateTime,\n\t\tisLiveStateDirty: false,\n\n\t\t// Immediately make the live state referentially unequal so that this doesn't have to happen during each action\n\t\t// several times between two publishes.\n\t\tliveState: new Map(previousState.liveState),\n\t})\n\tconst getNewDirtyState = (): FileUploadMultiTemporalState<Result, Metadata> => ({\n\t\tfileIdByFile: previousState.fileIdByFile,\n\t\tliveState: previousState.liveState,\n\t\tpublicState: previousState.publicState,\n\t\tisLiveStateDirty: true,\n\t\tlastUpdateTime: Date.now(),\n\t})\n\tswitch (action.type) {\n\t\tcase 'publishNewestState': {\n\t\t\treturn publishNewState()\n\t\t}\n\t\tcase 'initialize': {\n\t\t\tfor (const [fileId, metadata] of action.files) {\n\t\t\t\t// Deliberately allowing starting a new upload with the same id\n\n\t\t\t\tpreviousState.liveState.set(fileId, {\n\t\t\t\t\treadyState: 'initializing',\n\t\t\t\t\tabortController: metadata.abortController,\n\t\t\t\t\tpreviewUrl: metadata.previewUrl,\n\t\t\t\t\tfile: metadata.file,\n\t\t\t\t})\n\t\t\t\tpreviousState.fileIdByFile.set(metadata.file, fileId)\n\t\t\t}\n\t\t\treturn publishNewState() /* Making the feedback about new files immediate*/\n\t\t}\n\t\tcase 'startUploading': {\n\t\t\tfor (const [fileOrId, metadata] of action.files) {\n\t\t\t\tconst fileId = toFileId(previousState, fileOrId)\n\t\t\t\tconst fileState = previousState.liveState.get(fileId)\n\n\t\t\t\tif (fileState === undefined || fileState.readyState !== 'initializing') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tpreviousState.liveState.set(fileId, {\n\t\t\t\t\treadyState: 'uploading',\n\t\t\t\t\tabortController: fileState.abortController,\n\t\t\t\t\tfile: fileState.file,\n\t\t\t\t\tmetadata: metadata.metadata!, // If the user didn't supply the metadata, then that's on them.\n\t\t\t\t\tpreviewUrl: fileState.previewUrl,\n\t\t\t\t\tprogress: undefined,\n\t\t\t\t\tuploader: metadata.uploader,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn publishNewState() /* Making the feedback about started upload immediate*/\n\t\t}\n\t\tcase 'finishSuccessfully': {\n\t\t\tfor (const [fileOrId, result] of action.result) {\n\t\t\t\tconst fileId = toFileId(previousState, fileOrId)\n\t\t\t\tconst previousFileState = previousState.liveState.get(fileId)\n\t\t\t\tif (previousFileState === undefined || previousFileState.readyState !== 'uploading') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tpreviousState.liveState.set(fileId, {\n\t\t\t\t\treadyState: 'success',\n\t\t\t\t\tfile: previousFileState.file,\n\t\t\t\t\tmetadata: previousFileState.metadata,\n\t\t\t\t\tpreviewUrl: previousFileState.previewUrl,\n\t\t\t\t\tresult,\n\t\t\t\t\tuploader: previousFileState.uploader,\n\t\t\t\t})\n\t\t\t}\n\t\t\t// return publishNewState() // Making the feedback about successful upload immediate.\n\t\t\treturn getNewDirtyState()\n\t\t}\n\t\tcase 'finishWithError': {\n\t\t\tfor (const errorSpec of action.error) {\n\t\t\t\tlet fileOrId: File | FileId\n\t\t\t\tlet rawError: unknown\n\n\t\t\t\tif (Array.isArray(errorSpec)) {\n\t\t\t\t\t[fileOrId, rawError] = errorSpec\n\t\t\t\t} else {\n\t\t\t\t\tfileOrId = errorSpec\n\t\t\t\t\trawError = undefined\n\t\t\t\t}\n\n\t\t\t\tconst errors: FileUploadError[] = []\n\n\t\t\t\tif (rawError instanceof FileUploadError) {\n\t\t\t\t\terrors.push(rawError)\n\t\t\t\t} else if (Array.isArray(rawError)) {\n\t\t\t\t\tfor (const error of rawError) {\n\t\t\t\t\t\tif (error instanceof FileUploadError) {\n\t\t\t\t\t\t\terrors.push(error)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst fileId = toFileId(previousState, fileOrId)\n\t\t\t\tconst previousFileState = previousState.liveState.get(fileId)\n\t\t\t\tif (\n\t\t\t\t\tpreviousFileState === undefined ||\n\t\t\t\t\t(previousFileState.readyState !== 'initializing' && previousFileState.readyState !== 'uploading')\n\t\t\t\t) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst uploader = previousFileState.readyState === 'uploading' ? previousFileState.uploader : undefined\n\t\t\t\tconst metadata = previousFileState.readyState === 'uploading' ? previousFileState.metadata : undefined\n\t\t\t\tpreviousState.liveState.set(fileId, {\n\t\t\t\t\treadyState: 'error',\n\t\t\t\t\terrors: errors.length ? errors : undefined,\n\t\t\t\t\trawError,\n\t\t\t\t\tfile: previousFileState.file,\n\t\t\t\t\tmetadata,\n\t\t\t\t\tpreviewUrl: previousFileState.previewUrl,\n\t\t\t\t\tuploader,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn getNewDirtyState() // Bad news can wait.\n\t\t}\n\t\tcase 'purge': {\n\t\t\tlet atLeastOnePurged = false\n\t\t\tfor (const fileOrId of action.files) {\n\t\t\t\tconst fileId = toFileId(previousState, fileOrId)\n\t\t\t\tconst fileState = previousState.liveState.get(fileId)\n\n\t\t\t\tif (fileState === undefined) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tatLeastOnePurged = true\n\t\t\t\tif (fileState.readyState === 'initializing' || fileState.readyState === 'uploading') {\n\t\t\t\t\tfileState.abortController.abort() // This is a bit naughty… We shouldn't do this from here.\n\t\t\t\t}\n\t\t\t\tpreviousState.liveState.delete(fileId)\n\t\t\t}\n\t\t\tif (atLeastOnePurged) {\n\t\t\t\treturn getNewDirtyState()\n\t\t\t}\n\t\t\treturn previousState\n\t\t}\n\t\tcase 'updateUploadProgress': {\n\t\t\tfor (const [fileOrId, { progress }] of action.progress) {\n\t\t\t\tconst fileId = toFileId(previousState, fileOrId)\n\t\t\t\tconst previousFileState = previousState.liveState.get(fileId)\n\t\t\t\tif (progress === undefined || previousFileState === undefined || previousFileState.readyState !== 'uploading') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tpreviousState.liveState.set(fileId, {\n\t\t\t\t\treadyState: 'uploading',\n\t\t\t\t\tfile: previousFileState.file,\n\t\t\t\t\tuploader: previousFileState.uploader,\n\t\t\t\t\tabortController: previousFileState.abortController,\n\t\t\t\t\tpreviewUrl: previousFileState.previewUrl,\n\t\t\t\t\tmetadata: previousFileState.metadata,\n\t\t\t\t\tprogress,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn getNewDirtyState()\n\t\t}\n\t}\n\tassertNever(action)\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toFileId.js","sources":["../../../src/upload/toFileId.ts"],"sourcesContent":["import type { FileId } from './FileId'\nimport type { FileUploadMultiTemporalState } from './FileUploadMultiTemporalState'\n\nexport const toFileId = <Result = unknown, Metadata = undefined>(\n\tstate: FileUploadMultiTemporalState<Result, Metadata>,\n\tfileOrId: File | FileId,\n) => {\n\tif (fileOrId instanceof File) {\n\t\treturn state.fileIdByFile.get(fileOrId)! // Should we throw instead of the yolo \"!\"?\n\t}\n\treturn fileOrId\n}\n"],"names":[],"mappings":"MAGa,WAAW,CACvB,OACA,aACI;AACJ,MAAI,oBAAoB,MAAM;AAC7B,WAAO,MAAM,aAAa,IAAI;AAAA;AAE/B,SAAO;AAAA;;;;"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { S3FileUploader } from '@contember/client';
|
|
2
|
+
import { useRef, useReducer, useMemo, useEffect, useCallback } from 'react';
|
|
3
|
+
import { fileUploadReducer, initializeFileUploadState } from './fileUploadReducer.js';
|
|
4
|
+
import { toFileId } from './toFileId.js';
|
|
5
|
+
import { useCurrentContentGraphQlClient } from '../content/useCurrentContentGraphQlClient.js';
|
|
6
|
+
|
|
7
|
+
const useFileUpload = (options) => {
|
|
8
|
+
const maxUpdateFrequency = options?.maxUpdateFrequency ?? 100;
|
|
9
|
+
const contentApiClient = useCurrentContentGraphQlClient();
|
|
10
|
+
const updateTimeoutRef = useRef(void 0);
|
|
11
|
+
const isFirstRenderRef = useRef(true);
|
|
12
|
+
const fileIdSeedRef = useRef(1);
|
|
13
|
+
const [multiTemporalState, dispatch] = useReducer(fileUploadReducer, void 0, initializeFileUploadState);
|
|
14
|
+
const multiTemporalStateRef = useRef(multiTemporalState);
|
|
15
|
+
const defaultUploader = useMemo(() => new S3FileUploader(), []);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
multiTemporalStateRef.current = multiTemporalState;
|
|
18
|
+
});
|
|
19
|
+
const purgeUpload = useCallback((files) => {
|
|
20
|
+
dispatch({
|
|
21
|
+
type: "purge",
|
|
22
|
+
files
|
|
23
|
+
});
|
|
24
|
+
}, []);
|
|
25
|
+
const failUpload = useCallback((error) => {
|
|
26
|
+
dispatch({
|
|
27
|
+
type: "finishWithError",
|
|
28
|
+
error
|
|
29
|
+
});
|
|
30
|
+
}, []);
|
|
31
|
+
const initializeUpload = useCallback((files) => {
|
|
32
|
+
const newFileIds = new Set();
|
|
33
|
+
const fileWithMetadataByFileConfig = new Map();
|
|
34
|
+
for (const fileMaybeWithId of files) {
|
|
35
|
+
const abortController = new AbortController();
|
|
36
|
+
let fileId;
|
|
37
|
+
let file;
|
|
38
|
+
if (fileMaybeWithId instanceof File) {
|
|
39
|
+
fileId = `__contember__file-${fileIdSeedRef.current++}`;
|
|
40
|
+
file = fileMaybeWithId;
|
|
41
|
+
} else {
|
|
42
|
+
fileId = fileMaybeWithId[0];
|
|
43
|
+
file = fileMaybeWithId[1];
|
|
44
|
+
}
|
|
45
|
+
abortController.signal.addEventListener("abort", () => {
|
|
46
|
+
purgeUpload([fileId]);
|
|
47
|
+
});
|
|
48
|
+
fileWithMetadataByFileConfig.set(fileId, {
|
|
49
|
+
previewUrl: URL.createObjectURL(file),
|
|
50
|
+
abortController,
|
|
51
|
+
file,
|
|
52
|
+
fileId
|
|
53
|
+
});
|
|
54
|
+
newFileIds.add(fileId);
|
|
55
|
+
}
|
|
56
|
+
if (fileWithMetadataByFileConfig.size === 0) {
|
|
57
|
+
return fileWithMetadataByFileConfig;
|
|
58
|
+
}
|
|
59
|
+
if (newFileIds.size) {
|
|
60
|
+
dispatch({
|
|
61
|
+
type: "purge",
|
|
62
|
+
files: newFileIds
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
dispatch({
|
|
66
|
+
type: "initialize",
|
|
67
|
+
files: fileWithMetadataByFileConfig
|
|
68
|
+
});
|
|
69
|
+
return fileWithMetadataByFileConfig;
|
|
70
|
+
}, [purgeUpload]);
|
|
71
|
+
const startUpload = useCallback((files) => {
|
|
72
|
+
const filesById = new Map();
|
|
73
|
+
const groupedByUploader = new Map();
|
|
74
|
+
const currentState = multiTemporalStateRef.current;
|
|
75
|
+
for (const fileOrIdMaybeWithOptions of files) {
|
|
76
|
+
let fileOrId;
|
|
77
|
+
let options2;
|
|
78
|
+
if (Array.isArray(fileOrIdMaybeWithOptions)) {
|
|
79
|
+
fileOrId = fileOrIdMaybeWithOptions[0];
|
|
80
|
+
options2 = fileOrIdMaybeWithOptions[1];
|
|
81
|
+
} else {
|
|
82
|
+
fileOrId = fileOrIdMaybeWithOptions;
|
|
83
|
+
options2 = {};
|
|
84
|
+
}
|
|
85
|
+
const { uploader = defaultUploader, metadata } = options2;
|
|
86
|
+
const fileId = toFileId(currentState, fileOrId);
|
|
87
|
+
const fileState = currentState.liveState.get(fileId);
|
|
88
|
+
if (fileState === void 0 || fileState.readyState !== "initializing") {
|
|
89
|
+
throw new Error(`Trying to startUpload a file that hasn't been previously initialized. This will be possible in future, but isn't yet.`);
|
|
90
|
+
}
|
|
91
|
+
filesById.set(fileId, {
|
|
92
|
+
uploader,
|
|
93
|
+
metadata
|
|
94
|
+
});
|
|
95
|
+
let filesWithSameUploader = groupedByUploader.get(uploader);
|
|
96
|
+
if (filesWithSameUploader === void 0) {
|
|
97
|
+
groupedByUploader.set(uploader, filesWithSameUploader = new Map());
|
|
98
|
+
}
|
|
99
|
+
filesWithSameUploader.set(fileState.file, {
|
|
100
|
+
abortSignal: fileState.abortController.signal
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
dispatch({
|
|
104
|
+
type: "startUploading",
|
|
105
|
+
files: filesById
|
|
106
|
+
});
|
|
107
|
+
for (const [uploader, filesForUpload] of groupedByUploader) {
|
|
108
|
+
try {
|
|
109
|
+
uploader.upload(filesForUpload, {
|
|
110
|
+
onProgress: (progress) => {
|
|
111
|
+
dispatch({
|
|
112
|
+
type: "updateUploadProgress",
|
|
113
|
+
progress
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
onSuccess: (result) => {
|
|
117
|
+
dispatch({
|
|
118
|
+
type: "finishSuccessfully",
|
|
119
|
+
result
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
onError: (error) => {
|
|
123
|
+
dispatch({
|
|
124
|
+
type: "finishWithError",
|
|
125
|
+
error
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
contentApiClient
|
|
129
|
+
});
|
|
130
|
+
} catch (error) {
|
|
131
|
+
dispatch({
|
|
132
|
+
type: "finishWithError",
|
|
133
|
+
error: Array.from(filesForUpload).map(([file]) => [file, error])
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}, [contentApiClient, defaultUploader]);
|
|
138
|
+
const operations = useMemo(() => ({
|
|
139
|
+
failUpload,
|
|
140
|
+
initializeUpload,
|
|
141
|
+
purgeUpload,
|
|
142
|
+
startUpload
|
|
143
|
+
}), [failUpload, initializeUpload, purgeUpload, startUpload]);
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (isFirstRenderRef.current) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (multiTemporalState.isLiveStateDirty) {
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
const timeDelta = Math.max(now - multiTemporalState.lastUpdateTime, 0);
|
|
151
|
+
if (timeDelta > maxUpdateFrequency) {
|
|
152
|
+
if (updateTimeoutRef.current !== void 0) {
|
|
153
|
+
clearTimeout(updateTimeoutRef.current);
|
|
154
|
+
}
|
|
155
|
+
dispatch({
|
|
156
|
+
type: "publishNewestState"
|
|
157
|
+
});
|
|
158
|
+
} else {
|
|
159
|
+
if (updateTimeoutRef.current !== void 0) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
updateTimeoutRef.current = window.setTimeout(() => {
|
|
163
|
+
dispatch({
|
|
164
|
+
type: "publishNewestState"
|
|
165
|
+
});
|
|
166
|
+
updateTimeoutRef.current = void 0;
|
|
167
|
+
}, maxUpdateFrequency - timeDelta);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}, [
|
|
171
|
+
multiTemporalState.isLiveStateDirty,
|
|
172
|
+
multiTemporalState.lastUpdateTime,
|
|
173
|
+
multiTemporalState.liveState,
|
|
174
|
+
multiTemporalState.publicState,
|
|
175
|
+
maxUpdateFrequency
|
|
176
|
+
]);
|
|
177
|
+
useEffect(() => () => {
|
|
178
|
+
for (const [, state] of multiTemporalStateRef.current.liveState) {
|
|
179
|
+
URL.revokeObjectURL(state.previewUrl);
|
|
180
|
+
}
|
|
181
|
+
for (const [, state] of multiTemporalStateRef.current.publicState) {
|
|
182
|
+
URL.revokeObjectURL(state.previewUrl);
|
|
183
|
+
}
|
|
184
|
+
}, []);
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
isFirstRenderRef.current = false;
|
|
187
|
+
}, []);
|
|
188
|
+
return [multiTemporalState.publicState, operations];
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export { useFileUpload };
|
|
192
|
+
//# sourceMappingURL=useFileUpload.js.map
|