@payloadcms/figma 0.1.0-alpha.2 → 0.1.0-alpha.4
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/check-project-subdomain-availability.d.ts +12 -0
- package/dist/api/check-project-subdomain-availability.js +32 -0
- package/dist/api/control-plane-error.d.ts +6 -0
- package/dist/api/control-plane-error.js +8 -0
- package/dist/api/control-plane-fetch.d.ts +7 -0
- package/dist/api/control-plane-fetch.js +37 -0
- package/dist/api/control-plane.d.ts +1 -9
- package/dist/api/control-plane.js +2 -48
- package/dist/api/create-project.d.ts +18 -0
- package/dist/api/create-project.js +37 -0
- package/dist/api/list-project-workspaces.d.ts +8 -0
- package/dist/api/list-project-workspaces.js +28 -0
- package/dist/api/project-resource-type.d.ts +1 -0
- package/dist/api/project-resource-type.js +1 -0
- package/dist/auth/headless-oauth-flow.d.ts +23 -0
- package/dist/auth/headless-oauth-flow.js +69 -0
- package/dist/auth/oauth-flow.d.ts +2 -0
- package/dist/auth/oauth-flow.js +13 -8
- package/dist/auth/token-store.d.ts +4 -1
- package/dist/auth/token-store.js +14 -0
- package/dist/auth/types.d.ts +12 -0
- package/dist/cli.d.ts +39 -0
- package/dist/cli.js +71 -36
- package/dist/commands/bootstrap.js +2 -1
- package/dist/commands/deploy.d.ts +12 -0
- package/dist/commands/deploy.js +61 -23
- package/dist/commands/detect-project-resource-type.d.ts +3 -0
- package/dist/commands/detect-project-resource-type.js +28 -0
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.js +163 -78
- package/dist/commands/login.d.ts +11 -1
- package/dist/commands/login.js +66 -4
- package/dist/commands/prompt-to-create-project/format-project-subdomain.d.ts +1 -0
- package/dist/commands/prompt-to-create-project/format-project-subdomain.js +3 -0
- package/dist/commands/prompt-to-create-project/format-unavailable-subdomain-reason.d.ts +1 -0
- package/dist/commands/prompt-to-create-project/format-unavailable-subdomain-reason.js +7 -0
- package/dist/commands/prompt-to-create-project/get-default-project-name.d.ts +1 -0
- package/dist/commands/prompt-to-create-project/get-default-project-name.js +13 -0
- package/dist/commands/prompt-to-create-project/prompt-for-available-subdomain.d.ts +7 -0
- package/dist/commands/prompt-to-create-project/prompt-for-available-subdomain.js +32 -0
- package/dist/commands/prompt-to-create-project/resolve-project-region.d.ts +8 -0
- package/dist/commands/prompt-to-create-project/resolve-project-region.js +27 -0
- package/dist/commands/prompt-to-create-project/resolve-project-subdomain.d.ts +9 -0
- package/dist/commands/prompt-to-create-project/resolve-project-subdomain.js +54 -0
- package/dist/commands/prompt-to-create-project/resolve-text-input.d.ts +9 -0
- package/dist/commands/prompt-to-create-project/resolve-text-input.js +23 -0
- package/dist/commands/prompt-to-create-project/resolve-workspace-plan-key.d.ts +12 -0
- package/dist/commands/prompt-to-create-project/resolve-workspace-plan-key.js +36 -0
- package/dist/commands/prompt-to-create-project/validate-subdomain.d.ts +1 -0
- package/dist/commands/prompt-to-create-project/validate-subdomain.js +9 -0
- package/dist/commands/prompt-to-create-project.d.ts +24 -0
- package/dist/commands/prompt-to-create-project.js +69 -0
- package/dist/commands/setup-agent.d.ts +12 -0
- package/dist/commands/setup-agent.js +123 -0
- package/dist/commands/write-project-configuration.d.ts +12 -0
- package/dist/commands/write-project-configuration.js +16 -0
- package/dist/db-content-api/index.d.ts +1 -1
- package/dist/db-content-api/index.js +90 -55
- package/dist/db-content-api/utilities/data/injectGlobalType.d.ts +6 -0
- package/dist/db-content-api/utilities/data/injectGlobalType.js +11 -0
- package/dist/db-content-api/utilities/data/stringifyNumericIds.d.ts +1 -0
- package/dist/db-content-api/utilities/data/stringifyNumericIds.js +19 -0
- package/dist/db-content-api/utilities/isRecord.d.ts +9 -0
- package/dist/db-content-api/utilities/isRecord.js +19 -0
- 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/db-content-api/utilities/where.js +6 -4
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.js +2 -0
- package/dist/lib/write-agent-config.d.ts +12 -0
- package/dist/lib/write-agent-config.js +52 -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/skills/deploy-to-figma/SKILL.md +234 -0
- package/dist/skills/deploy-to-figma/references/cli-reference.md +146 -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 +11 -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/lambda-config.js +4 -14
- package/dist/utils/messages.js +24 -3
- package/dist/utils/payload-generate.d.ts +10 -0
- package/dist/utils/payload-generate.js +59 -0
- package/dist/utils/pnpm-builds.d.ts +14 -0
- package/dist/utils/pnpm-builds.js +125 -0
- package/package.json +6 -5
- package/dist/lib/download-skill.d.ts +0 -12
- package/dist/lib/download-skill.js +0 -77
|
@@ -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
|
+
};
|