@payloadcms/figma 0.1.0-alpha.2 → 0.1.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/control-plane.d.ts +1 -1
- package/dist/api/control-plane.js +1 -1
- package/dist/cli.d.ts +30 -0
- package/dist/cli.js +33 -33
- package/dist/commands/deploy.d.ts +2 -0
- package/dist/commands/deploy.js +22 -12
- package/dist/db-content-api/index.d.ts +1 -1
- package/dist/db-content-api/index.js +70 -40
- package/dist/db-content-api/utilities/schema/getDocumentSchema.d.ts +3 -0
- package/dist/db-content-api/utilities/schema/getDocumentSchema.js +24 -0
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.js +2 -0
- package/dist/plugin/build-config.js +32 -3
- package/dist/plugin/cloud-limits/CloudLimitModal/index.d.ts +9 -0
- package/dist/plugin/cloud-limits/CloudLimitModal/index.js +78 -0
- package/dist/plugin/cloud-limits/CloudLimitModal/index.scss +51 -0
- package/dist/plugin/cloud-limits/CloudLimitProvider/index.d.ts +7 -0
- package/dist/plugin/cloud-limits/CloudLimitProvider/index.js +169 -0
- package/dist/plugin/cloud-limits/SlugRegistryContext/index.d.ts +2 -0
- package/dist/plugin/cloud-limits/SlugRegistryContext/index.js +3 -0
- package/dist/plugin/cloud-limits/SlugTracker/index.d.ts +9 -0
- package/dist/plugin/cloud-limits/SlugTracker/index.js +23 -0
- package/dist/plugin/cloud-limits/icons/ExternalLinkIcon.d.ts +2 -0
- package/dist/plugin/cloud-limits/icons/ExternalLinkIcon.js +30 -0
- package/dist/plugin/cloud-limits/shared.d.ts +10 -0
- package/dist/plugin/cloud-limits/shared.js +27 -0
- package/dist/translations/ar.d.ts +12 -0
- package/dist/translations/ar.js +12 -0
- package/dist/translations/az.d.ts +12 -0
- package/dist/translations/az.js +12 -0
- package/dist/translations/bg.d.ts +12 -0
- package/dist/translations/bg.js +12 -0
- package/dist/translations/bnBd.d.ts +12 -0
- package/dist/translations/bnBd.js +12 -0
- package/dist/translations/bnIn.d.ts +12 -0
- package/dist/translations/bnIn.js +12 -0
- package/dist/translations/ca.d.ts +12 -0
- package/dist/translations/ca.js +12 -0
- package/dist/translations/cs.d.ts +12 -0
- package/dist/translations/cs.js +12 -0
- package/dist/translations/da.d.ts +12 -0
- package/dist/translations/da.js +12 -0
- package/dist/translations/de.d.ts +12 -0
- package/dist/translations/de.js +12 -0
- package/dist/translations/en.d.ts +12 -0
- package/dist/translations/en.js +12 -0
- package/dist/translations/es.d.ts +12 -0
- package/dist/translations/es.js +12 -0
- package/dist/translations/et.d.ts +12 -0
- package/dist/translations/et.js +12 -0
- package/dist/translations/fa.d.ts +12 -0
- package/dist/translations/fa.js +12 -0
- package/dist/translations/fr.d.ts +12 -0
- package/dist/translations/fr.js +12 -0
- package/dist/translations/he.d.ts +12 -0
- package/dist/translations/he.js +12 -0
- package/dist/translations/hr.d.ts +12 -0
- package/dist/translations/hr.js +12 -0
- package/dist/translations/hu.d.ts +12 -0
- package/dist/translations/hu.js +12 -0
- package/dist/translations/hy.d.ts +12 -0
- package/dist/translations/hy.js +12 -0
- package/dist/translations/id.d.ts +12 -0
- package/dist/translations/id.js +12 -0
- package/dist/translations/index.d.ts +533 -0
- package/dist/translations/index.js +90 -0
- package/dist/translations/is.d.ts +12 -0
- package/dist/translations/is.js +12 -0
- package/dist/translations/it.d.ts +12 -0
- package/dist/translations/it.js +12 -0
- package/dist/translations/ja.d.ts +12 -0
- package/dist/translations/ja.js +12 -0
- package/dist/translations/ko.d.ts +12 -0
- package/dist/translations/ko.js +12 -0
- package/dist/translations/lt.d.ts +12 -0
- package/dist/translations/lt.js +12 -0
- package/dist/translations/lv.d.ts +12 -0
- package/dist/translations/lv.js +12 -0
- package/dist/translations/my.d.ts +12 -0
- package/dist/translations/my.js +12 -0
- package/dist/translations/nb.d.ts +12 -0
- package/dist/translations/nb.js +12 -0
- package/dist/translations/nl.d.ts +12 -0
- package/dist/translations/nl.js +12 -0
- package/dist/translations/pl.d.ts +12 -0
- package/dist/translations/pl.js +12 -0
- package/dist/translations/pt.d.ts +12 -0
- package/dist/translations/pt.js +12 -0
- package/dist/translations/ro.d.ts +12 -0
- package/dist/translations/ro.js +12 -0
- package/dist/translations/rs.d.ts +12 -0
- package/dist/translations/rs.js +12 -0
- package/dist/translations/rsLatin.d.ts +12 -0
- package/dist/translations/rsLatin.js +12 -0
- package/dist/translations/ru.d.ts +12 -0
- package/dist/translations/ru.js +12 -0
- package/dist/translations/sk.d.ts +12 -0
- package/dist/translations/sk.js +12 -0
- package/dist/translations/sl.d.ts +12 -0
- package/dist/translations/sl.js +12 -0
- package/dist/translations/sv.d.ts +12 -0
- package/dist/translations/sv.js +12 -0
- package/dist/translations/ta.d.ts +12 -0
- package/dist/translations/ta.js +12 -0
- package/dist/translations/th.d.ts +12 -0
- package/dist/translations/th.js +12 -0
- package/dist/translations/tr.d.ts +12 -0
- package/dist/translations/tr.js +12 -0
- package/dist/translations/uk.d.ts +12 -0
- package/dist/translations/uk.js +12 -0
- package/dist/translations/vi.d.ts +12 -0
- package/dist/translations/vi.js +12 -0
- package/dist/translations/zh.d.ts +12 -0
- package/dist/translations/zh.js +12 -0
- package/dist/translations/zhTw.d.ts +12 -0
- package/dist/translations/zhTw.js +12 -0
- package/dist/types.d.ts +2 -0
- package/dist/utils/adapters/nextjs.d.ts +3 -3
- package/dist/utils/adapters/nextjs.js +9 -7
- package/dist/utils/adapters/nitro.d.ts +3 -3
- package/dist/utils/adapters/nitro.js +73 -77
- package/dist/utils/adapters/vite.d.ts +1 -1
- package/dist/utils/adapters/vite.js +8 -7
- package/dist/utils/assert-never.d.ts +1 -0
- package/dist/utils/assert-never.js +3 -0
- package/dist/utils/asset-collection.d.ts +2 -2
- package/dist/utils/asset-collection.js +10 -15
- package/dist/utils/build-detection.d.ts +6 -1
- package/dist/utils/build-detection.js +68 -89
- package/dist/utils/build-lambda-zip.d.ts +5 -6
- package/dist/utils/build-lambda-zip.js +31 -48
- package/dist/utils/deploy-adapter.d.ts +4 -4
- package/dist/utils/deploy-adapter.js +12 -8
- package/dist/utils/deploy-output/inspectNextjsOutput/getNextRelativeAppDir.d.ts +1 -0
- package/dist/utils/deploy-output/inspectNextjsOutput/getNextRelativeAppDir.js +15 -0
- package/dist/utils/deploy-output/inspectNextjsOutput.d.ts +12 -0
- package/dist/utils/deploy-output/inspectNextjsOutput.js +28 -0
- package/dist/utils/deploy-output/inspectNitroOutput.d.ts +9 -0
- package/dist/utils/deploy-output/inspectNitroOutput.js +13 -0
- package/dist/utils/deploy-output/isFile.d.ts +1 -0
- package/dist/utils/deploy-output/isFile.js +4 -0
- package/dist/utils/deploy-output/readJson.d.ts +1 -0
- package/dist/utils/deploy-output/readJson.js +9 -0
- package/dist/utils/deploy-output/resolveNitroOutputLayout.d.ts +8 -0
- package/dist/utils/deploy-output/resolveNitroOutputLayout.js +16 -0
- package/dist/utils/deploy-output/resolveOutputPath.d.ts +2 -0
- package/dist/utils/deploy-output/resolveOutputPath.js +9 -0
- package/dist/utils/deploy-output/resolveWithin.d.ts +1 -0
- package/dist/utils/deploy-output/resolveWithin.js +12 -0
- package/dist/utils/messages.js +2 -0
- package/package.json +5 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage';
|
|
2
2
|
import { lexicalEditor } from '@payloadcms/richtext-lexical';
|
|
3
3
|
import { buildConfig as payloadBuildConfig } from 'payload';
|
|
4
|
+
import { deepMergeSimple } from 'payload/shared';
|
|
4
5
|
import { getBootstrapInfo } from '../api/control-plane.js';
|
|
5
6
|
import { getValidCredential } from '../auth/oauth-flow.js';
|
|
6
7
|
import { getTokenStore } from '../auth/token-store.js';
|
|
@@ -12,6 +13,7 @@ import { schema } from '../endpoints/schema.js';
|
|
|
12
13
|
import { oAuth2Plugin } from '../oauth/index.js';
|
|
13
14
|
import { createStorageClient } from '../storage-content-api/client.js';
|
|
14
15
|
import { contentApiStorageAdapter } from '../storage-content-api/index.js';
|
|
16
|
+
import { translations as figmaTranslations } from '../translations/index.js';
|
|
15
17
|
import { cacheAllEnvironments } from '../utils/cache-bootstrap.js';
|
|
16
18
|
import { getEnvVarSync } from '../utils/env-management.js';
|
|
17
19
|
import * as log from '../utils/log.js';
|
|
@@ -323,7 +325,14 @@ export async function buildFigmaConfig(config) {
|
|
|
323
325
|
avatar: {
|
|
324
326
|
Component: '@payloadcms/figma/client#FigmaAvatar'
|
|
325
327
|
},
|
|
326
|
-
...config.admin
|
|
328
|
+
...config.admin,
|
|
329
|
+
components: {
|
|
330
|
+
...config.admin?.components,
|
|
331
|
+
providers: [
|
|
332
|
+
...config.admin?.components?.providers ?? [],
|
|
333
|
+
'@payloadcms/figma/client#FigmaCloudLimitProvider'
|
|
334
|
+
]
|
|
335
|
+
}
|
|
327
336
|
},
|
|
328
337
|
custom: {
|
|
329
338
|
figma: {
|
|
@@ -339,6 +348,10 @@ export async function buildFigmaConfig(config) {
|
|
|
339
348
|
health,
|
|
340
349
|
schema
|
|
341
350
|
],
|
|
351
|
+
i18n: {
|
|
352
|
+
...config.i18n,
|
|
353
|
+
translations: deepMergeSimple(figmaTranslations, config.i18n?.translations ?? {})
|
|
354
|
+
},
|
|
342
355
|
// Gate /api/payload-jobs/run and /api/payload-jobs/handle-schedules. Honor the
|
|
343
356
|
// sites-worker trust marker so Figma infra job runs never break, defer to the
|
|
344
357
|
// tenant's jobs.access.run if they set one, otherwise fall back to Payload's
|
|
@@ -403,16 +416,32 @@ export async function buildFigmaConfig(config) {
|
|
|
403
416
|
};
|
|
404
417
|
// Inject figma fields into users collection
|
|
405
418
|
const collections = configWithFigmaDefaults.collections?.map((col)=>{
|
|
419
|
+
const withSlugTracker = {
|
|
420
|
+
...col,
|
|
421
|
+
admin: {
|
|
422
|
+
...col.admin,
|
|
423
|
+
components: {
|
|
424
|
+
...col.admin?.components,
|
|
425
|
+
edit: {
|
|
426
|
+
...col.admin?.components?.edit,
|
|
427
|
+
beforeDocumentControls: [
|
|
428
|
+
'@payloadcms/figma/client#FigmaCloudLimitSlugTracker',
|
|
429
|
+
...col.admin?.components?.edit?.beforeDocumentControls ?? []
|
|
430
|
+
]
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
};
|
|
406
435
|
if (col.slug === 'users') {
|
|
407
436
|
return {
|
|
408
|
-
...
|
|
437
|
+
...withSlugTracker,
|
|
409
438
|
fields: [
|
|
410
439
|
...col.fields || [],
|
|
411
440
|
...figmaUserFields
|
|
412
441
|
]
|
|
413
442
|
};
|
|
414
443
|
}
|
|
415
|
-
return
|
|
444
|
+
return withSlugTracker;
|
|
416
445
|
});
|
|
417
446
|
if (collections) {
|
|
418
447
|
configWithFigmaDefaults.collections = collections;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import './index.scss';
|
|
2
|
+
type Props = {
|
|
3
|
+
adminRoute: string;
|
|
4
|
+
collectionLabel?: string;
|
|
5
|
+
collectionSlug?: string;
|
|
6
|
+
onRetry: () => void;
|
|
7
|
+
};
|
|
8
|
+
export declare function FigmaCloudLimitDocumentCountModal({ adminRoute, collectionLabel, collectionSlug, onRetry, }: Props): import("react").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button, DialogBody, DialogCancel, DialogFooter, DialogHeader, DialogModal, useModal, useTranslation } from '@payloadcms/ui';
|
|
4
|
+
import { useRouter } from 'next/navigation.js';
|
|
5
|
+
import { useCallback } from 'react';
|
|
6
|
+
import { ExternalLinkIcon } from '../icons/ExternalLinkIcon.js';
|
|
7
|
+
import { cloudLimitDocumentCountModalSlug } from '../shared.js';
|
|
8
|
+
import './index.scss';
|
|
9
|
+
const baseClass = 'figma-cloud-limit-modal';
|
|
10
|
+
export function FigmaCloudLimitDocumentCountModal({ adminRoute, collectionLabel, collectionSlug, onRetry }) {
|
|
11
|
+
const { t } = useTranslation();
|
|
12
|
+
const { closeModal } = useModal();
|
|
13
|
+
const router = useRouter();
|
|
14
|
+
const handleReviewClick = useCallback(()=>{
|
|
15
|
+
closeModal(cloudLimitDocumentCountModalSlug);
|
|
16
|
+
router.push(`${adminRoute}/collections/${collectionSlug}`);
|
|
17
|
+
}, [
|
|
18
|
+
adminRoute,
|
|
19
|
+
closeModal,
|
|
20
|
+
collectionSlug,
|
|
21
|
+
router
|
|
22
|
+
]);
|
|
23
|
+
return /*#__PURE__*/ _jsxs(DialogModal, {
|
|
24
|
+
size: "small",
|
|
25
|
+
slug: cloudLimitDocumentCountModalSlug,
|
|
26
|
+
children: [
|
|
27
|
+
/*#__PURE__*/ _jsx(DialogHeader, {
|
|
28
|
+
showClose: true,
|
|
29
|
+
title: t('figma:cloudLimitModalHeading')
|
|
30
|
+
}),
|
|
31
|
+
/*#__PURE__*/ _jsx(DialogBody, {
|
|
32
|
+
children: /*#__PURE__*/ _jsx("p", {
|
|
33
|
+
className: `${baseClass}__body`,
|
|
34
|
+
children: t('figma:cloudLimitModalBody')
|
|
35
|
+
})
|
|
36
|
+
}),
|
|
37
|
+
/*#__PURE__*/ _jsx(DialogFooter, {
|
|
38
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
39
|
+
className: `${baseClass}__footer`,
|
|
40
|
+
children: [
|
|
41
|
+
collectionLabel && collectionSlug ? /*#__PURE__*/ _jsxs("button", {
|
|
42
|
+
className: `${baseClass}__review-btn`,
|
|
43
|
+
onClick: handleReviewClick,
|
|
44
|
+
type: "button",
|
|
45
|
+
children: [
|
|
46
|
+
/*#__PURE__*/ _jsx("span", {
|
|
47
|
+
className: `${baseClass}__review-btn-label`,
|
|
48
|
+
children: t('figma:cloudLimitModalReviewCollection', {
|
|
49
|
+
collection: collectionLabel
|
|
50
|
+
})
|
|
51
|
+
}),
|
|
52
|
+
/*#__PURE__*/ _jsx(ExternalLinkIcon, {})
|
|
53
|
+
]
|
|
54
|
+
}) : null,
|
|
55
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
56
|
+
className: `${baseClass}__actions`,
|
|
57
|
+
children: [
|
|
58
|
+
/*#__PURE__*/ _jsx(DialogCancel, {
|
|
59
|
+
label: t('figma:cloudLimitModalConfirm')
|
|
60
|
+
}),
|
|
61
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
62
|
+
buttonStyle: "primary",
|
|
63
|
+
margin: false,
|
|
64
|
+
onClick: ()=>{
|
|
65
|
+
closeModal(cloudLimitDocumentCountModalSlug);
|
|
66
|
+
onRetry();
|
|
67
|
+
},
|
|
68
|
+
size: "medium",
|
|
69
|
+
children: t('figma:cloudLimitModalRetry')
|
|
70
|
+
})
|
|
71
|
+
]
|
|
72
|
+
})
|
|
73
|
+
]
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.figma-cloud-limit-modal {
|
|
2
|
+
&__body {
|
|
3
|
+
margin: 0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
&__footer {
|
|
7
|
+
align-items: center;
|
|
8
|
+
display: flex;
|
|
9
|
+
gap: var(--spacer-4);
|
|
10
|
+
width: 100%;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&__review-btn {
|
|
14
|
+
align-items: center;
|
|
15
|
+
background: none;
|
|
16
|
+
border: none;
|
|
17
|
+
color: var(--color-text-brand);
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
flex-shrink: 1;
|
|
21
|
+
font-size: var(--text-body-medium-font-size);
|
|
22
|
+
gap: var(--spacer-1);
|
|
23
|
+
min-width: 0;
|
|
24
|
+
padding: 0;
|
|
25
|
+
|
|
26
|
+
&:hover {
|
|
27
|
+
color: var(--ramp-blue-700);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
&:active {
|
|
31
|
+
color: var(--ramp-blue-800);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&__review-btn-label {
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
text-overflow: ellipsis;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Prevents the icon from shrinking when the label ellipses.
|
|
42
|
+
&__review-btn svg {
|
|
43
|
+
flex-shrink: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&__actions {
|
|
47
|
+
display: flex;
|
|
48
|
+
gap: var(--spacer-2);
|
|
49
|
+
margin-inline-start: auto;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { getTranslation } from '@payloadcms/translations';
|
|
4
|
+
import { FormErrorHandlerContext, toast, useConfig, useFormErrorHandler, useModal, useTranslation } from '@payloadcms/ui';
|
|
5
|
+
import { hasAutosaveEnabled } from 'payload/shared';
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
7
|
+
import { FigmaCloudLimitDocumentCountModal } from '../CloudLimitModal/index.js';
|
|
8
|
+
import { cloudLimitDocumentCountModalSlug, cloudLimitErrorCodes, cloudLimitToastKeyByCode, getCloudLimitErrorCode } from '../shared.js';
|
|
9
|
+
import { FigmaCloudLimitSlugRegistryContext } from '../SlugRegistryContext/index.js';
|
|
10
|
+
const AUTOSAVE_TOAST_ID = 'figma-cloud-limit-doc-count';
|
|
11
|
+
let isUploadFetchPatched = false;
|
|
12
|
+
function slugFromPathSuffix(suffix) {
|
|
13
|
+
return /^\/collections\/([^/?#]+)/.exec(suffix)?.[1];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Surfaces Content API cloud-limit errors in the admin UI.
|
|
17
|
+
*/ export function FigmaCloudLimitProvider({ children }) {
|
|
18
|
+
const { openModal } = useModal();
|
|
19
|
+
const { i18n, t } = useTranslation();
|
|
20
|
+
const { config, getEntityConfig } = useConfig();
|
|
21
|
+
const parentErrorHandler = useFormErrorHandler();
|
|
22
|
+
const adminRouteRef = useRef(config.routes?.admin ?? '/admin');
|
|
23
|
+
const apiRouteRef = useRef(config.routes?.api ?? '/api');
|
|
24
|
+
const [collectionSlug, setCollectionSlug] = useState();
|
|
25
|
+
const [collectionLabel, setCollectionLabel] = useState();
|
|
26
|
+
const retryRef = useRef(undefined);
|
|
27
|
+
// Ref so the handler always calls the latest getEntityConfig without being recreated.
|
|
28
|
+
const getEntityConfigRef = useRef(getEntityConfig);
|
|
29
|
+
getEntityConfigRef.current = getEntityConfig;
|
|
30
|
+
const tRef = useRef(t);
|
|
31
|
+
tRef.current = t;
|
|
32
|
+
// Stack of active collection slugs. FigmaCloudLimitSlugTracker components push/pop as
|
|
33
|
+
// documents mount/unmount (including drawers). The last entry is the active form's collection.
|
|
34
|
+
const slugStackRef = useRef([]);
|
|
35
|
+
const registerCollectionSlug = useCallback((slug)=>{
|
|
36
|
+
const id = Symbol();
|
|
37
|
+
slugStackRef.current = [
|
|
38
|
+
...slugStackRef.current,
|
|
39
|
+
{
|
|
40
|
+
id,
|
|
41
|
+
slug
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
return ()=>{
|
|
45
|
+
slugStackRef.current = slugStackRef.current.filter((e)=>e.id !== id);
|
|
46
|
+
};
|
|
47
|
+
}, []);
|
|
48
|
+
// Detect upload related cloud-limit that bypass form state
|
|
49
|
+
useEffect(()=>{
|
|
50
|
+
if (isUploadFetchPatched) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
isUploadFetchPatched = true;
|
|
54
|
+
const originalFetch = window.fetch.bind(window);
|
|
55
|
+
const originalToastError = toast.error;
|
|
56
|
+
const toastObj = toast;
|
|
57
|
+
const pendingSuppressions = [];
|
|
58
|
+
const removeSuppression = (suppression)=>{
|
|
59
|
+
window.clearTimeout(suppression.timeout);
|
|
60
|
+
const index = pendingSuppressions.indexOf(suppression);
|
|
61
|
+
if (index !== -1) {
|
|
62
|
+
pendingSuppressions.splice(index, 1);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
toastObj.error = (...args)=>{
|
|
66
|
+
// prevent the thrown error from sending a duplicate toast
|
|
67
|
+
const msg = typeof args[0] === 'string' ? args[0] : args[0]?.props?.errorMessage ?? '';
|
|
68
|
+
const suppression = pendingSuppressions.find(({ message })=>msg.includes(message));
|
|
69
|
+
if (suppression) {
|
|
70
|
+
removeSuppression(suppression);
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
return originalToastError(...args);
|
|
74
|
+
};
|
|
75
|
+
window.fetch = async function(...args) {
|
|
76
|
+
const response = await originalFetch(...args);
|
|
77
|
+
if (response.status === 409) {
|
|
78
|
+
const url = args[0] instanceof Request ? args[0].url : String(args[0]);
|
|
79
|
+
const uploadInstructionsPath = `${apiRouteRef.current.replace(/\/$/, '')}/upload-instructions`;
|
|
80
|
+
if (new URL(url, window.location.origin).pathname === uploadInstructionsPath) {
|
|
81
|
+
try {
|
|
82
|
+
const json = await response.clone().json();
|
|
83
|
+
const code = getCloudLimitErrorCode(json);
|
|
84
|
+
const messageKey = code !== undefined ? cloudLimitToastKeyByCode[code] : undefined;
|
|
85
|
+
if (messageKey) {
|
|
86
|
+
toast.info(tRef.current(messageKey));
|
|
87
|
+
const rawMessage = json?.errors?.[0]?.message;
|
|
88
|
+
if (rawMessage) {
|
|
89
|
+
const suppression = {
|
|
90
|
+
message: rawMessage,
|
|
91
|
+
timeout: 0
|
|
92
|
+
};
|
|
93
|
+
suppression.timeout = window.setTimeout(()=>removeSuppression(suppression), 0);
|
|
94
|
+
pendingSuppressions.push(suppression);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
// ignore JSON parse failures
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return response;
|
|
103
|
+
};
|
|
104
|
+
return ()=>{
|
|
105
|
+
pendingSuppressions.forEach(({ timeout })=>window.clearTimeout(timeout));
|
|
106
|
+
window.fetch = originalFetch;
|
|
107
|
+
toastObj.error = originalToastError;
|
|
108
|
+
isUploadFetchPatched = false;
|
|
109
|
+
};
|
|
110
|
+
}, []);
|
|
111
|
+
const handleNonFieldError = useCallback((err, retry)=>{
|
|
112
|
+
const code = getCloudLimitErrorCode({
|
|
113
|
+
errors: [
|
|
114
|
+
err
|
|
115
|
+
]
|
|
116
|
+
});
|
|
117
|
+
if (!code) {
|
|
118
|
+
return parentErrorHandler?.(err, retry) ?? false;
|
|
119
|
+
}
|
|
120
|
+
if (code === cloudLimitErrorCodes.documentCount) {
|
|
121
|
+
// Prefer the tracker-provided slug (correct even in drawers) over URL parsing.
|
|
122
|
+
const stack = slugStackRef.current;
|
|
123
|
+
const slug = stack.length > 0 ? stack[stack.length - 1]?.slug : slugFromPathSuffix(window.location.pathname.slice(adminRouteRef.current.length));
|
|
124
|
+
const collectionConfig = slug ? getEntityConfigRef.current({
|
|
125
|
+
collectionSlug: slug
|
|
126
|
+
}) : undefined;
|
|
127
|
+
const isAutosave = collectionConfig ? hasAutosaveEnabled(collectionConfig) : false;
|
|
128
|
+
if (isAutosave) {
|
|
129
|
+
// Stable ID prevents a new toast stacking on every autosave attempt.
|
|
130
|
+
toast.info(t('figma:cloudLimitDocumentCountError'), {
|
|
131
|
+
id: AUTOSAVE_TOAST_ID
|
|
132
|
+
});
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
const label = collectionConfig?.labels?.plural != null ? getTranslation(collectionConfig.labels.plural, i18n) : slug;
|
|
136
|
+
setCollectionSlug(slug);
|
|
137
|
+
setCollectionLabel(label);
|
|
138
|
+
retryRef.current = retry;
|
|
139
|
+
openModal(cloudLimitDocumentCountModalSlug);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
const messageKey = cloudLimitToastKeyByCode[code];
|
|
143
|
+
if (messageKey) {
|
|
144
|
+
toast.info(t(messageKey));
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}, [
|
|
149
|
+
i18n,
|
|
150
|
+
openModal,
|
|
151
|
+
parentErrorHandler,
|
|
152
|
+
t
|
|
153
|
+
]);
|
|
154
|
+
return /*#__PURE__*/ _jsx(FigmaCloudLimitSlugRegistryContext, {
|
|
155
|
+
value: registerCollectionSlug,
|
|
156
|
+
children: /*#__PURE__*/ _jsxs(FormErrorHandlerContext, {
|
|
157
|
+
value: handleNonFieldError,
|
|
158
|
+
children: [
|
|
159
|
+
children,
|
|
160
|
+
/*#__PURE__*/ _jsx(FigmaCloudLimitDocumentCountModal, {
|
|
161
|
+
adminRoute: adminRouteRef.current,
|
|
162
|
+
collectionLabel: collectionLabel,
|
|
163
|
+
collectionSlug: collectionSlug,
|
|
164
|
+
onRetry: ()=>retryRef.current?.()
|
|
165
|
+
})
|
|
166
|
+
]
|
|
167
|
+
})
|
|
168
|
+
});
|
|
169
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invisible component injected into every collection's
|
|
3
|
+
* `admin.components.edit.beforeDocumentControls`. Renders inside
|
|
4
|
+
* DocumentInfoProvider so it can read the correct collectionSlug even inside
|
|
5
|
+
* relationship drawers. Pushes to / pops from the slug stack owned by
|
|
6
|
+
* FigmaCloudLimitProvider so the error handler always knows which collection
|
|
7
|
+
* the active form belongs to.
|
|
8
|
+
*/
|
|
9
|
+
export declare function FigmaCloudLimitSlugTracker(): null;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useDocumentInfo } from '@payloadcms/ui';
|
|
3
|
+
import { use, useEffect } from 'react';
|
|
4
|
+
import { FigmaCloudLimitSlugRegistryContext } from '../SlugRegistryContext/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Invisible component injected into every collection's
|
|
7
|
+
* `admin.components.edit.beforeDocumentControls`. Renders inside
|
|
8
|
+
* DocumentInfoProvider so it can read the correct collectionSlug even inside
|
|
9
|
+
* relationship drawers. Pushes to / pops from the slug stack owned by
|
|
10
|
+
* FigmaCloudLimitProvider so the error handler always knows which collection
|
|
11
|
+
* the active form belongs to.
|
|
12
|
+
*/ export function FigmaCloudLimitSlugTracker() {
|
|
13
|
+
const register = use(FigmaCloudLimitSlugRegistryContext);
|
|
14
|
+
const { collectionSlug } = useDocumentInfo();
|
|
15
|
+
useEffect(()=>{
|
|
16
|
+
const unregister = register(collectionSlug);
|
|
17
|
+
return unregister;
|
|
18
|
+
}, [
|
|
19
|
+
collectionSlug,
|
|
20
|
+
register
|
|
21
|
+
]);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/** External link icon (box with arrow pointing out). Used in cloud-limit UI. */ export function ExternalLinkIcon() {
|
|
4
|
+
return /*#__PURE__*/ _jsxs("svg", {
|
|
5
|
+
"aria-hidden": "true",
|
|
6
|
+
fill: "none",
|
|
7
|
+
height: "14",
|
|
8
|
+
stroke: "currentColor",
|
|
9
|
+
strokeLinecap: "round",
|
|
10
|
+
strokeLinejoin: "round",
|
|
11
|
+
strokeWidth: "2",
|
|
12
|
+
viewBox: "0 0 24 24",
|
|
13
|
+
width: "14",
|
|
14
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
15
|
+
children: [
|
|
16
|
+
/*#__PURE__*/ _jsx("path", {
|
|
17
|
+
d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"
|
|
18
|
+
}),
|
|
19
|
+
/*#__PURE__*/ _jsx("polyline", {
|
|
20
|
+
points: "15 3 21 3 21 9"
|
|
21
|
+
}),
|
|
22
|
+
/*#__PURE__*/ _jsx("line", {
|
|
23
|
+
x1: "10",
|
|
24
|
+
x2: "21",
|
|
25
|
+
y1: "14",
|
|
26
|
+
y2: "3"
|
|
27
|
+
})
|
|
28
|
+
]
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const cloudLimitErrorCodes: {
|
|
2
|
+
readonly assetStorage: "cloud_limit.cms_assets_bytes_exceeded";
|
|
3
|
+
readonly documentCount: "cloud_limit.document_count_exceeded";
|
|
4
|
+
readonly documentDataSize: "cloud_limit.per_document_data_bytes_exceeded";
|
|
5
|
+
};
|
|
6
|
+
export type CloudLimitErrorCode = (typeof cloudLimitErrorCodes)[keyof typeof cloudLimitErrorCodes];
|
|
7
|
+
export declare function isCloudLimitErrorCode(code: unknown): code is CloudLimitErrorCode;
|
|
8
|
+
export declare function getCloudLimitErrorCode(json: unknown): CloudLimitErrorCode | undefined;
|
|
9
|
+
export declare const cloudLimitDocumentCountModalSlug = "figma-cloud-limit-document-count";
|
|
10
|
+
export declare const cloudLimitToastKeyByCode: Partial<Record<CloudLimitErrorCode, string>>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const cloudLimitErrorCodes = {
|
|
2
|
+
assetStorage: 'cloud_limit.cms_assets_bytes_exceeded',
|
|
3
|
+
documentCount: 'cloud_limit.document_count_exceeded',
|
|
4
|
+
documentDataSize: 'cloud_limit.per_document_data_bytes_exceeded'
|
|
5
|
+
};
|
|
6
|
+
const knownCloudLimitCodes = Object.values(cloudLimitErrorCodes);
|
|
7
|
+
export function isCloudLimitErrorCode(code) {
|
|
8
|
+
return typeof code === 'string' && knownCloudLimitCodes.includes(code);
|
|
9
|
+
}
|
|
10
|
+
export function getCloudLimitErrorCode(json) {
|
|
11
|
+
const errors = json?.errors;
|
|
12
|
+
if (!Array.isArray(errors)) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
for (const err of errors){
|
|
16
|
+
const code = err?.data?.code;
|
|
17
|
+
if (isCloudLimitErrorCode(code)) {
|
|
18
|
+
return code;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
export const cloudLimitDocumentCountModalSlug = 'figma-cloud-limit-document-count';
|
|
24
|
+
export const cloudLimitToastKeyByCode = {
|
|
25
|
+
[cloudLimitErrorCodes.assetStorage]: 'figma:cloudLimitAssetStorageError',
|
|
26
|
+
[cloudLimitErrorCodes.documentDataSize]: 'figma:cloudLimitDocumentDataSizeError'
|
|
27
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const arTranslations: {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: string;
|
|
4
|
+
cloudLimitDocumentCountError: string;
|
|
5
|
+
cloudLimitDocumentDataSizeError: string;
|
|
6
|
+
cloudLimitModalBody: string;
|
|
7
|
+
cloudLimitModalConfirm: string;
|
|
8
|
+
cloudLimitModalHeading: string;
|
|
9
|
+
cloudLimitModalRetry: string;
|
|
10
|
+
cloudLimitModalReviewCollection: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const arTranslations = {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: 'يتعذر التحميل. يرجى تحرير بعض المساحة للمتابعة.',
|
|
4
|
+
cloudLimitDocumentCountError: 'غير قادر على إنشاء وثيقة. تم الوصول إلى الحد الأقصى لسعة التخزين.',
|
|
5
|
+
cloudLimitDocumentDataSizeError: 'تعذر حفظ المستند، النص كبير جدًا.',
|
|
6
|
+
cloudLimitModalBody: 'لقد وصلت إلى الحد الأقصى لعدد الوثائق. يرجى حذف بعض الوثائق الحالية لمواصلة الإنشاء.',
|
|
7
|
+
cloudLimitModalConfirm: 'تم فهم ذلك',
|
|
8
|
+
cloudLimitModalHeading: 'تعذر حفظ المستند',
|
|
9
|
+
cloudLimitModalRetry: 'إعادة المحاولة',
|
|
10
|
+
cloudLimitModalReviewCollection: 'مراجعة {{collection}}'
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const azTranslations: {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: string;
|
|
4
|
+
cloudLimitDocumentCountError: string;
|
|
5
|
+
cloudLimitDocumentDataSizeError: string;
|
|
6
|
+
cloudLimitModalBody: string;
|
|
7
|
+
cloudLimitModalConfirm: string;
|
|
8
|
+
cloudLimitModalHeading: string;
|
|
9
|
+
cloudLimitModalRetry: string;
|
|
10
|
+
cloudLimitModalReviewCollection: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const azTranslations = {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: 'Yükləmək mümkün deyil. Davam etmək üçün yer boşaldın.',
|
|
4
|
+
cloudLimitDocumentCountError: 'Sənəd yaratmaq mümkün deyil. Saxlama limiti aşılmışdır.',
|
|
5
|
+
cloudLimitDocumentDataSizeError: 'Sənədi saxlamaq mümkün deyil, mətn çox böyükdür.',
|
|
6
|
+
cloudLimitModalBody: 'Sənəd limitinizə çatdınız. Yenilərini yaratmaq üçün mövcud sənədlərdən bəzilərini silin.',
|
|
7
|
+
cloudLimitModalConfirm: 'Başa düşdüm',
|
|
8
|
+
cloudLimitModalHeading: 'Sənədi yadda saxlamaq mümkün olmadı',
|
|
9
|
+
cloudLimitModalRetry: 'Təkrar cəhd edin',
|
|
10
|
+
cloudLimitModalReviewCollection: '{{collection}}-ə baxış'
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const bgTranslations: {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: string;
|
|
4
|
+
cloudLimitDocumentCountError: string;
|
|
5
|
+
cloudLimitDocumentDataSizeError: string;
|
|
6
|
+
cloudLimitModalBody: string;
|
|
7
|
+
cloudLimitModalConfirm: string;
|
|
8
|
+
cloudLimitModalHeading: string;
|
|
9
|
+
cloudLimitModalRetry: string;
|
|
10
|
+
cloudLimitModalReviewCollection: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const bgTranslations = {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: 'Не може да се качи. Освободете пространство, за да продължите.',
|
|
4
|
+
cloudLimitDocumentCountError: 'Неуспешно създаване на документ. Достигнат е лимитът за съхранение.',
|
|
5
|
+
cloudLimitDocumentDataSizeError: 'Неуспешно записване на документа, текстът е твърде голям.',
|
|
6
|
+
cloudLimitModalBody: 'Достигнали сте лимита на вашите документи. Изтрийте някои съществуващи документи, за да продължите да създавате нови.',
|
|
7
|
+
cloudLimitModalConfirm: 'Разбрах',
|
|
8
|
+
cloudLimitModalHeading: 'Неуспешно запазване на документа',
|
|
9
|
+
cloudLimitModalRetry: 'Опитайте отново.',
|
|
10
|
+
cloudLimitModalReviewCollection: 'Преглед на {{collection}}'
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const bnBdTranslations: {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: string;
|
|
4
|
+
cloudLimitDocumentCountError: string;
|
|
5
|
+
cloudLimitDocumentDataSizeError: string;
|
|
6
|
+
cloudLimitModalBody: string;
|
|
7
|
+
cloudLimitModalConfirm: string;
|
|
8
|
+
cloudLimitModalHeading: string;
|
|
9
|
+
cloudLimitModalRetry: string;
|
|
10
|
+
cloudLimitModalReviewCollection: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const bnBdTranslations = {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: 'আপলোড করা সম্ভব হচ্ছে না। চালিয়ে যেতে হলে স্থান খালি করুন।',
|
|
4
|
+
cloudLimitDocumentCountError: 'দস্তাবেজ তৈরি করা সম্ভব নয়। সংরক্ষণ সীমা অতিক্রম করা হয়েছে।',
|
|
5
|
+
cloudLimitDocumentDataSizeError: 'ডকুমেন্ট সংরক্ষণ করা সম্ভব নয়, কারণ পাঠ্যটি খুব বড়।',
|
|
6
|
+
cloudLimitModalBody: 'আপনি আপনার document সীমা অতিক্রম করেছেন। নতুনভাবে তৈরি করতে হলে কিছু বিদ্যমান document মুছে ফেলুন।',
|
|
7
|
+
cloudLimitModalConfirm: 'বুঝেছি',
|
|
8
|
+
cloudLimitModalHeading: 'ডকুমেন্ট সংরক্ষণ করা যায়নি',
|
|
9
|
+
cloudLimitModalRetry: 'পুনঃচেষ্টা করুন',
|
|
10
|
+
cloudLimitModalReviewCollection: '{{collection}} পর্যালোচনা করুন'
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const bnInTranslations: {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: string;
|
|
4
|
+
cloudLimitDocumentCountError: string;
|
|
5
|
+
cloudLimitDocumentDataSizeError: string;
|
|
6
|
+
cloudLimitModalBody: string;
|
|
7
|
+
cloudLimitModalConfirm: string;
|
|
8
|
+
cloudLimitModalHeading: string;
|
|
9
|
+
cloudLimitModalRetry: string;
|
|
10
|
+
cloudLimitModalReviewCollection: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const bnInTranslations = {
|
|
2
|
+
figma: {
|
|
3
|
+
cloudLimitAssetStorageError: 'আপলোড করা সম্ভব হচ্ছে না। চালিয়ে যেতে হলে স্থান খালি করুন।',
|
|
4
|
+
cloudLimitDocumentCountError: 'ডকুমেন্ট তৈরি করা সম্ভব হয়নি। সংরক্ষণ সীমা অতিক্রম করা হয়েছে।',
|
|
5
|
+
cloudLimitDocumentDataSizeError: 'নথিটি সংরক্ষণ করা সম্ভব নয়, কারণ টেক্সটের আকার অত্যন্ত বড়।',
|
|
6
|
+
cloudLimitModalBody: 'আপনি আপনার document সীমায় পৌঁছেছেন। নতুন তৈরি করতে থাকলে কিছু বিদ্যমান document মুছে ফেলুন।',
|
|
7
|
+
cloudLimitModalConfirm: 'বুঝেছি',
|
|
8
|
+
cloudLimitModalHeading: 'ডকুমেন্ট সংরক্ষণ করা যায়নি',
|
|
9
|
+
cloudLimitModalRetry: 'পুনরায় চেষ্টা করুন',
|
|
10
|
+
cloudLimitModalReviewCollection: '{{collection}} পর্যালোচনা করুন'
|
|
11
|
+
}
|
|
12
|
+
};
|