headroom-cms 0.1.11 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/.well-known/headroom.json +9 -0
- package/admin/assets/{AdminsPage-BnzH9TL3.js → AdminsPage-DUMTsCEp.js} +1 -1
- package/admin/assets/{AllContentPage-BtObN6oy.js → AllContentPage-D5ey5AOV.js} +1 -1
- package/admin/assets/{ApiKeysPage-DEAa8eyC.js → ApiKeysPage-CzUOSoz_.js} +1 -1
- package/admin/assets/{AuditPage-BN9yNsxh.js → AuditPage-CYAg4dbI.js} +1 -1
- package/admin/assets/BackupsPage-04_oMy3v.js +1 -0
- package/admin/assets/{BlockEditor-3wnisTOZ.js → BlockEditor-s0CRZsjy.js} +3 -3
- package/admin/assets/BlockTypeEditPage-D1OFIlJZ.js +1 -0
- package/admin/assets/{BlockTypesPage-Dhkho6T_.js → BlockTypesPage-cJNR25fN.js} +1 -1
- package/admin/assets/{BulkActionBar-BxdfUSrN.js → BulkActionBar-BWysX7Wo.js} +1 -1
- package/admin/assets/{CollectionEditPage-lOb4hEZy.js → CollectionEditPage-DRmCA_73.js} +1 -1
- package/admin/assets/{CollectionsPage-CgtOloa1.js → CollectionsPage-CeQB5e9u.js} +1 -1
- package/admin/assets/{ContentCreatePage-LeQjahp_.js → ContentCreatePage-Cq8Pi8EF.js} +1 -1
- package/admin/assets/ContentEditPage-CEJ7I3WH.js +1 -0
- package/admin/assets/{ContentField-pilCbdnA.js → ContentField-BZT4OUfI.js} +1 -1
- package/admin/assets/ContentListPage-BCEQrYVs.js +1 -0
- package/admin/assets/{CustomBlockPreview-DNnTFM0z.js → CustomBlockPreview-Kc6bb3oq.js} +1 -1
- package/admin/assets/FieldRenderer-CT-DgCbC.js +2 -0
- package/admin/assets/FileTypeIcon-CNHtffHC.js +1 -0
- package/admin/assets/FloatingComposerController-D4uLQfUX-0_Y8mkGU.js +1 -0
- package/admin/assets/{IconPicker-CpIgiQTC.js → IconPicker-BpPlHJO0.js} +2 -2
- package/admin/assets/{LoginPage-D9ZsGLIi.js → LoginPage-Dya8sF_P.js} +1 -1
- package/admin/assets/MediaField-C3qFf3g5.js +1 -0
- package/admin/assets/MediaPage-BNxc0wLq.js +1 -0
- package/admin/assets/{Pagination-Df9nQ7Z0.js → Pagination-Dx8h11Rn.js} +1 -1
- package/admin/assets/{RelationshipPicker-B3Ftmqxp.js → RelationshipPicker-C2MTxrhl.js} +1 -1
- package/admin/assets/{SiteSettingsPage-6NvH7CiQ.js → SiteSettingsPage-BDZaUBmf.js} +1 -1
- package/admin/assets/{SiteUserEditPage-D5VaQ1Xq.js → SiteUserEditPage-MfzhPW7v.js} +1 -1
- package/admin/assets/{SiteUsersPage-BYVduiqs.js → SiteUsersPage-CrYugXpx.js} +1 -1
- package/admin/assets/{SitesPage-rfWWE0yK.js → SitesPage-Cl8V3Hb7.js} +1 -1
- package/admin/assets/SubmissionDetailPage-BnVlsGb-.js +1 -0
- package/admin/assets/SubmissionEditPage-B0Kq52fb.js +1 -0
- package/admin/assets/SubmissionListPage-K665VwMp.js +1 -0
- package/admin/assets/{TagInput-57c4DG1w.js → TagInput-C6tcB5Xw.js} +1 -1
- package/admin/assets/{TagsPage-BEO5AwCv.js → TagsPage-BONR6bSu.js} +1 -1
- package/admin/assets/{UsersPage-BpIRorJ1.js → UsersPage-C2iCy0UR.js} +1 -1
- package/admin/assets/{WebhookEditPage-D5xgi56h.js → WebhookEditPage-DjZFxT72.js} +1 -1
- package/admin/assets/{WebhooksPage-BY7AaiGr.js → WebhooksPage-g_a224a4.js} +1 -1
- package/admin/assets/{card-C9hfyHXf.js → card-DlfsF8lU.js} +1 -1
- package/admin/assets/{checkbox-DVJcwUt1.js → checkbox-BX8EcGFf.js} +1 -1
- package/admin/assets/{command-Bfmj0MEL.js → command-DaTsImUa.js} +1 -1
- package/admin/assets/{contentStatus-CkPi9Dh6.js → contentStatus-WXGfd7vX.js} +1 -1
- package/admin/assets/format-BRcflvs9.js +1 -0
- package/admin/assets/index-9sbb3-yI.css +1 -0
- package/admin/assets/{index-Ce5pmRMj.js → index-DC1UyCW2.js} +10 -10
- package/admin/assets/listCellValue-CBqXAwce.js +1 -0
- package/admin/assets/{popover-CzaQYEEP.js → popover-BA-47SRI.js} +1 -1
- package/admin/assets/{select-CrRhFGIi.js → select-waaVyoQ5.js} +1 -1
- package/admin/assets/{serializeToText-2VrsuRUh.js → serializeToText-CjHhyvXp.js} +1 -1
- package/admin/assets/{table-_3bMY0_z.js → table-Br-QgtTL.js} +1 -1
- package/admin/assets/{textarea-6fq0R6VV.js → textarea-BILv1DQB.js} +1 -1
- package/admin/assets/useAdminResolver-CbDzGoDp.js +1 -0
- package/admin/assets/useContent-Bp4f9qe0.js +1 -0
- package/admin/assets/{useContentSearch-B3aTjuCu.js → useContentSearch-DbiA8aG-.js} +1 -1
- package/admin/assets/{usePageTitle-C1r1-C00.js → usePageTitle-DOEFrHbj.js} +1 -1
- package/admin/assets/{useSiteUsers-DIaqgNSp.js → useSiteUsers-BFYAbJNT.js} +1 -1
- package/admin/assets/{useTags-B-HgMVwo.js → useTags-DJlXwDyc.js} +1 -1
- package/admin/assets/{useWebhooks-BvZjUJkJ.js → useWebhooks-BkpJKNLN.js} +1 -1
- package/admin/index.html +2 -2
- package/admin/sw.js +1 -1
- package/admin/workbox-362996ec.js +1 -0
- package/dist/admin-site.d.ts.map +1 -1
- package/dist/admin-site.js +46 -3
- package/dist/admin-site.js.map +1 -1
- package/dist/api.d.ts +2 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +57 -5
- package/dist/api.js.map +1 -1
- package/dist/backup.d.ts +29 -0
- package/dist/backup.d.ts.map +1 -0
- package/dist/backup.js +95 -0
- package/dist/backup.js.map +1 -0
- package/dist/cdn-api.d.ts.map +1 -1
- package/dist/cdn-api.js +20 -19
- package/dist/cdn-api.js.map +1 -1
- package/dist/image.d.ts +8 -1
- package/dist/image.d.ts.map +1 -1
- package/dist/image.js +26 -6
- package/dist/image.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -1
- package/dist/index.js.map +1 -1
- package/dist/storage.d.ts +1 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +21 -0
- package/dist/storage.js.map +1 -1
- package/dist/webhooks.d.ts +4 -3
- package/dist/webhooks.d.ts.map +1 -1
- package/dist/webhooks.js +22 -35
- package/dist/webhooks.js.map +1 -1
- package/lambda/api/bootstrap +0 -0
- package/lambda/backup-worker/bootstrap +0 -0
- package/lambda/image-lambda/index.mjs +30 -6
- package/lambda/image-lambda/node_modules/.package-lock.json +3 -3
- package/lambda/image-lambda/node_modules/semver/classes/range.js +7 -0
- package/lambda/image-lambda/node_modules/semver/package.json +1 -1
- package/lambda/image-lambda/node_modules/semver/ranges/subset.js +2 -2
- package/lambda/webhook-worker/bootstrap +0 -0
- package/package.json +1 -1
- package/src/admin-site.ts +46 -3
- package/src/api.ts +58 -5
- package/src/backup.ts +114 -0
- package/src/cdn-api.ts +20 -22
- package/src/image.ts +30 -6
- package/src/index.ts +37 -1
- package/src/sst-env.d.ts +4 -0
- package/src/storage.ts +22 -0
- package/src/webhooks.ts +22 -39
- package/admin/assets/BlockTypeEditPage-C2evAESK.js +0 -1
- package/admin/assets/ContentEditPage-xczr4d_h.js +0 -1
- package/admin/assets/ContentListPage-BAKDn1Xy.js +0 -1
- package/admin/assets/FieldRenderer-DiOKvkWV.js +0 -2
- package/admin/assets/FilterBar-BZoa63zh.js +0 -1
- package/admin/assets/FloatingComposerController-D4uLQfUX-BMIvFCoE.js +0 -1
- package/admin/assets/MediaField-CxccCFGQ.js +0 -1
- package/admin/assets/MediaPage-QvMaH2YJ.js +0 -1
- package/admin/assets/SubmissionDetailPage-BSUR685F.js +0 -1
- package/admin/assets/SubmissionEditPage-DjLXHjWU.js +0 -1
- package/admin/assets/SubmissionListPage-DBxNEvde.js +0 -1
- package/admin/assets/format-C88SDH8g.js +0 -1
- package/admin/assets/index-BB9Syqw2.css +0 -1
- package/admin/assets/useAdminResolver-BJNPz3OG.js +0 -1
- package/admin/assets/useContent-Bs7nel7C.js +0 -1
- package/admin/assets/useMedia-ae3s_ajC.js +0 -1
- package/admin/workbox-7d58179f.js +0 -1
package/src/image.ts
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Sharp-based image transformation Lambda with HMAC-signed URLs.
|
|
5
5
|
* Supports dev mode (Node.js source) and package mode (pre-bundled handler).
|
|
6
|
+
*
|
|
7
|
+
* The signing key is per-site: the Lambda derives it from a master KDF
|
|
8
|
+
* input (HMAC-SHA256(master, site)) so leaking one site's key cannot be
|
|
9
|
+
* used to forge URLs for another site. The OLD master is an opt-in
|
|
10
|
+
* fallback for smooth rotation — the Sharp Lambda accepts either, the Go
|
|
11
|
+
* API only signs with the primary.
|
|
6
12
|
*/
|
|
7
13
|
|
|
8
14
|
import path from "path";
|
|
@@ -18,7 +24,15 @@ export interface ImageArgs {
|
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
export function createImage(name: string, args: ImageArgs) {
|
|
21
|
-
const
|
|
27
|
+
const imageSigningMasterSecret = new sst.Secret(
|
|
28
|
+
`${name}ImageSigningMasterSecret`,
|
|
29
|
+
);
|
|
30
|
+
// Optional fallback master used during rotation. SST treats unset
|
|
31
|
+
// secrets as empty strings, which the Lambda's deriveSiteSecret turns
|
|
32
|
+
// into a null per-site key — disabling the fallback path entirely.
|
|
33
|
+
const imageSigningMasterSecretOld = new sst.Secret(
|
|
34
|
+
`${name}ImageSigningMasterSecretOld`,
|
|
35
|
+
);
|
|
22
36
|
|
|
23
37
|
let imageLambda: sst.aws.Function;
|
|
24
38
|
if (args.dev) {
|
|
@@ -36,9 +50,14 @@ export function createImage(name: string, args: ImageArgs) {
|
|
|
36
50
|
},
|
|
37
51
|
environment: {
|
|
38
52
|
CONTENT_BUCKET: args.contentBucket.name,
|
|
39
|
-
|
|
53
|
+
IMAGE_SIGNING_MASTER_SECRET: imageSigningMasterSecret.value,
|
|
54
|
+
IMAGE_SIGNING_MASTER_SECRET_OLD: imageSigningMasterSecretOld.value,
|
|
40
55
|
},
|
|
41
|
-
link: [
|
|
56
|
+
link: [
|
|
57
|
+
args.contentBucket,
|
|
58
|
+
imageSigningMasterSecret,
|
|
59
|
+
imageSigningMasterSecretOld,
|
|
60
|
+
],
|
|
42
61
|
});
|
|
43
62
|
} else {
|
|
44
63
|
imageLambda = new sst.aws.Function(`${name}ImageLambda`, {
|
|
@@ -53,13 +72,18 @@ export function createImage(name: string, args: ImageArgs) {
|
|
|
53
72
|
},
|
|
54
73
|
environment: {
|
|
55
74
|
CONTENT_BUCKET: args.contentBucket.name,
|
|
56
|
-
|
|
75
|
+
IMAGE_SIGNING_MASTER_SECRET: imageSigningMasterSecret.value,
|
|
76
|
+
IMAGE_SIGNING_MASTER_SECRET_OLD: imageSigningMasterSecretOld.value,
|
|
57
77
|
},
|
|
58
|
-
link: [
|
|
78
|
+
link: [
|
|
79
|
+
args.contentBucket,
|
|
80
|
+
imageSigningMasterSecret,
|
|
81
|
+
imageSigningMasterSecretOld,
|
|
82
|
+
],
|
|
59
83
|
});
|
|
60
84
|
}
|
|
61
85
|
|
|
62
|
-
return {
|
|
86
|
+
return { imageSigningMasterSecret, imageSigningMasterSecretOld, imageLambda };
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
export type ImageResources = ReturnType<typeof createImage>;
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import path from "path";
|
|
|
10
10
|
import { createStorage } from "./storage.js";
|
|
11
11
|
import { createAuth } from "./auth.js";
|
|
12
12
|
import { createWebhooks } from "./webhooks.js";
|
|
13
|
+
import { createBackup } from "./backup.js";
|
|
13
14
|
import { createImage } from "./image.js";
|
|
14
15
|
import { createApi } from "./api.js";
|
|
15
16
|
import { createApiCdn } from "./cdn-api.js";
|
|
@@ -48,6 +49,7 @@ function resolvePkgRoot(): string {
|
|
|
48
49
|
export type { StorageResources } from "./storage.js";
|
|
49
50
|
export type { AuthResources } from "./auth.js";
|
|
50
51
|
export type { WebhookResources } from "./webhooks.js";
|
|
52
|
+
export type { BackupResources } from "./backup.js";
|
|
51
53
|
export type { ImageResources } from "./image.js";
|
|
52
54
|
export type { ApiResources } from "./api.js";
|
|
53
55
|
export type { ApiCdnResources } from "./cdn-api.js";
|
|
@@ -127,6 +129,8 @@ export interface HeadroomCMSArgs {
|
|
|
127
129
|
apiHandler: string;
|
|
128
130
|
/** Go source path for webhook worker, e.g. "packages/webhook-worker" */
|
|
129
131
|
webhookWorkerHandler: string;
|
|
132
|
+
/** Go source path for backup worker, e.g. "packages/backup-worker" */
|
|
133
|
+
backupWorkerHandler: string;
|
|
130
134
|
/** SST handler for custom message function, e.g. "packages/functions/custom-message.handler" */
|
|
131
135
|
customMessageHandler: string;
|
|
132
136
|
/** SST handler for image Lambda, e.g. "packages/image-lambda/index.handler" */
|
|
@@ -177,7 +181,7 @@ export class HeadroomCMS {
|
|
|
177
181
|
: undefined,
|
|
178
182
|
});
|
|
179
183
|
|
|
180
|
-
// 3. Webhooks (DynamoDB tables,
|
|
184
|
+
// 3. Webhooks (DynamoDB tables, DLQ, worker Lambda)
|
|
181
185
|
const webhooks = createWebhooks(name, {
|
|
182
186
|
sites: storage.sites,
|
|
183
187
|
pkgRoot,
|
|
@@ -186,6 +190,18 @@ export class HeadroomCMS {
|
|
|
186
190
|
: undefined,
|
|
187
191
|
});
|
|
188
192
|
|
|
193
|
+
// 3b. Backup worker Lambda (export + restore). Needs access to every
|
|
194
|
+
// site-scoped table plus the content + backup buckets. Created after
|
|
195
|
+
// webhooks so it can link the webhooks table for backup payloads.
|
|
196
|
+
const backup = createBackup(name, {
|
|
197
|
+
storage,
|
|
198
|
+
webhooks,
|
|
199
|
+
pkgRoot,
|
|
200
|
+
dev: args.dev
|
|
201
|
+
? { handler: args.dev.backupWorkerHandler }
|
|
202
|
+
: undefined,
|
|
203
|
+
});
|
|
204
|
+
|
|
189
205
|
// 4. Image Lambda (Sharp transform with HMAC-signed URLs)
|
|
190
206
|
const image = createImage(name, {
|
|
191
207
|
contentBucket: storage.contentBucket,
|
|
@@ -204,6 +220,7 @@ export class HeadroomCMS {
|
|
|
204
220
|
storage,
|
|
205
221
|
auth,
|
|
206
222
|
webhooks,
|
|
223
|
+
backup,
|
|
207
224
|
image,
|
|
208
225
|
collab: collabTable,
|
|
209
226
|
senderEmail: args.senderEmail,
|
|
@@ -289,6 +306,25 @@ export class HeadroomCMS {
|
|
|
289
306
|
userPoolId: auth.userPool.id,
|
|
290
307
|
userPoolClientId: auth.userPoolClient.id,
|
|
291
308
|
collabWs: collab.wsUrl,
|
|
309
|
+
// DynamoDB table names (with Pulumi-generated random suffixes baked
|
|
310
|
+
// in). Exposed so consumers — notably the Phase 6 E2E test harness —
|
|
311
|
+
// can discover real table names rather than guess them from the
|
|
312
|
+
// `<app>-<stage>-<Name>` template (which omits the random suffix).
|
|
313
|
+
// Per CLAUDE.md, `.sst/outputs.json` IS the supported interface for
|
|
314
|
+
// post-deploy discovery.
|
|
315
|
+
sitesTable: storage.sites.name,
|
|
316
|
+
contentTable: storage.content.name,
|
|
317
|
+
draftContentTable: storage.draftContent.name,
|
|
318
|
+
blocksTable: storage.blocks.name,
|
|
319
|
+
mediaTable: storage.media.name,
|
|
320
|
+
collectionsTable: storage.collections.name,
|
|
321
|
+
blockTypesTable: storage.blockTypes.name,
|
|
322
|
+
adminAuditTable: storage.adminAudit.name,
|
|
323
|
+
relationshipsTable: storage.relationships.name,
|
|
324
|
+
siteUsersTable: storage.siteUsers.name,
|
|
325
|
+
webhooksTable: webhooks.webhooks.name,
|
|
326
|
+
contentBucket: storage.contentBucket.name,
|
|
327
|
+
backupBucket: storage.backupBucket.name,
|
|
292
328
|
};
|
|
293
329
|
}
|
|
294
330
|
}
|
package/src/sst-env.d.ts
CHANGED
package/src/storage.ts
CHANGED
|
@@ -39,15 +39,23 @@ export function createStorage(name: string) {
|
|
|
39
39
|
fields: {
|
|
40
40
|
pk: "string",
|
|
41
41
|
sk: "string",
|
|
42
|
+
siteHost: "string",
|
|
42
43
|
},
|
|
43
44
|
primaryIndex: { hashKey: "pk", rangeKey: "sk" },
|
|
45
|
+
globalIndexes: {
|
|
46
|
+
bySite: { hashKey: "siteHost", rangeKey: "sk" },
|
|
47
|
+
},
|
|
44
48
|
});
|
|
45
49
|
|
|
46
50
|
const blocks = new sst.aws.Dynamo(`${name}Blocks`, {
|
|
47
51
|
fields: {
|
|
48
52
|
pk: "string",
|
|
53
|
+
siteHost: "string",
|
|
49
54
|
},
|
|
50
55
|
primaryIndex: { hashKey: "pk" },
|
|
56
|
+
globalIndexes: {
|
|
57
|
+
bySite: { hashKey: "siteHost", rangeKey: "pk" },
|
|
58
|
+
},
|
|
51
59
|
});
|
|
52
60
|
|
|
53
61
|
const media = new sst.aws.Dynamo(`${name}Media`, {
|
|
@@ -94,10 +102,12 @@ export function createStorage(name: string) {
|
|
|
94
102
|
sk: "string",
|
|
95
103
|
targetPk: "string",
|
|
96
104
|
targetSk: "string",
|
|
105
|
+
siteHost: "string",
|
|
97
106
|
},
|
|
98
107
|
primaryIndex: { hashKey: "pk", rangeKey: "sk" },
|
|
99
108
|
globalIndexes: {
|
|
100
109
|
byTarget: { hashKey: "targetPk", rangeKey: "targetSk" },
|
|
110
|
+
bySite: { hashKey: "siteHost", rangeKey: "sk" },
|
|
101
111
|
},
|
|
102
112
|
});
|
|
103
113
|
|
|
@@ -106,14 +116,25 @@ export function createStorage(name: string) {
|
|
|
106
116
|
pk: "string",
|
|
107
117
|
sk: "string",
|
|
108
118
|
userId: "string",
|
|
119
|
+
siteHost: "string",
|
|
109
120
|
},
|
|
110
121
|
primaryIndex: { hashKey: "pk", rangeKey: "sk" },
|
|
111
122
|
globalIndexes: {
|
|
112
123
|
byUserId: { hashKey: "userId", rangeKey: "sk" },
|
|
124
|
+
bySite: { hashKey: "siteHost", rangeKey: "sk" },
|
|
113
125
|
},
|
|
114
126
|
ttl: "expiresAt",
|
|
115
127
|
});
|
|
116
128
|
|
|
129
|
+
// Backup bucket: archives of full site exports written by the backup worker.
|
|
130
|
+
// Layout: backups/{host}/{timestamp}.tar.gz + backups/{host}/latest.json.
|
|
131
|
+
// Versioning disabled — archives are immutable by convention (a new timestamp
|
|
132
|
+
// is a new object). No CloudFront origin — admin endpoints serve presigned
|
|
133
|
+
// URLs directly off S3.
|
|
134
|
+
const backupBucket = new sst.aws.Bucket(`${name}BackupBucket`, {
|
|
135
|
+
versioning: false,
|
|
136
|
+
});
|
|
137
|
+
|
|
117
138
|
const contentBucket = new sst.aws.Bucket(`${name}ContentBucket`, {
|
|
118
139
|
versioning: true,
|
|
119
140
|
access: "cloudfront",
|
|
@@ -181,6 +202,7 @@ export function createStorage(name: string) {
|
|
|
181
202
|
relationships,
|
|
182
203
|
siteUsers,
|
|
183
204
|
contentBucket,
|
|
205
|
+
backupBucket,
|
|
184
206
|
collabStateBucket,
|
|
185
207
|
kvs,
|
|
186
208
|
internalSecret,
|
package/src/webhooks.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Webhook Infrastructure
|
|
3
3
|
*
|
|
4
|
-
* 2 DynamoDB tables +
|
|
5
|
-
*
|
|
4
|
+
* 2 DynamoDB tables + webhook worker Lambda (async-invoked by the API) + DLQ
|
|
5
|
+
* (Lambda async on-failure destination). The API directly invokes the worker
|
|
6
|
+
* via lambda:InvokeFunction; there is no SQS queue between them.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import path from "path";
|
|
@@ -35,6 +36,9 @@ export function createWebhooks(name: string, args: WebhookArgs) {
|
|
|
35
36
|
ttl: "ttl",
|
|
36
37
|
});
|
|
37
38
|
|
|
39
|
+
// DLQ retained as Lambda async OnFailure destination. Lambda writes a
|
|
40
|
+
// failure envelope (not the original payload verbatim) when retries are
|
|
41
|
+
// exhausted. No consumer polls this queue — it's a sink only.
|
|
38
42
|
const webhookDeliveryDLQ = new sst.aws.Queue(`${name}WebhookDeliveryDLQ`, {
|
|
39
43
|
transform: {
|
|
40
44
|
queue: (queueArgs: any) => {
|
|
@@ -43,26 +47,6 @@ export function createWebhooks(name: string, args: WebhookArgs) {
|
|
|
43
47
|
},
|
|
44
48
|
});
|
|
45
49
|
|
|
46
|
-
const webhookDeliveryQueue = new sst.aws.Queue(
|
|
47
|
-
`${name}WebhookDeliveryQueue`,
|
|
48
|
-
{
|
|
49
|
-
dlq: {
|
|
50
|
-
queue: webhookDeliveryDLQ.arn,
|
|
51
|
-
retry: 5,
|
|
52
|
-
},
|
|
53
|
-
transform: {
|
|
54
|
-
queue: (queueArgs: any) => {
|
|
55
|
-
queueArgs.visibilityTimeoutSeconds = 60;
|
|
56
|
-
queueArgs.messageRetentionSeconds = 4 * 24 * 60 * 60; // 4 days
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
// Webhook worker Lambda: processes SQS messages and delivers webhooks.
|
|
63
|
-
// Note: We use a manual Function + EventSourceMapping instead of
|
|
64
|
-
// queue.subscribe() to avoid a duplicate LambdaEncryptionKey issue
|
|
65
|
-
// caused by SST's dynamic import creating a separate Function class instance.
|
|
66
50
|
const workerConfig = args.dev
|
|
67
51
|
? {
|
|
68
52
|
handler: args.dev.handler,
|
|
@@ -81,32 +65,31 @@ export function createWebhooks(name: string, args: WebhookArgs) {
|
|
|
81
65
|
timeout: "30 seconds",
|
|
82
66
|
environment: {
|
|
83
67
|
WEBHOOK_DELIVERIES_TABLE: webhookDeliveries.name,
|
|
84
|
-
WEBHOOKS_TABLE: webhooks.name,
|
|
85
|
-
SITES_TABLE: args.sites.name,
|
|
86
68
|
},
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"sqs:GetQueueAttributes",
|
|
94
|
-
],
|
|
95
|
-
resources: [webhookDeliveryQueue.arn],
|
|
96
|
-
},
|
|
97
|
-
],
|
|
69
|
+
// webhookDeliveryDLQ is linked so SST auto-grants sqs:SendMessage on the
|
|
70
|
+
// worker's execution role. Lambda async OnFailure delivery uses the
|
|
71
|
+
// function's own role to write the failure envelope to the DLQ — without
|
|
72
|
+
// this grant, AWS accepts the FunctionEventInvokeConfig at deploy time but
|
|
73
|
+
// silently drops failure envelopes at runtime.
|
|
74
|
+
link: [webhookDeliveries, webhookDeliveryDLQ],
|
|
98
75
|
});
|
|
99
76
|
|
|
100
|
-
|
|
101
|
-
|
|
77
|
+
// Lambda async retry + DLQ on terminal failure. MaximumRetryAttempts is
|
|
78
|
+
// 0–2 (industry standard for webhook delivery — Stripe/GitHub publish
|
|
79
|
+
// similar caps). Total attempts = initial + 2 retries = 3.
|
|
80
|
+
new aws.lambda.FunctionEventInvokeConfig(`${name}WebhookWorkerAsyncConfig`, {
|
|
102
81
|
functionName: webhookWorker.name,
|
|
103
|
-
|
|
82
|
+
maximumRetryAttempts: 2,
|
|
83
|
+
maximumEventAgeInSeconds: 6 * 60 * 60, // 6 hours
|
|
84
|
+
destinationConfig: {
|
|
85
|
+
onFailure: { destination: webhookDeliveryDLQ.arn },
|
|
86
|
+
},
|
|
104
87
|
});
|
|
105
88
|
|
|
106
89
|
return {
|
|
107
90
|
webhooks,
|
|
108
91
|
webhookDeliveries,
|
|
109
|
-
|
|
92
|
+
webhookWorker,
|
|
110
93
|
webhookDeliveryDLQ,
|
|
111
94
|
};
|
|
112
95
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{j as e}from"./tanstack-Bs3zYPPV.js";import{u as R,f as U,r as o}from"./react-vendor-C2CvUxFh.js";import{W as b,aF as V,S as T,aG as G,aH as W,aI as z,x as J,L as u,I as K,a0 as B,B as x,a as Q,D as X,i as Y,T as Z,k as ee,l as se,m as te,n as ae,o as ie,v as h}from"./index-Ce5pmRMj.js";import{I as ne,a as re,F as le}from"./IconPicker-CpIgiQTC.js";import{i as oe}from"./format-C88SDH8g.js";import{T as ce}from"./textarea-6fq0R6VV.js";import{C as de,a as me,b as pe,c as ue}from"./card-C9hfyHXf.js";import{C as $,a as D,b as F}from"./collapsible-D3d29uJp.js";import{C as xe}from"./CustomBlockPreview-DNnTFM0z.js";import{F as he}from"./FieldRenderer-DiOKvkWV.js";import{u as N}from"./useContentSearch-B3aTjuCu.js";import{u as je}from"./usePageTitle-C1r1-C00.js";import"./radix-C5ZmWuuL.js";import"./core.esm-DdQHdRkd.js";import"./sortable.esm-qVEMoaTg.js";import"./select-CrRhFGIi.js";import"./checkbox-DVJcwUt1.js";import"./popover-CzaQYEEP.js";import"./media-url-DdCoIedP.js";import"./MediaField-CxccCFGQ.js";import"./useMedia-ae3s_ajC.js";import"./ContentField-pilCbdnA.js";import"./command-Bfmj0MEL.js";function fe({fields:a,previewTemplate:s,previewData:t,onPreviewDataChange:i,blockTypeName:l,blockTypeLabel:d,blockTypeIcon:v}){const n=N(s,300),g=N(t,300);return e.jsxs("div",{className:"space-y-4",children:[e.jsx(he,{fields:a,values:t,onChange:i}),e.jsx(b,{}),e.jsx("div",{className:"overflow-hidden rounded-md border p-4",children:e.jsx(xe,{blockType:{name:l,label:d,icon:v,fields:a,previewTemplate:n},props:g,blocksToHTML:()=>""})})]})}function Ue(){const{host:a,name:s}=R(),t=s==="new",{data:i,isLoading:l}=V(a,t?"":s);return!t&&l?e.jsxs("div",{className:"space-y-4",children:[e.jsx(T,{className:"h-8 w-64"}),e.jsx(T,{className:"h-64 w-full"})]}):t?e.jsx(C,{host:a,isNew:!0}):i?e.jsx(C,{host:a,isNew:!1,blockType:i},i.name):e.jsx("p",{className:"text-muted-foreground",children:"Block type not found."})}function C({host:a,isNew:s,blockType:t}){const i=U(),l=G(a),d=W(a,t?.name??""),v=z(a,t?.name??""),[n,g]=o.useState(t?.name??""),[j,y]=o.useState(t?.label??""),[f,P]=o.useState(t?.icon??""),[S,L]=o.useState(!s),I=new Set((t?.fields??[]).map(r=>r.name).filter(Boolean)),[c,E]=o.useState(t?.fields??[]),[m,O]=o.useState(t?.previewTemplate??""),[p,q]=o.useState(t?.previewData??{}),[H,w]=o.useState(!1),_=J();je({title:s?"New Block Type":t?.label??n,showBack:!0,backTo:`/sites/${a}/settings/block-types`});async function A(r){r.preventDefault();try{s?(await l.mutateAsync({name:n,label:j,icon:f,fields:c,previewTemplate:m||void 0,previewData:Object.keys(p).length>0?p:void 0}),h.success("Block type created"),i(`/sites/${a}/settings/block-types/${n}`)):(await d.mutateAsync({label:j,icon:f,fields:c,previewTemplate:m||void 0,previewData:Object.keys(p).length>0?p:void 0}),h.success("Block type updated"))}catch(k){h.error(s?"Failed to create":"Failed to update",{description:k instanceof Error?k.message:void 0})}}async function M(){try{await v.mutateAsync(),h.success("Block type deleted"),i(`/sites/${a}/settings/block-types`)}catch(r){h.error("Failed to delete",{description:r instanceof Error?r.message:void 0})}}return e.jsxs("div",{className:"mx-auto max-w-2xl",children:[!_&&e.jsx("h1",{className:"mb-6 text-2xl font-semibold",children:s?"New Block Type":`Edit: ${t?.label??n}`}),e.jsxs(de,{children:[e.jsx(me,{children:e.jsx(pe,{children:"Block Type Settings"})}),e.jsx(ue,{children:e.jsxs("form",{onSubmit:A,className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(u,{htmlFor:"name",children:"Name"}),e.jsx(ne,{id:"name",value:n,onChange:g,onBlur:()=>{n&&!S&&y(oe(n))},readOnly:!s,placeholder:"e.g. hero_banner",required:!0})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(u,{htmlFor:"label",children:"Label"}),e.jsx(K,{id:"label",value:j,onChange:r=>{y(r.target.value),L(!0)},required:!0})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(u,{children:"Icon"}),e.jsx(re,{value:f,onChange:P})]}),e.jsx(b,{}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(u,{children:"Block Fields"}),e.jsx(le,{fields:c,onChange:E,existingFieldNames:I})]}),e.jsx(b,{}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(u,{htmlFor:"preview-template",children:"Preview Template (Liquid + Tailwind)"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Optional. Use Liquid syntax to render a preview. Tailwind utility classes are supported."}),e.jsx(ce,{id:"preview-template",value:m,onChange:r=>O(r.target.value),rows:6,placeholder:'<div class="p-4">{{ title }}</div>',className:"font-mono text-sm"}),c.length>0&&e.jsx(ge,{fields:c})]}),(m||c.length>0)&&e.jsxs($,{children:[e.jsxs(D,{className:"flex w-full items-center gap-2 text-sm font-medium",children:[e.jsx(B,{className:"h-4 w-4 transition-transform [[data-state=open]>&]:rotate-90"}),"Preview"]}),e.jsx(F,{className:"mt-2",children:e.jsx(fe,{fields:c,previewTemplate:m,previewData:p,onPreviewDataChange:q,blockTypeName:n,blockTypeLabel:j,blockTypeIcon:f})})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(x,{type:"submit",disabled:l.isPending||d.isPending,children:[(l.isPending||d.isPending)&&e.jsx(Q,{className:"mr-2 h-4 w-4 animate-spin"}),s?"Create":"Save"]}),e.jsx(x,{type:"button",variant:"outline",onClick:()=>i(`/sites/${a}/settings/block-types`),children:"Cancel"})]})]})})]}),!s&&e.jsx("div",{className:"mt-6",children:e.jsxs(X,{open:H,onOpenChange:w,children:[e.jsx(Y,{asChild:!0,children:e.jsxs(x,{variant:"destructive",children:[e.jsx(Z,{className:"mr-2 h-4 w-4"}),"Delete Block Type"]})}),e.jsxs(ee,{children:[e.jsxs(se,{children:[e.jsx(te,{children:"Delete block type?"}),e.jsx(ae,{children:"This will permanently delete this block type."})]}),e.jsxs(ie,{children:[e.jsx(x,{variant:"outline",onClick:()=>w(!1),children:"Cancel"}),e.jsx(x,{variant:"destructive",onClick:M,children:"Delete"})]})]})]})})]})}function ve(a){const s=a.name;switch(a.type){case"media":return`{{ ${s}.url | media_url }} {{ ${s}.alt }} {{ ${s}.width }}`;case"content":return`{{ ${s}.title }} {{ ${s}.id }}`;case"boolean":return`{% if ${s} %}...{% endif %}`;case"array":{const t=a.options?.itemFields;if(t&&t.length>0){const i=t.map(l=>`item.${l.name}`).join(" }} {{ ");return`{% for item in ${s} %}{{ ${i} }}{% endfor %}`}return`{% for item in ${s} %}{{ item }}{% endfor %}`}case"select":return a.options?.multiple?`{% for item in ${s} %}{{ item }}{% endfor %}`:`{{ ${s} }}`;case"container":{const t=a.options?.fields;return t&&t.length>0?t.map(i=>`{{ ${s}.${i.name} }}`).join(" "):`{{ ${s}.fieldName }}`}case"blocks":return`{{ ${s} | blocks_html }} or {{ ${s} | blocks_text }}`;default:return`{{ ${s} }}`}}function ge({fields:a}){return e.jsxs($,{children:[e.jsxs(D,{className:"flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground",children:[e.jsx(B,{className:"h-3 w-3 transition-transform [[data-state=open]>&]:rotate-90"}),"Template variables"]}),e.jsx(F,{children:e.jsx("div",{className:"mt-1 rounded-md border bg-muted/50 p-2 font-mono text-xs space-y-0.5",children:a.map(s=>e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("span",{className:"text-muted-foreground shrink-0",children:[s.label,":"]}),e.jsx("code",{children:ve(s)})]},s.name))})})]})}export{Ue as BlockTypeEditPage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as Bs,u as Pn,b as En,j as e}from"./tanstack-Bs3zYPPV.js";import{r as s,u as Ln,f as Tn,m as In,L as Un}from"./react-vendor-C2CvUxFh.js";import{f as Fn,g as St,h as On,i as Ct,j as Bn,k as qn,l as $n,m as Vn,n as _n,o as Mn,p as Hn,q as Jn,r as wt}from"./useContent-Bs7nel7C.js";import{C as Ee,v as V,E as qs,e as ls,u as $s,F as zn,G as Ss,B as P,y as cs,J as Kn,K as Yn,M as Qn,N as Gn,S as fe,O as Rt,Q as Nt,R as ns,V as as,W as Dt,Y as At,Z as Pt,_ as Et,U as Wn,$ as Xn,w as Zn,d as ea,x as sa,L as Ze,I as it,a0 as Lt,X as rt,a1 as ta,a2 as lt,a3 as na,a4 as ct,a5 as aa,j as ia,a as ve,a6 as ot,a7 as dt,a8 as ra,a9 as ut,aa as Cs,ab as la,ac as ca,D as Es,k as Ls,l as Ts,m as Is,n as Us,o as Fs,i as oa,T as da}from"./index-Ce5pmRMj.js";import{A as Tt,a as It,b as Ut,c as Ft,d as Ot,e as Bt,f as qt,g as $t,T as ua}from"./TagInput-57c4DG1w.js";import{a as ts,f as Se}from"./format-C88SDH8g.js";import{u as Vt}from"./useAdminResolver-BJNPz3OG.js";import{u as ha}from"./usePageTitle-C1r1-C00.js";import{s as Oe,T as fa,d as ma}from"./serializeToText-2VrsuRUh.js";import{S as pa,a as ga,b as ba,c as xa,d as ws,e as va,f as ya,g as ja}from"./select-CrRhFGIi.js";import{T as ka}from"./textarea-6fq0R6VV.js";import{C as Ue,c as Fe,a as ht,b as ft}from"./card-C9hfyHXf.js";import{C as _t,a as Mt,b as Ht}from"./collapsible-D3d29uJp.js";import{u as Sa}from"./useTags-B-HgMVwo.js";import{M as Ca}from"./MediaField-CxccCFGQ.js";import{m as wa}from"./media-url-DdCoIedP.js";import{R as Ra}from"./RelationshipPicker-B3Ftmqxp.js";import{A as Na,a as Da,i as Aa,F as Pa,b as es,C as Ea}from"./FieldRenderer-DiOKvkWV.js";import{g as La,a as Ta,b as Ia}from"./contentStatus-CkPi9Dh6.js";import{O as Ua,f as Fa,g as is,e as Jt,w as Rs,a as Oa,t as Ba,r as Ns,b as qa,c as $a,d as Va,h as _a,i as mt,j as Ma,D as Ha}from"./yjs-tXBm_srz.js";import"./radix-C5ZmWuuL.js";import"./useMedia-ae3s_ajC.js";import"./core.esm-DdQHdRkd.js";import"./sortable.esm-qVEMoaTg.js";import"./ContentField-pilCbdnA.js";import"./popover-CzaQYEEP.js";import"./command-Bfmj0MEL.js";import"./useContentSearch-B3aTjuCu.js";import"./checkbox-DVJcwUt1.js";const Ja=3e3,za="__HEADROOM_API_URL__".replace(/\/+$/,"");function Ka(r,t,i,a,l,c=Ja,f,h={}){const m=Fn(r,t),u=s.useRef(null),v=s.useRef(i?JSON.stringify(i):""),x=s.useRef(void 0),[S,w]=s.useState(null),[j,L]=s.useState(null),C=s.useRef(!1),R=s.useRef(!1),y=s.useRef(!1),k=s.useRef(!1),N=s.useRef(!1),[$,M]=s.useState(!1),_=s.useRef(!1),E=s.useCallback(O=>{_.current!==O&&(_.current=O,M(O))},[]),D=s.useRef(f);s.useEffect(()=>{D.current=f},[f]);const T=s.useRef(h.onBeforeFirstSave);s.useEffect(()=>{T.current=h.onBeforeFirstSave},[h.onBeforeFirstSave]);const X=s.useRef(h.onStaleBaseConflict);s.useEffect(()=>{X.current=h.onStaleBaseConflict},[h.onStaleBaseConflict]);const K=s.useRef(h.getCurrentParams);s.useEffect(()=>{K.current=h.getCurrentParams},[h.getCurrentParams]);const se=s.useCallback(O=>{N.current||JSON.stringify(O)===v.current||(u.current=O,E(!0),clearTimeout(x.current),x.current=window.setTimeout(async()=>{if(!u.current)return;if(!k.current&&T.current)try{if(!(await T.current()).ok)return;k.current=!0}catch{return}if(!u.current||R.current)return;const I=u.current,H=JSON.stringify(I);y.current=!0,m.mutate(I,{onSuccess:A=>{if(y.current=!1,C.current){C.current=!1;return}u.current===I&&(u.current=null,E(!1)),v.current=H,w(Date.now()),A?.blockId&&L(A.blockId),D.current?.(A)},onError:A=>{if(y.current=!1,A instanceof Ee&&A.code==="SLUG_TAKEN")a?.();else if(A instanceof Ee&&A.code==="LOCK_HELD")k.current=!1,l?.(A);else if(A instanceof Ee&&A.code==="STALE_BASE"){const J=A.body;X.current?.(J?.currentUpdatedAt??0,J?.currentBlockId??"")}else A instanceof Ee&&A.status===400?V.error("Auto-save failed",{description:A.message}):A instanceof Ee&&A.status>=500&&V.error("Auto-save failed",{description:"The server returned an error. Reload to continue editing safely."})}})},c))},[m,a,l,c,E]),re=s.useCallback(async O=>{clearTimeout(x.current),R.current=!0;try{let B=null;if(u.current?B={...u.current}:O?.createVersion&&K.current&&(B=K.current()),!B)return;if(O?.createVersion&&(B.createVersion=!0),!k.current&&T.current)try{if(!(await T.current()).ok)return;k.current=!0}catch{return}const I=JSON.stringify(B);u.current=null,E(!1);const H=await m.mutateAsync(B);v.current=I,w(Date.now()),H?.blockId&&L(H.blockId)}finally{R.current=!1}},[m,E]),Z=s.useCallback(()=>{clearTimeout(x.current),u.current=null,E(!1)},[E]),Q=s.useCallback(()=>{k.current=!1},[]),F=s.useCallback(O=>{v.current=JSON.stringify(O),k.current=!1},[]),le=s.useCallback(()=>{clearTimeout(x.current),u.current=null,E(!1),C.current=!0,L(null),k.current=!1},[E]),o=s.useCallback(()=>{N.current=!0,clearTimeout(x.current)},[]),d=s.useCallback(()=>{N.current=!1},[]);return s.useEffect(()=>()=>{if(clearTimeout(x.current),u.current){const{sessionId:O,...B}=u.current,I=JSON.stringify(B),H=qs(),A=`${za}/v1/admin/sites/${r}/content/${t}/draft`;fetch(A,{method:"PUT",body:I,headers:{"Content-Type":"application/json",...H?{Authorization:`Bearer ${H}`}:{}},keepalive:!0}).catch(()=>{}),u.current=null}},[r,t]),{schedule:se,flush:re,cancel:Z,resetBaseline:F,discard:le,pause:o,resume:d,markLockReleased:Q,isDirty:$,isSaving:m.isPending,lastSavedAt:S,lastSavedBlockId:j,getIsSavingSync:()=>y.current,getHasPending:()=>u.current!==null}}const pt="headroom:idleHintShown",Ya="__HEADROOM_API_URL__".replace(/\/+$/,""),Qa=5e3,Ga=3600*1e3,Wa=6e4,Ds=2e3;function Xa(r){const t=`headroom:editSession:${r}`;let i=sessionStorage.getItem(t);return i||(i=zn(),sessionStorage.setItem(t,i)),i}const As=new Map;function Za(r,t,i={}){const a=ls(),{user:l}=$s(),c=Bs(),[f,h]=s.useState("viewing"),[m,u]=s.useState(null),[v,x]=s.useState(null),[S,w]=s.useState([]),[j,L]=s.useState(!1),[C,R]=s.useState(!1),y=t?Xa(t):"",k=s.useRef(0),N=s.useRef(!1),$=s.useRef(!1),M=s.useRef(!1),_=s.useRef(null),E=s.useRef(null),D=s.useRef(0),T=s.useRef(null),X=s.useRef(i.getIsDirty),K=s.useRef(i.getIsSaving),se=s.useRef(i.getIsSavingSync),re=s.useRef(i.onIdleRelease);s.useEffect(()=>{X.current=i.getIsDirty,K.current=i.getIsSaving,se.current=i.getIsSavingSync,re.current=i.onIdleRelease});const Z=s.useCallback(async(b=!1)=>{if(!r||!t||!y)return null;const q=`${r}:${t}:${b?"force":"edit"}`,U=As.get(q);if(U)return U;const ee=a.apiFetch(`/v1/admin/sites/${r}/content/${t}/edit-lock`,{method:"POST",body:JSON.stringify({sessionId:y,force:b,email:l?.email,name:l?.name})}).finally(()=>{As.delete(q)});return As.set(q,ee),ee},[a,r,t,y,l?.email,l?.name]),Q=s.useCallback(async()=>{if(!(!r||!t||!y)&&!$.current&&!M.current){$.current=!0,M.current=!0;try{await a.apiFetch(`/v1/admin/sites/${r}/content/${t}/edit-lock`,{method:"DELETE",body:JSON.stringify({sessionId:y})})}catch{}finally{M.current=!1}}},[a,r,t,y]),F=s.useCallback(()=>{_.current&&(clearTimeout(_.current),_.current=null),E.current&&(clearTimeout(E.current),E.current=null)},[]),le=s.useRef(()=>{}),o=s.useCallback(()=>{const b=X.current?X.current():!1,q=K.current?K.current():!1,U=se.current?se.current():!1;if(b||q||U){E.current=setTimeout(()=>le.current(),1e3);return}if(N.current){N.current=!1,Q(),re.current?.(),h("idle-released"),u(null),x(null),w([]),R(!1);try{typeof window<"u"&&window.sessionStorage&&(window.sessionStorage.getItem(pt)||(V("Released editing — others can edit now."),window.sessionStorage.setItem(pt,"1")))}catch{}}},[Q]);s.useEffect(()=>{le.current=o},[o]);const d=s.useCallback(()=>{F(),_.current=setTimeout(o,Wa)},[F,o]),O=s.useCallback(()=>{if(C){F();return}N.current&&d()},[C,F,d]),B=s.useRef(C);s.useEffect(()=>{const b=B.current;B.current=C,b!==C&&(C?F():N.current&&d())},[C,F,d]);const I=s.useCallback(async()=>{if(!r||!t||!y||!l)return{ok:!1,holder:null};if(Date.now()<D.current)return{ok:!1,holder:T.current};try{const b=await Z(!1);if(!b||!b.acquired){const q=b?.lockHolder??null;return D.current=Date.now()+Ds,T.current=q,h("blocked-edit"),u(q),R(b?.collaborationEnabled??!1),k.current||(k.current=Date.now()),{ok:!1,holder:q}}return N.current=!0,$.current=!1,D.current=0,T.current=null,h("editing"),u(b.lockHolder??null),x(b.takeoverReason),R(b.collaborationEnabled),d(),{ok:!0}}catch(b){const q=b;if(q.status===409){const U=q.body?.lockHolder??null,ee=q.body?.collaborationEnabled??!1;if(U&&U.sub===l.sub&&U.sessionId!==y)try{const G=await Z(!1);if(G?.acquired)return N.current=!0,$.current=!1,D.current=0,T.current=null,h("editing"),u(G.lockHolder??null),x(G.takeoverReason),R(G.collaborationEnabled),d(),{ok:!0}}catch{}return D.current=Date.now()+Ds,T.current=U,h("blocked-edit"),u(U),R(ee),k.current||(k.current=Date.now()),{ok:!1,holder:U}}return h("error"),{ok:!1,holder:null}}},[r,t,y,l,Z,d]);s.useEffect(()=>{if(!r||!t||!y)return;const b=()=>{if(!N.current||$.current||M.current)return;$.current=!0;const q=qs(),U=`${Ya}/v1/admin/sites/${r}/content/${t}/edit-lock`;fetch(U,{method:"DELETE",body:JSON.stringify({sessionId:y}),headers:{"Content-Type":"application/json",...q?{Authorization:`Bearer ${q}`}:{}},keepalive:!0}).catch(()=>{})};return window.addEventListener("beforeunload",b),()=>window.removeEventListener("beforeunload",b)},[r,t,y]);const H=s.useRef(Q),A=s.useRef(F);s.useEffect(()=>{H.current=Q,A.current=F},[Q,F]),s.useEffect(()=>()=>{A.current(),N.current&&(N.current=!1,H.current())},[r,t,y]);const J=f==="blocked-edit"&&!j,ye=s.useCallback(b=>{if(k.current&&Date.now()-k.current>Ga){L(!0),h("poll-ceiling");return}const q=b.lock;if(!q)D.current=0,T.current=null,u(null),R(!1),w([]),h("idle-released"),k.current=0;else{u(q.heldBy),R(q.collaborationEnabled);const U=(q.accessRequests??[]).filter(ee=>ee.sub!==l?.sub);w(U)}},[l?.sub]);Pn({queryKey:["sites",r,"edit-lock",t],queryFn:async()=>{try{const b=await a.apiFetch(`/v1/admin/sites/${r}/content/${t}/edit-lock`);return ye(b),b}catch{return{lock:m?{heldBy:m,expiresAt:0,collaborationEnabled:C,accessRequests:[]}:null}}},enabled:J,refetchInterval:J?Qa:!1,refetchIntervalInBackground:!1,retry:!1});const ne=En({mutationFn:()=>a.apiFetch(`/v1/admin/sites/${r}/content/${t}/edit-lock/access-requests`,{method:"POST",body:JSON.stringify({sessionId:y,email:l?.email,name:l?.name})})}),g=s.useCallback(async()=>{const b=await Z(!0);return b?.acquired&&(N.current=!0,$.current=!1,D.current=0,T.current=null,h("editing"),u(b.lockHolder??null),x(b.takeoverReason),R(b.collaborationEnabled),d(),c.invalidateQueries({queryKey:["sites",r,"edit-lock",t]})),b},[Z,c,r,t,d]),Be=s.useCallback(async()=>I(),[I]),Y=s.useCallback(b=>{N.current=!1,F(),D.current=Date.now()+Ds,T.current=b.lockHolder??null,h("blocked-edit"),u(b.lockHolder??null),x(b.takeoverReason??null),k.current||(k.current=Date.now())},[F]),os=s.useCallback(()=>{F(),N.current&&(N.current=!1,Q()),D.current=0,T.current=null,h("viewing"),u(null),x(null),R(!1),w([]),k.current=0},[F,Q]),ds=s.useCallback(()=>{F(),h("stale-reload-pending")},[F]),de=s.useCallback(()=>{h("editing"),N.current&&d()},[d]),me=s.useCallback(()=>{F(),D.current=0,T.current=null,h("read-only-explicit")},[F]),je=s.useCallback(()=>{h("viewing")},[]);return{status:f,lockHolder:m,takeoverReason:v,accessRequests:S,sessionId:y,pollCeiling:j,collaborationEnabled:C,acquireLock:Z,releaseLock:Q,tryAcquireForEdit:I,bumpIdleTimer:O,requestCollaboration:ne,forceTakeover:g,takeEditing:Be,endEditing:os,setStaleReloadPending:ds,resumeEditingAfterStale:de,setReadOnlyExplicit:me,exitReadOnly:je,onAutosaveConflict:Y,setAccessRequests:w,setCollaborationEnabled:R}}function ei({host:r,contentId:t,isDirty:i,serverBlockId:a,serverUpdatedAt:l,onSilentReload:c,onStaleWithDirty:f,onTabHidden:h,onTabVisibleResume:m,minHiddenMs:u=3e4}){const v=Bs(),x=s.useRef(null),S=s.useRef(i),w=s.useRef(a),j=s.useRef(l),L=s.useRef(c),C=s.useRef(f),R=s.useRef(h),y=s.useRef(m),k=s.useRef(u);s.useEffect(()=>{S.current=i,w.current=a,j.current=l,L.current=c,C.current=f,R.current=h,y.current=m,k.current=u},[i,a,l,c,f,h,m,u]),s.useEffect(()=>{if(typeof document>"u"||!r||!t)return;const N=["sites",r,"content-detail",t];let $=!1;const M=async()=>{if(typeof document>"u")return;if(document.visibilityState==="hidden"){x.current=Date.now(),R.current&&R.current();return}if(document.visibilityState!=="visible")return;const _=x.current;if(x.current=null,_==null)return;if(Date.now()-_<k.current){y.current&&y.current();return}if(await v.refetchQueries({queryKey:[...N],exact:!0}),$)return;const D=v.getQueryData([...N]);if(!D){y.current&&y.current();return}const T=D.draft?.updatedAt,X=D.draft?.blockId,K=j.current??0,se=w.current??null;if(!(typeof T=="number"&&T>K||X!=null&&X!==se)){y.current&&y.current();return}$||(S.current?C.current(D):(y.current&&y.current(),L.current(D)))};return document.addEventListener("visibilitychange",M),()=>{$=!0,document.removeEventListener("visibilitychange",M)}},[r,t,v])}function Vs(){return"__HEADROOM_COLLAB_ENABLED__"!=="false"}function gt({variant:r="read-only-explicit",lockHolder:t,onRequestCollaboration:i,onForceTakeover:a,onDiscardPending:l,onViewReadOnly:c,onResumeEditing:f,isRequesting:h,requestSent:m}){if(r==="poll-ceiling")return e.jsx("div",{className:"bg-amber-50 border border-amber-200 rounded-lg p-4 mb-4","data-testid":"edit-lock-banner","data-variant":"poll-ceiling",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(Ss,{className:"h-5 w-5 text-amber-600 mt-0.5 shrink-0"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("p",{className:"font-medium text-amber-900",children:"Lock check paused"}),e.jsx("p",{className:"text-sm text-amber-700 mt-1",children:"Refresh the page to retry."})]})]})});const u=Vs(),v=t?.name||t?.email||"another user";return r==="blocked-edit"?e.jsx("div",{className:"bg-amber-50 border border-amber-200 rounded-lg p-4 mb-4","data-testid":"edit-lock-banner","data-variant":"blocked-edit",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(Ss,{className:"h-5 w-5 text-amber-600 mt-0.5 shrink-0"}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("p",{className:"font-medium text-amber-900",children:[v," is editing this content"]}),e.jsxs("p",{className:"text-sm text-amber-700 mt-1",children:["Your changes are pending and will be saved when ",v," finishes."]}),e.jsxs("div",{className:"flex flex-wrap gap-2 mt-3 items-center",children:[u&&i&&e.jsx(P,{size:"sm",variant:"outline",onClick:i,disabled:h||m,"data-testid":"request-collaboration-btn",children:m?"Request sent":"Request collaboration"}),l&&e.jsx(P,{size:"sm",variant:"ghost",onClick:l,"data-testid":"discard-pending-btn",children:"Discard pending changes"}),c&&e.jsx(P,{size:"sm",variant:"ghost",onClick:c,"data-testid":"view-read-only-btn",children:"View read-only"}),a&&e.jsx(P,{size:"sm",variant:"destructive",onClick:a,"data-testid":"force-takeover-btn",children:"Take over"})]})]})]})}):e.jsx("div",{className:"bg-amber-50 border border-amber-200 rounded-lg p-4 mb-4","data-testid":"edit-lock-banner","data-variant":"read-only-explicit",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(Ss,{className:"h-5 w-5 text-amber-600 mt-0.5 shrink-0"}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("p",{className:"font-medium text-amber-900",children:["Editing: ",v]}),e.jsx("p",{className:"text-sm text-amber-700 mt-1",children:u?"This content is being edited. You can view it read-only or ask to collaborate.":"This content is being edited. You can view it read-only until the editor is finished."}),e.jsxs("div",{className:"flex gap-2 mt-3",children:[u&&i&&e.jsx(P,{size:"sm",variant:"outline",onClick:i,disabled:h||m,"data-testid":"request-collaboration-btn",children:m?"Request sent":"Request collaboration"}),f&&e.jsx(P,{size:"sm",variant:"ghost",onClick:f,"data-testid":"resume-editing-btn",children:"Resume editing"})]})]})]})})}function si({open:r,trigger:t,updatedBy:i,updatedAt:a,onReload:l,onCancel:c}){const f=a>0?ts(a):"just now";return e.jsx(Tt,{open:r,children:e.jsxs(It,{"data-testid":"stale-reload-modal","data-trigger":t,onEscapeKeyDown:h=>h.preventDefault(),children:[e.jsxs(Ut,{children:[e.jsx(Ft,{children:"This content was updated"}),e.jsx(Ot,{children:t==="save-conflict"?e.jsxs(e.Fragment,{children:["Your save couldn't go through —"," ",e.jsx("strong",{"data-testid":"stale-reload-updated-by",children:i})," ",e.jsxs("span",{className:"text-muted-foreground","data-testid":"stale-reload-updated-at",children:["(",f,")"]})," ","updated this content since you started editing. Reload to see the latest version (your unsaved changes will be lost), or cancel to keep editing — your next save will hit the same conflict."]}):e.jsxs(e.Fragment,{children:["This content was updated by"," ",e.jsx("strong",{"data-testid":"stale-reload-updated-by",children:i})," ",e.jsxs("span",{className:"text-muted-foreground","data-testid":"stale-reload-updated-at",children:["(",f,")"]})," ","while this tab was inactive. Reload to see the latest version (your unsaved changes will be lost), or cancel to keep editing your version — the next save will be rejected if it conflicts."]})})]}),e.jsxs(Bt,{children:[e.jsx(qt,{onClick:c,"data-testid":"stale-reload-cancel-btn",children:"Cancel"}),e.jsx($t,{onClick:l,"data-testid":"stale-reload-reload-btn",children:"Reload"})]})]})})}function ti({lines:r}){return e.jsx("div",{className:"font-mono text-sm leading-relaxed",children:r.map((t,i)=>e.jsx("div",{style:{paddingLeft:`${t.indent*1.5}rem`},className:cs("min-h-[1.5em]",t.type==="label"&&"text-muted-foreground font-semibold mt-1",t.type==="heading"&&"font-bold",t.type==="empty"&&"h-2"),children:t.text},i))})}function Os(r){switch(r.kind){case"draft":return"Draft";case"published":return"Published";case"history":return Se(r.createdAt)}}function rs(r){switch(r.kind){case"draft":return"draft";case"published":return"published";case"history":return`history:${r.blockId}`}}function bt({value:r,onChange:t,isPublished:i,versions:a,exclude:l,size:c}){const f=l?rs(l):null;function h(m){if(m==="draft")t({kind:"draft"});else if(m==="published")t({kind:"published"});else if(m.startsWith("history:")){const u=m.slice(8),v=a.find(x=>x.blockId===u);v&&t({kind:"history",blockId:v.blockId,createdAt:v.createdAt,title:v.title})}}return e.jsxs(pa,{value:rs(r),onValueChange:h,children:[e.jsx(ga,{size:c,children:e.jsx(ba,{children:Os(r)})}),e.jsxs(xa,{position:"popper",children:[f!=="draft"&&e.jsx(ws,{value:"draft",children:"Draft"}),i&&f!=="published"&&e.jsx(ws,{value:"published",children:"Published"}),a.length>0&&e.jsxs(e.Fragment,{children:[e.jsx(va,{}),e.jsxs(ya,{children:[e.jsx(ja,{children:"Version History"}),a.map(m=>{const u=`history:${m.blockId}`;return u===f?null:e.jsx(ws,{value:u,children:Se(m.createdAt)},u)})]})]})]})]})}function xt({ref:r,host:t,contentId:i,collectionFields:a,isSingleton:l,draftBody:c,draftMetadata:f,collectionRelationships:h,draftRelationships:m}){const u=r?.kind==="published",v=r?.kind==="history",x=v?r.blockId:null,{data:S,isLoading:w}=St(t,i,u),{data:j,isLoading:L}=On(t,i,v?x:null),C=s.useMemo(()=>(h??[]).map(k=>({name:k.name,label:k.label})),[h]);function R(k){if(C.length!==0)return{defs:C,values:k??{}}}const y=s.useMemo(()=>{if(!r)return[];if(r.kind==="draft")return c?Oe(a,c,l?void 0:f,R(m)):[];if(r.kind==="published"){if(!S)return[];const $=l?void 0:{title:S.title,slug:S.slug,snippet:S.snippet,tags:S.tags},M=S.relationships;return Oe(a,S.fields??{},$,R(M))}if(!j)return[];const k=l?void 0:{title:j.title,slug:j.slug,snippet:j.snippet,tags:j.tags},N=j.relationships;return Oe(a,j.body??{},k,R(N))},[r,c,f,m,S,j,a,l,C]);return r?r.kind==="draft"?{lines:y,isLoading:!1,hasData:!!c}:r.kind==="published"?{lines:y,isLoading:w,hasData:!!S}:{lines:y,isLoading:L,hasData:!!j}:{lines:[],isLoading:!1,hasData:!1}}function ni({open:r,onOpenChange:t,host:i,contentId:a,collectionFields:l,isSingleton:c,isPublished:f,draftBody:h,draftMetadata:m,initialVersion:u,collectionRelationships:v,draftRelationships:x}){const[S,w]=s.useState(u??{kind:"published"}),[j,L]=s.useState({kind:"draft"}),[C,R]=s.useState(r),[y,k]=s.useState(u);if((r!==C||u!==y)&&(R(r),k(u),r)){const T=u??{kind:"published"};w(T),L(T.kind==="draft"?{kind:"published"}:{kind:"draft"})}rs(S)===rs(j)&&(S.kind!=="draft"?L({kind:"draft"}):f&&L({kind:"published"}));const{data:N}=Ct(i,a),$=N?.items??[],M={host:i,contentId:a,collectionFields:l,isSingleton:c,draftBody:h,draftMetadata:m,collectionRelationships:v,draftRelationships:x},_=xt({ref:r?S:null,...M}),E=xt({ref:r?j:null,...M}),D=_.isLoading;return e.jsx(Kn,{open:r,onOpenChange:t,children:e.jsxs(Yn,{className:"w-[calc(100vw-2rem)] sm:max-w-2xl overflow-y-auto pt-[env(safe-area-inset-top,0px)] pr-[env(safe-area-inset-right,0px)]",children:[e.jsx(Qn,{children:e.jsxs(Gn,{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-muted-foreground text-sm font-normal",children:"Viewing"}),e.jsx(bt,{value:S,onChange:w,isPublished:f,versions:$,size:"sm"})]})}),D&&e.jsxs("div",{className:"space-y-4 p-4",children:[e.jsx(fe,{className:"h-6 w-48"}),e.jsx(fe,{className:"h-4 w-full"}),e.jsx(fe,{className:"h-4 w-full"}),e.jsx(fe,{className:"h-4 w-2/3"})]}),!D&&!_.hasData&&e.jsx("p",{className:"p-4 text-sm text-muted-foreground",children:"No data available for this version."}),!D&&_.hasData&&e.jsx("div",{className:"p-4",children:e.jsxs(Rt,{defaultValue:"changes",children:[e.jsxs(Nt,{variant:"line",className:"mb-4",children:[e.jsx(ns,{value:"content",children:"Content"}),e.jsx(ns,{value:"changes",children:"Changes"})]}),e.jsx(as,{value:"content",children:e.jsx(ti,{lines:_.lines})}),e.jsxs(as,{value:"changes",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[e.jsx("span",{className:"text-sm text-muted-foreground",children:"Compare with"}),e.jsx(bt,{value:j,onChange:L,isPublished:f,versions:$,exclude:S,size:"sm"})]}),E.isLoading?e.jsxs("div",{className:"space-y-4",children:[e.jsx(fe,{className:"h-4 w-full"}),e.jsx(fe,{className:"h-4 w-full"}),e.jsx(fe,{className:"h-4 w-2/3"})]}):E.hasData?e.jsx(fa,{left:E.lines,right:_.lines,leftLabel:Os(j),rightLabel:Os(S)}):e.jsx("p",{className:"text-sm text-muted-foreground italic",children:"No data available for comparison."})]})]})})]})})}const Ps=3e4;class ai extends Ua{constructor(t){super(),this.doc=t,this.clientID=t.clientID,this.states=new Map,this.meta=new Map,this._checkInterval=setInterval(()=>{const i=is();this.getLocalState()!==null&&Ps/2<=i-this.meta.get(this.clientID).lastUpdated&&this.setLocalState(this.getLocalState());const a=[];this.meta.forEach((l,c)=>{c!==this.clientID&&Ps<=i-l.lastUpdated&&this.states.has(c)&&a.push(c)}),a.length>0&&ii(this,a,"timeout")},Fa(Ps/10)),t.on("destroy",()=>{this.destroy()}),this.setLocalState({})}destroy(){this.emit("destroy",[this]),this.setLocalState(null),super.destroy(),clearInterval(this._checkInterval)}getLocalState(){return this.states.get(this.clientID)||null}setLocalState(t){const i=this.clientID,a=this.meta.get(i),l=a===void 0?0:a.clock+1,c=this.states.get(i);t===null?this.states.delete(i):this.states.set(i,t),this.meta.set(i,{clock:l,lastUpdated:is()});const f=[],h=[],m=[],u=[];t===null?u.push(i):c==null?t!=null&&f.push(i):(h.push(i),Jt(c,t)||m.push(i)),(f.length>0||m.length>0||u.length>0)&&this.emit("change",[{added:f,updated:m,removed:u},"local"]),this.emit("update",[{added:f,updated:h,removed:u},"local"])}setLocalStateField(t,i){const a=this.getLocalState();a!==null&&this.setLocalState({...a,[t]:i})}getStates(){return this.states}}const ii=(r,t,i)=>{const a=[];for(let l=0;l<t.length;l++){const c=t[l];if(r.states.has(c)){if(r.states.delete(c),c===r.clientID){const f=r.meta.get(c);r.meta.set(c,{clock:f.clock+1,lastUpdated:is()})}a.push(c)}}a.length>0&&(r.emit("change",[{added:[],updated:[],removed:a},i]),r.emit("update",[{added:[],updated:[],removed:a},i]))},vt=(r,t,i=r.states)=>{const a=t.length,l=$a();Rs(l,a);for(let c=0;c<a;c++){const f=t[c],h=i.get(f)||null,m=r.meta.get(f).clock;Rs(l,f),Rs(l,m),Oa(l,JSON.stringify(h))}return Ba(l)},ri=(r,t,i)=>{const a=Va(t),l=is(),c=[],f=[],h=[],m=[],u=Ns(a);for(let v=0;v<u;v++){const x=Ns(a);let S=Ns(a);const w=JSON.parse(qa(a)),j=r.meta.get(x),L=r.states.get(x),C=j===void 0?0:j.clock;(C<S||C===S&&w===null&&r.states.has(x))&&(w===null?x===r.clientID&&r.getLocalState()!=null?S++:r.states.delete(x):r.states.set(x,w),r.meta.set(x,{clock:S,lastUpdated:l}),j===void 0&&w!==null?c.push(x):j!==void 0&&w===null?m.push(x):w!==null&&(Jt(w,L)||h.push(x),f.push(x)))}(c.length>0||h.length>0||m.length>0)&&r.emit("change",[{added:c,updated:h,removed:m},i]),(c.length>0||f.length>0||m.length>0)&&r.emit("update",[{added:c,updated:f,removed:m},i])},yt=[1e3,2e3,4e3,8e3,16e3];class _s{awareness;ws=null;doc;room;wsUrl;ticket;getTicket;reconnectAttempt=0;reconnectTimer=null;connected=!1;destroyed=!1;pendingUpdates=[];pendingFieldUpdates=[];static MAX_PENDING_FIELD_UPDATES=100;statusListeners=new Set;constructor(t){this.doc=t.doc,this.room=t.room,this.wsUrl=t.wsUrl,this.ticket=t.ticket,this.getTicket=t.getTicket,this.awareness=new ai(this.doc),this.awareness.setLocalStateField("user",t.user),this.doc.on("update",this.handleDocUpdate),this.awareness.on("update",this.handleAwarenessUpdate),this.connect()}onStatus(t){return this.statusListeners.add(t),()=>{this.statusListeners.delete(t)}}connect(){if(this.destroyed)return;this.statusListeners.forEach(i=>i("connecting"));const t=`${this.wsUrl}?ticket=${encodeURIComponent(this.ticket)}&room=${encodeURIComponent(this.room)}`;this.ws=new WebSocket(t),this.ws.onopen=()=>{this.connected=!0,this.reconnectAttempt=0,this.statusListeners.forEach(l=>l("connected"));const i=_a(this.doc);this.ws.send(JSON.stringify({action:"yjs",type:"sync-step-1",data:Ie(i)}));const a=vt(this.awareness,[this.doc.clientID]);this.ws.send(JSON.stringify({action:"awareness",data:Ie(a)}))},this.ws.onmessage=i=>{const a=JSON.parse(i.data);switch(a.action){case"yjs":this.handleYjsMessage(a);break;case"field":this.fieldListeners.forEach(l=>l(a));break;case"awareness":this.handleAwarenessMessage(a);break;case"presence":this.presenceListeners.forEach(l=>l(a));break;case"leader-change":this.leaderChangeListeners.forEach(l=>l(a));break;case"collaboration-disabled":this.collabDisabledListeners.forEach(l=>l());break;case"publish-requested":this.publishRequestedListeners.forEach(l=>l(a));break;case"save-version-requested":this.saveVersionRequestedListeners.forEach(l=>l(a));break;case"publish-in-progress":this.publishInProgressListeners.forEach(l=>l());break;case"published":this.publishedListeners.forEach(l=>l(a));break}},this.ws.onclose=()=>{this.connected=!1,this.statusListeners.forEach(i=>i("disconnected")),this.scheduleReconnect()},this.ws.onerror=()=>{this.ws?.close()}}handleDocUpdate=(t,i)=>{i!=="remote"&&(this.connected?this.sendYjsUpdate(t):this.pendingUpdates.push(t))};sendYjsUpdate(t){this.ws?.send(JSON.stringify({action:"yjs",type:"update",data:Ie(t)}))}flushPendingUpdates(){for(const t of this.pendingUpdates)this.sendYjsUpdate(t);this.pendingUpdates=[]}handleYjsMessage(t){const i=jt(t.data);switch(t.type){case"sync-step-1":{const a=Ma(this.doc,i);this.ws.send(JSON.stringify({action:"yjs",type:"sync-step-2",data:Ie(a)}));break}case"sync-step-2":mt(this.doc,i,"remote"),this.flushPendingUpdates(),this.flushPendingFieldUpdates();break;case"update":mt(this.doc,i,"remote");break}}fieldListeners=new Set;onFieldUpdate(t){return this.fieldListeners.add(t),()=>{this.fieldListeners.delete(t)}}sendFieldUpdate(t,i){if(!this.connected){const a=this.pendingFieldUpdates.findIndex(l=>l.field===t);a>=0?this.pendingFieldUpdates[a]={field:t,value:i}:(this.pendingFieldUpdates.length>=_s.MAX_PENDING_FIELD_UPDATES&&this.pendingFieldUpdates.shift(),this.pendingFieldUpdates.push({field:t,value:i}));return}this.ws?.send(JSON.stringify({action:"field",field:t,value:i}))}flushPendingFieldUpdates(){for(const{field:t,value:i}of this.pendingFieldUpdates)this.ws?.send(JSON.stringify({action:"field",field:t,value:i}));this.pendingFieldUpdates=[]}presenceListeners=new Set;onPresence(t){return this.presenceListeners.add(t),()=>{this.presenceListeners.delete(t)}}leaderChangeListeners=new Set;onLeaderChange(t){return this.leaderChangeListeners.add(t),()=>{this.leaderChangeListeners.delete(t)}}collabDisabledListeners=new Set;onCollabDisabled(t){return this.collabDisabledListeners.add(t),()=>{this.collabDisabledListeners.delete(t)}}sendDisableCollab(){this.connected&&this.ws?.send(JSON.stringify({action:"disable-collab"}))}publishRequestedListeners=new Set;onPublishRequested(t){return this.publishRequestedListeners.add(t),()=>{this.publishRequestedListeners.delete(t)}}saveVersionRequestedListeners=new Set;onSaveVersionRequested(t){return this.saveVersionRequestedListeners.add(t),()=>{this.saveVersionRequestedListeners.delete(t)}}publishInProgressListeners=new Set;onPublishInProgress(t){return this.publishInProgressListeners.add(t),()=>{this.publishInProgressListeners.delete(t)}}publishedListeners=new Set;onPublished(t){return this.publishedListeners.add(t),()=>{this.publishedListeners.delete(t)}}sendRequestPublish(){this.connected&&this.ws?.send(JSON.stringify({action:"request-publish"}))}sendRequestSaveVersion(){this.connected&&this.ws?.send(JSON.stringify({action:"request-save-version"}))}sendPublishInProgress(){this.connected&&this.ws?.send(JSON.stringify({action:"publish-in-progress"}))}sendPublished(t){this.connected&&this.ws?.send(JSON.stringify({action:"published",...t?.contentId?{contentId:t.contentId}:{},...t?.version!==void 0?{version:t.version}:{}}))}handleAwarenessUpdate=({added:t,updated:i,removed:a})=>{if(!this.connected)return;const l=vt(this.awareness,[...t,...i,...a]);this.ws?.send(JSON.stringify({action:"awareness",data:Ie(l)}))};handleAwarenessMessage(t){const i=jt(t.data);ri(this.awareness,i,"remote")}scheduleReconnect(){if(this.destroyed)return;const t=yt[Math.min(this.reconnectAttempt,yt.length-1)];this.reconnectAttempt++,this.reconnectTimer=window.setTimeout(async()=>{try{this.ticket=await this.getTicket()}catch{this.statusListeners.forEach(i=>i("disconnected"));return}this.connect()},t)}destroy(){this.destroyed=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.doc.off("update",this.handleDocUpdate),this.awareness.off("update",this.handleAwarenessUpdate),this.awareness.destroy(),this.ws?.close()}}function Ie(r){let t="";for(let a=0;a<r.length;a+=8192)t+=String.fromCharCode(...r.subarray(a,a+8192));return btoa(t)}function jt(r){const t=atob(r),i=new Uint8Array(t.length);for(let a=0;a<t.length;a++)i[a]=t.charCodeAt(a);return i}const ss=["#3b82f6","#ef4444","#10b981","#f59e0b","#8b5cf6","#ec4899","#14b8a6","#f97316"];function li(r,t,i,a){const{user:l}=$s(),[c,f]=s.useState(null),[h,m]=s.useState("disconnected"),[u,v]=s.useState([]),[x,S]=s.useState({}),w=s.useRef(null),j=s.useRef(a?.onCollabDisabled),L=s.useRef(a?.onPublishRequested),C=s.useRef(a?.onSaveVersionRequested),R=s.useRef(a?.onPublishInProgress),y=s.useRef(a?.onPublished);s.useEffect(()=>{j.current=a?.onCollabDisabled,L.current=a?.onPublishRequested,C.current=a?.onSaveVersionRequested,R.current=a?.onPublishInProgress,y.current=a?.onPublished},[a?.onCollabDisabled,a?.onPublishRequested,a?.onSaveVersionRequested,a?.onPublishInProgress,a?.onPublished]);const k="__HEADROOM_COLLAB_WS_URL__",N=Vs(),$=N&&!!c&&h==="connected";s.useEffect(()=>{if(!N||!k||!l||!i)return;const o=new Ha;w.current=o;const d=`${r}/${t}`,O=async()=>{const H=qs();if(!H)throw new Error("No access token");const A="__HEADROOM_API_URL__".replace(/\/+$/,""),J=await fetch(`${A}/v1/admin/sites/${r}/content/${t}/collab/ticket`,{method:"POST",headers:{Authorization:`Bearer ${H}`,"Content-Type":"application/json"},body:JSON.stringify({room:d})});if(!J.ok)throw new Error(`Ticket request failed: ${J.status}`);return(await J.json()).ticket};let B=!1,I=null;return O().then(H=>{if(B)return;const A=kt(l.sub)%ss.length;I=new _s({wsUrl:k,room:d,ticket:H,getTicket:O,doc:o,user:{sub:l.sub,name:l.name||l.email,color:ss[A]}}),I.onStatus(m),I.onPresence(J=>{v(J.connections.filter(ne=>ne.connectionId!==J.youAre).map(ne=>({sub:ne.adminSub,name:ne.adminName,color:ne.color})));const ye=J.connections.find(ne=>ne.connectionId===J.youAre);le(ye?.isLeader??!1)}),I.onCollabDisabled(()=>{j.current?.()}),I.onPublishRequested(()=>L.current?.()),I.onSaveVersionRequested(()=>C.current?.()),I.onPublishInProgress(()=>R.current?.()),I.onPublished(J=>y.current?.({contentId:J.contentId,version:J.version})),f(I)}).catch(()=>{B||m("disconnected")}),()=>{B=!0,I?.destroy(),o.destroy(),f(null),m("disconnected")}},[r,t,l?.sub,i,k]);const M=s.useCallback(o=>{if(!c||!l||!w.current)return;const d=w.current.getXmlFragment(`document-store-${o}`),O=kt(l.sub)%ss.length;return{provider:c,fragment:d,user:{name:l.email,color:ss[O]}}},[c,l]);s.useEffect(()=>{if(!c){S({});return}const o=()=>{const d={};c.awareness.getStates().forEach(B=>{const I=B?.user?.sub;if(!I)return;const H=B.activeField??null;d[I]=H}),S(d)};return o(),c.awareness.on("change",o),()=>{c.awareness.off("change",o)}},[c]);const _=s.useMemo(()=>u.map(o=>({...o,activeField:x[o.sub]??null})),[u,x]),E=s.useCallback(o=>{c&&c.awareness.setLocalStateField("activeField",o)},[c]),D=s.useRef(new Set),T=s.useCallback(o=>(D.current.add(o),()=>{D.current.delete(o)}),[]);s.useEffect(()=>{if(c)return c.onFieldUpdate(o=>{D.current.forEach(d=>d(o.field,o.value))})},[c]);const X=s.useCallback((o,d)=>{c?.sendFieldUpdate(o,d)},[c]),K=s.useCallback(()=>{c?.sendDisableCollab()},[c]),se=s.useCallback(()=>{c?.sendRequestPublish()},[c]),re=s.useCallback(()=>{c?.sendRequestSaveVersion()},[c]),Z=s.useCallback(()=>{c?.sendPublishInProgress()},[c]),Q=s.useCallback(o=>{c?.sendPublished(o)},[c]),[F,le]=s.useState(!1);return s.useEffect(()=>{if(c)return c.onLeaderChange(o=>{le(o.leaderSub===l?.sub)})},[c,l]),{active:$,status:h,editors:_,isLeader:F,getBlockNoteCollab:M,updateField:X,onRemoteFieldChange:T,setActiveField:E,sendDisableCollab:K,sendRequestPublish:se,sendRequestSaveVersion:re,sendPublishInProgress:Z,sendPublished:Q}}function kt(r){let t=0;for(let i=0;i<r.length;i++)t=(t<<5)-t+r.charCodeAt(i)|0;return Math.abs(t)}function ci({status:r,editors:t}){return t.length===0&&r==="connected"?null:e.jsxs("div",{className:"flex items-center gap-2 px-3 py-1.5 bg-muted/50 rounded-md text-sm","data-testid":"collaboration-bar",children:[e.jsxs("div",{className:"flex items-center gap-1.5","aria-label":r,children:[e.jsx("span",{"data-testid":"collaboration-bar-status-dot","data-status":r,className:cs("h-2 w-2 rounded-full",r==="connected"&&"bg-green-500",r==="connecting"&&"bg-yellow-500 animate-pulse",r==="disconnected"&&"bg-red-500")}),e.jsx("span",{className:"text-muted-foreground text-xs",children:r==="connected"?"Live":r==="connecting"?"Connecting...":"Offline"})]}),t.length>0&&e.jsxs(e.Fragment,{children:[e.jsx(Dt,{orientation:"vertical",className:"h-4"}),e.jsx("div",{className:"flex -space-x-1.5",children:t.map(i=>e.jsxs(At,{children:[e.jsx(Pt,{asChild:!0,children:e.jsx(Na,{className:"h-6 w-6 border-2",style:{borderColor:i.color},"aria-label":i.name,children:e.jsx(Da,{className:"text-[10px]",style:{backgroundColor:i.color+"20"},children:Aa(i.name)})})}),e.jsx(Et,{children:i.name})]},i.sub))}),e.jsxs("span",{className:"text-muted-foreground text-xs",children:[t.length," other ",t.length===1?"editor":"editors"]})]})]})}function oi({host:r,contentId:t,collaborationEnabled:i,hasConnectedPeers:a,isLockHolder:l,sessionId:c,onChange:f,onBeforeDisable:h}){const[m,u]=s.useState(!1),v=ls();if(!Vs()||!l)return null;const x=async()=>{const C=!i;u(!0);try{if(!C)try{h?.()}catch{}await v.apiFetch(`/v1/admin/sites/${r}/content/${t}/edit-lock/collaboration`,{method:"POST",body:JSON.stringify({collaborationEnabled:C,sessionId:c})}),f(C)}catch{V.error("Failed to update collaboration setting")}finally{u(!1)}},S=i&&a,w=m||S,j=S?"Cannot stop sharing while other editors are connected":null,L=e.jsxs(P,{variant:i?"default":"outline",size:"sm",disabled:w,onClick:x,"aria-pressed":i,children:[i?e.jsx(Wn,{className:"h-4 w-4"}):e.jsx(Xn,{className:"h-4 w-4"}),i?"Collaborating":"Collaborate"]});return j?e.jsxs(At,{children:[e.jsx(Pt,{asChild:!0,children:L}),e.jsx(Et,{children:j})]}):L}function di(r,t,i,a,l){const c=s.useRef(new Set),f=ls();s.useEffect(()=>{const h=new Set(a.map(m=>m.sub));for(const m of Array.from(c.current))h.has(m)||c.current.delete(m)},[a]),s.useEffect(()=>{for(const h of a){if(c.current.has(h.sub))continue;c.current.add(h.sub);const m=h.name||h.email||"Someone";V(`${m} wants to collaborate`,{action:{label:"Allow",onClick:()=>{f.apiFetch(`/v1/admin/sites/${r}/content/${t}/edit-lock/collaboration`,{method:"POST",body:JSON.stringify({collaborationEnabled:!0,sessionId:i})}).then(()=>l()).catch(()=>V.error("Failed to enable collaboration"))}},cancel:{label:"Decline",onClick:()=>{f.apiFetch(`/v1/admin/sites/${r}/content/${t}/edit-lock/access-requests/${h.sub}?sessionId=${i}`,{method:"DELETE"}).catch(()=>V.error("Failed to decline request"))}},duration:1/0})}},[a,r,t,i,l,f])}function Hi(){const{host:r,collection:t,id:i}=Ln(),{data:a,isLoading:l}=Bn(r,i);return l?e.jsxs("div",{className:"space-y-4",children:[e.jsx(fe,{className:"h-8 w-64"}),e.jsx(fe,{className:"h-64 w-full"})]}):a?.content?e.jsx(ui,{host:r,collection:t,contentId:i,content:a.content,draft:a.draft,publishedBlockId:a.publishedBlockId}):e.jsx("p",{className:"text-muted-foreground",children:"Content not found."})}function ui({host:r,collection:t,contentId:i,content:a,draft:l,publishedBlockId:c}){const f=Tn(),h=ls(),m=Bs(),{collections:u}=Zn(),v=qn(r,i),x=$n(r,i),S=Vn(r,i),w=_n(r,i),j=Mn(r,i),L=Hn(r,i),C=l?{title:l.title??a.title,slug:l.slug??a.slug??"",snippet:l.snippet??a.snippet??"",tags:l.tags??a.tags??[],cover:l.cover??a.cover??null,body:l.body??{},relationships:l.relationships??{}}:void 0,{user:R}=$s(),{data:y}=ea(),k=R?(y?.superAdminIds??[]).includes(R.sub):!1,N=s.useRef(null),$=s.useCallback(async()=>{const n=N.current;return n?n():{ok:!0}},[]),M=typeof l?.updatedAt=="number"?l.updatedAt:0,[_,E]=s.useState(M),D=s.useRef(M);s.useEffect(()=>{D.current=_},[_]);const T=s.useRef(()=>{}),X=s.useRef(()=>{}),[K,se]=s.useState(!1),re=s.useRef(!1),Z=s.useRef(!1),Q=s.useRef(()=>!1),F=s.useRef(()=>!1),le=s.useRef(null),o=Za(r,i,{getIsDirty:()=>Q.current()||re.current,getIsSaving:()=>Z.current,getIsSavingSync:()=>F.current(),onIdleRelease:()=>le.current?.()}),d=li(r,i,o.collaborationEnabled,{onCollabDisabled:()=>o.setCollaborationEnabled(!1),onPublishRequested:()=>T.current(),onSaveVersionRequested:()=>X.current(),onPublishInProgress:()=>se(!0),onPublished:()=>{se(!1),V.success("Content published")}}),[O,B]=s.useState(null),I=d.active?1e4:void 0,H=s.useCallback(n=>{const p=n,W=(p?.accessRequests??[]).filter(Te=>Te.sub!==R?.sub);o.setAccessRequests(W),typeof p?.updatedAt=="number"&&(E(p.updatedAt),xs(!1))},[o,R?.sub]),A=s.useRef(null),J=s.useCallback(()=>{A.current?.()},[]),ye=s.useRef(null),ne=s.useCallback(()=>ye.current?.()??{},[]),g=Ka(r,i,C,()=>{B("This slug is already in use by another item in this collection")},n=>{o.onAutosaveConflict({lockHolder:n.body?.lockHolder??void 0,takeoverReason:n.body?.takeoverReason??"expired"})},I,H,{onBeforeFirstSave:$,onStaleBaseConflict:J,getCurrentParams:ne});N.current=o.tryAcquireForEdit,re.current=g.isDirty,Z.current=g.isSaving,Q.current=g.getHasPending,F.current=g.getIsSavingSync,le.current=g.markLockReleased;const Be=o.bumpIdleTimer;s.useEffect(()=>{g.lastSavedAt!=null&&Be()},[g.lastSavedAt,Be]);const Y=(o.status==="blocked-edit"||o.status==="read-only-explicit"||o.status==="stale-reload-pending"||o.status==="poll-ceiling")&&!o.collaborationEnabled;di(r,i,o.sessionId,o.accessRequests,()=>o.setCollaborationEnabled(!0));const{data:os}=Sa(r),ds=os?.map(n=>n.tag),de=u.find(n=>n.name===t),me=s.useMemo(()=>de?.fields??[],[de?.fields]),je=s.useMemo(()=>de?.relationships??[],[de?.relationships]),b=de?.singleton??!1,q=sa(),[U,ee]=s.useState(l?.title??a.title),[G,Ce]=s.useState(l?.slug??a.slug??""),[ce,we]=s.useState(l?.snippet??a.snippet??""),Ms=l?.autoSnippet??"",[pe,Re]=s.useState(l?.tags??a.tags??[]),[ae,Ne]=s.useState(l?.cover??a.cover??null),[ge,De]=s.useState(l?.body??{}),[be,Ae]=s.useState(l?.relationships??{}),[zt,us]=s.useState(0),[Kt,Yt]=s.useState(!1),[Qt,qe]=s.useState(!1),[Gt,Le]=s.useState(!1),[Wt,$e]=s.useState(null),[hs,Ve]=s.useState(!1),[Xt,_e]=s.useState(!1),[Zt,Me]=s.useState(!1),[He,Hs]=s.useState(""),[en,fs]=s.useState(!1),[ms,Js]=s.useState(""),zs=Jn(r,i),te=s.useCallback(()=>({title:U,slug:G,snippet:ce,tags:pe,cover:ae,body:ge,relationships:be,...o.sessionId?{sessionId:o.sessionId}:{},...D.current?{baseUpdatedAt:D.current}:{}}),[U,G,ce,pe,ae,ge,be,o.sessionId]);s.useEffect(()=>{ye.current=te},[te]);const sn=d.active?n=>{ee(n),d.updateField("title",n)}:n=>{ee(n),g.schedule({...te(),title:n})},tn=d.active?n=>{Ce(n),B(null),d.updateField("slug",n)}:n=>{Ce(n),B(null),g.schedule({...te(),slug:n})},nn=d.active?n=>{we(n),d.updateField("snippet",n)}:n=>{we(n),g.schedule({...te(),snippet:n})},an=d.active?n=>{Re(n),d.updateField("tags",n)}:n=>{Re(n),g.schedule({...te(),tags:n})},Ks=d.active?n=>{Ne(n),d.updateField("cover",n)}:n=>{Ne(n),g.schedule({...te(),cover:n})},rn=d.active?n=>{De(n),d.updateField("body",n)}:n=>{De(n),g.schedule({...te(),body:n})},ln=d.active?n=>{Ae(n),d.updateField("relationships",n)}:n=>{Ae(n),g.schedule({...te(),relationships:n})},Je=d.active,ze=d.setActiveField,ps=s.useCallback(n=>{Je&&ze(n)},[Je,ze]),gs=s.useCallback(()=>{Je&&ze(null)},[Je,ze]);s.useEffect(()=>{if(d.active)return d.onRemoteFieldChange((n,p)=>{switch(n){case"title":ee(p);break;case"slug":Ce(p);break;case"snippet":we(p);break;case"tags":Re(p);break;case"cover":Ne(p);break;case"body":De(p);break;case"relationships":Ae(p);break}d.isLeader&&g.schedule(te())})},[d.active,d.onRemoteFieldChange,d.isLeader]);const Ys=d.active?d.isLeader:!0;s.useEffect(()=>{if(!d.active||!Ys)return;g.schedule(te());const n=window.setInterval(()=>{g.schedule(te())},1e4);return()=>window.clearInterval(n)},[Ys,d.active]);const Qs=g.lastSavedBlockId??l?.blockId,ke=s.useCallback(n=>{const p=n.draft,z=n.content;if(!p&&!z)return;const W={title:p?.title??z?.title??"",slug:p?.slug??z?.slug??"",snippet:p?.snippet??z?.snippet??"",tags:p?.tags??z?.tags??[],cover:p?.cover??z?.cover??null,body:p?.body??{},relationships:p?.relationships??{}};ee(W.title),Ce(W.slug),we(W.snippet),Re(W.tags),Ne(W.cover),De(W.body),Ae(W.relationships);const Te=p?.updatedAt??0;E(Te),g.resetBaseline(W),us(js=>js+1)},[g]),[oe,bs]=s.useState(null),cn=s.useMemo(()=>oe?.updatedBy?[oe.updatedBy]:[],[oe?.updatedBy]),{resolve:Gs}=Vt(cn),on=s.useMemo(()=>{const n=oe?.updatedBy??"";if(!n)return"another admin";const p=Gs(n);return!p||p===n?"another admin":p},[oe?.updatedBy,Gs]),[dn,xs]=s.useState(!1),Ke=s.useRef(null),Ws=o.setStaleReloadPending,Ye=s.useCallback((n,p)=>{g.pause(),Ke.current={title:U,slug:G,snippet:ce,tags:pe,cover:ae,body:ge,relationships:be};const z=n.draft?.updatedAt??0,W=n.draft?.updatedBy??"";bs({trigger:p,updatedBy:W,updatedAt:z,latest:n}),Ws()},[g,Ws,U,G,ce,pe,ae,ge,be]),Qe=o.endEditing,un=s.useCallback(()=>{const n=oe;n&&ke(n.latest),Ke.current=null,bs(null),xs(!1),g.resume(),Qe()},[oe,ke,g,Qe]),Xs=o.resumeEditingAfterStale,hn=s.useCallback(()=>{const n=Ke.current;n&&(ee(n.title),Ce(n.slug),we(n.snippet),Re(n.tags),Ne(n.cover),De(n.body),Ae(n.relationships),us(p=>p+1),g.resetBaseline(n),Ke.current=null),bs(null),xs(!0),g.resume(),Xs()},[g,Xs]),Pe=s.useCallback(async()=>(await m.invalidateQueries({queryKey:["sites",r,"content-detail",i]}),m.getQueryData(["sites",r,"content-detail",i])??null),[m,r,i]),fn=s.useCallback(async()=>{g.cancel();const n=await Pe();n&&ke(n),Qe()},[g,Pe,ke,Qe]),Zs=o.setReadOnlyExplicit,mn=s.useCallback(async()=>{g.cancel();const n=await Pe();n&&ke(n),Zs()},[g,Pe,ke,Zs]),et=s.useCallback(async()=>{const n=await Pe();n&&Ye(n,"save-conflict")},[Pe,Ye]);s.useEffect(()=>{A.current=()=>void et()},[et]);const pn=s.useCallback(()=>{g.pause()},[g]),gn=s.useCallback(()=>{g.resume()},[g]),bn=s.useCallback(n=>{Ye(n,"tab-refocus")},[Ye]);ei({host:r,contentId:i,isDirty:g.isDirty,serverBlockId:Qs,serverUpdatedAt:_,onSilentReload:ke,onStaleWithDirty:bn,onTabHidden:pn,onTabVisibleResume:gn});const ue=La(a.publishedAt,a.lastPublishedAt,c,Qs,a.scheduledAt,a.scheduledFailed),Ge=Ta(ue),We=Ia(ue),{data:xe}=St(r,i,!!a.publishedAt),he=s.useMemo(()=>{if(!hs||!xe)return null;const n=b?void 0:{title:xe.title,slug:xe.slug,snippet:xe.snippet,tags:xe.tags},p=je.map(ie=>({name:ie.name,label:ie.label})),z=xe.relationships,W=p.length>0?{defs:p,values:z??{}}:void 0,Te=Oe(me,xe.fields??{},n,W),js=b?void 0:{title:U,slug:G,snippet:ce,tags:pe},Nn=p.length>0?{defs:p,values:be}:void 0,Dn=Oe(me,ge,js,Nn),An=ma(Te,Dn,{comparator:(ie,ks)=>ie.text===ks.text&&ie.indent===ks.indent&&ie.type===ks.type});let nt=0,at=0;for(const ie of An)ie.added?nt+=ie.count??0:ie.removed&&(at+=ie.count??0);return{added:nt,removed:at}},[hs,xe,me,je,b,U,G,ce,pe,ge,be]),[xn]=In(),vn=xn.get("from")==="recent"?`/sites/${r}/content`:`/sites/${r}/content/${t}`;ha({title:b?de?.label??t:U||"Untitled",showBack:!b,backTo:b?void 0:vn,badge:{label:Ge.label,variant:Ge.variant}});function Xe(){if(d.active&&!d.isLeader){d.sendRequestPublish();return}if(a.publishedAt&&a.slug&&G!==a.slug){_e(!0);return}ue==="published-changes"?Ve(!0):vs()}async function vs(){d.active&&d.isLeader&&d.sendPublishInProgress();try{await g.flush({createVersion:!0});const p=(await v.mutateAsync(void 0))?.updatedAt;typeof p=="number"&&p>0&&E(p),g.discard(),o.endEditing(),V.success("Content published"),d.active&&d.isLeader&&d.sendPublished({contentId:i})}catch(n){if(n instanceof Ee&&n.code==="SLUG_TAKEN"){B("This slug is already in use by another item in this collection"),V.error("Slug already in use",{description:"Please choose a different slug before publishing."});return}V.error("Failed to publish",{description:n instanceof Error?n.message:void 0})}finally{}}function yn(){if(d.active&&!d.isLeader){d.sendRequestSaveVersion();return}g.flush({createVersion:!0})}s.useEffect(()=>{T.current=Xe,X.current=()=>{g.flush({createVersion:!0})}});async function jn(){try{const p=(await x.mutateAsync())?.updatedAt;typeof p=="number"&&p>0&&E(p),Le(!1),o.endEditing(),V.success("Content unpublished")}catch(n){V.error("Failed to unpublish",{description:n instanceof Error?n.message:void 0})}}async function kn(){try{g.discard();const n=await h.apiFetch(`/v1/admin/sites/${r}/content/${i}/published`);await zs.mutateAsync();const p={title:n.title??"",slug:n.slug??"",snippet:n.snippet??"",tags:n.tags??[],cover:n.cover??null,body:n.fields??{},relationships:n.relationships??{}};ee(p.title),Ce(p.slug),we(p.snippet),Re(p.tags),Ne(p.cover),De(p.body),Ae(p.relationships),us(z=>z+1),g.resetBaseline(p),V.success("Changes discarded")}catch(n){V.error("Failed to discard changes",{description:n instanceof Error?n.message:void 0})}}async function Sn(){try{await S.mutateAsync(),o.endEditing(),V.success("Content deleted"),f(`/sites/${r}/content/${t}`)}catch(n){V.error("Failed to delete",{description:n instanceof Error?n.message:void 0})}}async function Cn(){if(He)try{await g.flush({createVersion:!0});const n=new Date(He).getTime(),z=(await j.mutateAsync(n))?.updatedAt;typeof z=="number"&&z>0&&E(z),Me(!1),Hs(""),o.endEditing(),V.success("Content scheduled for publishing")}catch(n){V.error("Failed to schedule",{description:n instanceof Error?n.message:void 0})}}async function wn(){try{const p=(await L.mutateAsync())?.updatedAt;typeof p=="number"&&p>0&&E(p),o.endEditing(),V.success("Schedule cancelled")}catch(n){V.error("Failed to cancel schedule",{description:n instanceof Error?n.message:void 0})}}async function Rn(){if(ms)try{const n=new Date(ms).getTime();await w.mutateAsync(n),fs(!1),V.success("Publish date updated")}catch(n){V.error("Failed to update publish date",{description:n instanceof Error?n.message:void 0})}}function ys(n){const p=new Date(n),z=p.getTimezoneOffset();return new Date(p.getTime()-z*6e4).toISOString().slice(0,16)}const st=e.jsx("div",{className:`space-y-6 ${Y?"pointer-events-none opacity-60 select-none":""}`,"aria-readonly":Y||void 0,children:me.length>0?e.jsx(Pa,{fields:me,values:ge,onChange:rn},zt):e.jsx(Ue,{children:e.jsx(Fe,{className:"py-8 text-center",children:e.jsxs("p",{className:"text-sm text-muted-foreground",children:["No fields defined for this collection."," ",e.jsx(Un,{to:`/sites/${r}/settings/collections/${t}`,className:"underline",children:"Configure fields"})]})})})}),tt=e.jsxs("div",{className:`space-y-6 ${Y?"pointer-events-none opacity-60 select-none":""}`,"aria-readonly":Y||void 0,children:[!b&&e.jsx(Ue,{children:e.jsxs(Fe,{className:"space-y-4 pt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(Ze,{htmlFor:"title",className:"flex items-center",children:["Title",e.jsx(es,{field:"title",editors:d.editors})]}),e.jsx(it,{id:"title",value:U,onChange:n=>sn(n.target.value),onFocus:()=>ps("title"),onBlur:gs})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(Ze,{htmlFor:"slug",className:"flex items-center",children:["Slug",e.jsx(es,{field:"slug",editors:d.editors})]}),e.jsx(it,{id:"slug",value:G,onChange:n=>tn(n.target.value),onFocus:()=>ps("slug"),onBlur:gs,className:O?"border-destructive":""}),O&&e.jsx("p",{className:"text-sm text-destructive",children:O})]}),e.jsxs(_t,{defaultOpen:!!ce,children:[e.jsxs(Mt,{className:"flex w-full items-center gap-2 text-sm font-medium",children:[e.jsx(Lt,{className:"h-4 w-4 transition-transform [[data-state=open]>&]:rotate-90"}),"Snippet",e.jsx("span",{className:"text-xs text-muted-foreground",children:"(auto-generated if empty)"}),e.jsx(es,{field:"snippet",editors:d.editors})]}),e.jsxs(Ht,{className:"mt-2 space-y-2",children:[e.jsx(ka,{id:"snippet",value:ce,onChange:n=>nn(n.target.value),onFocus:()=>ps("snippet"),onBlur:gs,rows:3,placeholder:"Brief summary of this content..."}),!ce&&Ms&&e.jsxs("p",{className:"text-xs italic text-muted-foreground",children:["Auto-generated: ",Ms]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(Ze,{children:"Cover Image"}),ae?e.jsxs("div",{className:"flex items-center gap-3 rounded-md border p-2 cursor-pointer hover:bg-muted/50 transition-colors",onClick:()=>qe(!0),children:[e.jsx("img",{src:wa(ae.url),alt:ae.alt??ae.filename??"",className:"h-10 w-10 rounded object-cover bg-muted"}),e.jsx("span",{className:"flex-1 truncate text-sm",children:ae.filename??ae.alt??ae.id}),e.jsx(P,{type:"button",variant:"ghost",size:"sm",onClick:n=>{n.stopPropagation(),Ks(null)},children:e.jsx(rt,{className:"h-3 w-3"})})]}):e.jsxs(P,{type:"button",variant:"outline",className:"w-full",onClick:()=>qe(!0),children:[e.jsx(ta,{className:"mr-2 h-4 w-4"}),"Select Image"]}),e.jsx(Ca,{open:Qt,onClose:()=>qe(!1),onSelect:n=>{Ks({id:n.mediaId,url:n.url,width:n.width??0,height:n.height??0,alt:n.alt,caption:n.caption,filename:n.filename}),qe(!1)},allowedTypes:["image/*"]})]})]})}),!b&&e.jsxs(Ue,{children:[e.jsx(ht,{children:e.jsxs(ft,{className:"flex items-center",children:["Tags",e.jsx(es,{field:"tags",editors:d.editors})]})}),e.jsx(Fe,{children:e.jsx(ua,{tags:pe,onChange:an,suggestions:ds})})]}),je.length>0&&e.jsx(Ra,{relationships:je,values:be,onChange:ln,host:r}),e.jsxs(Ue,{children:[e.jsx(ht,{children:e.jsx(ft,{children:"Info"})}),e.jsxs(Fe,{className:"space-y-2 text-sm",children:[e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-muted-foreground",children:"Collection"}),e.jsx("span",{children:a.collection})]}),e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-muted-foreground",children:"ID"}),e.jsx("span",{className:"font-mono text-xs",children:a.contentId})]}),a.publishedAt?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex justify-between items-center",children:[e.jsx("span",{className:"text-muted-foreground",children:"Published"}),en?e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("input",{type:"datetime-local",value:ms,onChange:n=>Js(n.target.value),className:"text-xs border rounded px-1 py-0.5",max:ys(Date.now())}),e.jsx(P,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:Rn,disabled:w.isPending,children:e.jsx(lt,{className:"h-3 w-3"})}),e.jsx(P,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>fs(!1),children:e.jsx(rt,{className:"h-3 w-3"})})]}):e.jsxs("span",{className:"cursor-pointer hover:underline",title:Se(a.publishedAt),onClick:()=>{Js(ys(a.publishedAt)),fs(!0)},children:[ts(a.publishedAt),e.jsx(na,{className:"inline ml-1 h-3 w-3 text-muted-foreground"})]})]}),a.lastPublishedAt&&a.lastPublishedAt!==a.publishedAt&&e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-muted-foreground",children:"Last published"}),e.jsx("span",{title:Se(a.lastPublishedAt),children:ts(a.lastPublishedAt)})]})]}):a.lastPublishedAt?e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-muted-foreground",children:"Last published"}),e.jsx("span",{title:Se(a.lastPublishedAt),children:ts(a.lastPublishedAt)})]}):null,ue==="scheduled"&&a.scheduledAt&&e.jsxs("div",{className:"flex justify-between items-center",children:[e.jsx("span",{className:"text-muted-foreground",children:"Scheduled for"}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(ct,{className:"h-3 w-3"}),Se(a.scheduledAt)]})]}),ue==="schedule-failed"&&e.jsx("div",{className:"text-destructive text-xs",children:"Scheduled publishing failed after multiple attempts."}),a.publishedAt&&e.jsxs(P,{variant:"outline",size:"sm",className:"w-full mt-2",onClick:()=>{$e({kind:"published"}),Le(!0)},children:[e.jsx(aa,{className:"mr-2 h-4 w-4"}),"View published"]})]})]}),e.jsx(mi,{host:r,contentId:i,onViewVersion:n=>{$e({kind:"history",blockId:n.blockId,createdAt:n.createdAt,title:n.title}),Le(!0)}}),!b&&e.jsx(fi,{deleteOpen:Kt,setDeleteOpen:Yt,onDelete:Sn,host:r,contentId:i})]});return e.jsx(Ea.Provider,{value:d.active?d:null,children:e.jsxs("div",{className:"mx-auto max-w-6xl",children:[o.collaborationEnabled&&e.jsx("div",{className:"mb-3",children:e.jsx(ci,{status:d.status,editors:d.editors})}),o.status==="poll-ceiling"&&e.jsx(gt,{variant:"poll-ceiling"}),(o.status==="blocked-edit"||o.status==="read-only-explicit")&&o.lockHolder&&e.jsx(gt,{variant:o.status,lockHolder:o.lockHolder,onRequestCollaboration:()=>o.requestCollaboration.mutate(),isRequesting:o.requestCollaboration.isPending,requestSent:o.requestCollaboration.isSuccess,onDiscardPending:o.status==="blocked-edit"?()=>void fn():void 0,onViewReadOnly:o.status==="blocked-edit"?()=>void mn():void 0,onResumeEditing:o.status==="read-only-explicit"?()=>o.exitReadOnly():void 0,onForceTakeover:o.status==="blocked-edit"&&k?()=>void o.forceTakeover():void 0}),o.status==="read-only-explicit"&&!o.lockHolder&&e.jsxs("div",{className:"bg-emerald-50 border border-emerald-200 rounded-lg p-4 mb-4 flex items-center justify-between gap-3","data-testid":"lock-available-banner",children:[e.jsx("p",{className:"text-sm text-emerald-900",children:"Lock available — you can take over editing now."}),e.jsx(P,{size:"sm",onClick:()=>void o.takeEditing(),"data-testid":"take-editing-btn",children:"Take editing"})]}),!q&&e.jsxs("div",{className:"mb-4 flex flex-wrap items-center gap-2 md:mb-6 md:flex-nowrap md:gap-3 md:justify-between",children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-2 md:gap-3",children:[e.jsx("h1",{className:"truncate text-xl font-semibold md:text-2xl",children:b?de?.label??t:U||"Untitled"}),e.jsx(ia,{variant:Ge.variant,children:Ge.label}),g.isSaving&&e.jsxs("span",{className:"flex items-center gap-1 text-xs text-muted-foreground",children:[e.jsx(ve,{className:"h-3 w-3 animate-spin"}),"Saving..."]}),!g.isSaving&&g.lastSavedAt&&e.jsxs("span",{className:"flex items-center gap-1 text-xs text-muted-foreground",children:[e.jsx(lt,{className:"h-3 w-3"}),"Saved"]}),dn&&e.jsxs("span",{className:"flex items-center gap-1 text-xs text-amber-700",title:"Your edits are based on an older version. The next save may be rejected.","data-testid":"stale-base-indicator",children:[e.jsx("span",{className:"inline-block h-2 w-2 rounded-full bg-amber-500"}),"Older version"]})]}),e.jsxs("div",{className:"flex gap-2 ml-auto",children:[e.jsx(oi,{host:r,contentId:i,collaborationEnabled:o.collaborationEnabled,hasConnectedPeers:d.editors.length>0,isLockHolder:o.status==="editing",sessionId:o.sessionId,onChange:n=>o.setCollaborationEnabled(n),onBeforeDisable:d.sendDisableCollab}),e.jsxs(P,{variant:"outline",size:"sm",onClick:yn,disabled:g.isSaving||Y,className:"px-3",children:[g.isSaving&&e.jsx(ve,{className:"mr-2 h-4 w-4 animate-spin"}),"Save Draft"]}),ue==="scheduled"&&e.jsxs(e.Fragment,{children:[e.jsxs(P,{variant:"outline",size:"sm",onClick:wn,disabled:L.isPending||Y,className:"px-3",children:[L.isPending&&e.jsx(ve,{className:"mr-2 h-4 w-4 animate-spin"}),"Cancel Schedule"]}),e.jsxs(P,{size:"sm",onClick:Xe,disabled:v.isPending||K||Y,className:"px-3",children:[(v.isPending||K)&&e.jsx(ve,{className:"mr-2 h-4 w-4 animate-spin"}),"Publish Now"]})]}),ue!=="scheduled"&&We&&e.jsxs("div",{className:"flex",children:[e.jsxs(P,{size:"sm",onClick:Xe,disabled:v.isPending||K||Y,className:cs("px-3",!a.publishedAt&&"rounded-r-none"),children:[(v.isPending||K)&&e.jsx(ve,{className:"mr-2 h-4 w-4 animate-spin"}),We]}),!a.publishedAt&&e.jsxs(ot,{children:[e.jsx(dt,{asChild:!0,children:e.jsx(P,{size:"sm",className:"rounded-l-none border-l px-2",disabled:v.isPending||K||Y,children:e.jsx(ra,{className:"h-4 w-4"})})}),e.jsx(ut,{align:"end",children:e.jsxs(Cs,{onClick:()=>Me(!0),disabled:Y,children:[e.jsx(ct,{className:"mr-2 h-4 w-4"}),"Schedule for later"]})})]})]}),a.publishedAt&&e.jsxs(ot,{children:[e.jsx(dt,{asChild:!0,children:e.jsx(P,{variant:"outline",size:"sm",className:"size-8 p-0",disabled:Y,children:e.jsx(la,{className:"h-4 w-4"})})}),e.jsxs(ut,{align:"end",children:[ue==="published-changes"&&e.jsxs(Cs,{onClick:kn,disabled:zs.isPending||Y,children:[e.jsx(ca,{className:"mr-2 h-4 w-4"}),"Discard Changes"]}),e.jsx(Cs,{onClick:jn,className:"text-destructive focus:text-destructive",disabled:Y,children:"Unpublish"})]})]})]})]}),q?e.jsxs(Rt,{defaultValue:"content",children:[e.jsxs("div",{className:"mb-2 flex items-center",children:[e.jsxs(Nt,{variant:"line",children:[e.jsx(ns,{value:"content",children:"Content"}),e.jsx(ns,{value:"info",children:"Info"})]}),e.jsxs("div",{className:"ml-auto flex gap-2",children:[e.jsxs(P,{variant:"outline",size:"sm",onClick:()=>g.flush({createVersion:!0}),disabled:g.isSaving||Y,children:[g.isSaving&&e.jsx(ve,{className:"mr-1 h-3 w-3 animate-spin"}),"Save"]}),ue!=="scheduled"&&We&&e.jsxs(P,{size:"sm",onClick:Xe,disabled:v.isPending||Y,children:[v.isPending&&e.jsx(ve,{className:"mr-1 h-3 w-3 animate-spin"}),We]})]})]}),e.jsx(as,{value:"content",className:"mt-0",children:st}),e.jsx(as,{value:"info",className:"mt-0",children:tt})]}):e.jsxs("div",{className:"grid gap-6 lg:grid-cols-3",children:[e.jsx("div",{className:"lg:col-span-2",children:st}),e.jsx("div",{children:tt})]}),e.jsx(ni,{open:Gt,onOpenChange:n=>{Le(n),n||$e(null)},host:r,contentId:i,collectionFields:me,isSingleton:b,isPublished:!!a.publishedAt,draftBody:ge,draftMetadata:b?void 0:{title:U,slug:G,snippet:ce,tags:pe},initialVersion:Wt,collectionRelationships:je,draftRelationships:be}),e.jsx(si,{open:!!oe,trigger:oe?.trigger??"tab-refocus",updatedBy:on,updatedAt:oe?.updatedAt??0,onReload:un,onCancel:hn}),e.jsx(Tt,{open:hs,onOpenChange:Ve,children:e.jsxs(It,{children:[e.jsxs(Ut,{children:[e.jsx(Ft,{children:"Publish changes?"}),e.jsx(Ot,{children:he?e.jsxs(e.Fragment,{children:[he.added>0&&e.jsxs("span",{className:"text-green-600",children:["+",he.added," added"]}),he.added>0&&he.removed>0&&", ",he.removed>0&&e.jsxs("span",{className:"text-red-600",children:["-",he.removed," removed"]}),he.added===0&&he.removed===0&&e.jsx("span",{children:"No visible changes detected."})]}):"This will update the published version with your current changes."})]}),e.jsx("div",{className:"mb-2",children:e.jsx(P,{variant:"link",className:"p-0 h-auto text-sm",onClick:()=>{Ve(!1),$e({kind:"draft"}),Le(!0)},children:"View full diff"})}),e.jsxs(Bt,{children:[e.jsx(qt,{children:"Cancel"}),e.jsx($t,{onClick:()=>{Ve(!1),vs()},children:"Publish Update"})]})]})}),e.jsx(Es,{open:Xt,onOpenChange:_e,children:e.jsxs(Ls,{children:[e.jsxs(Ts,{children:[e.jsx(Is,{children:"Slug change detected"}),e.jsxs(Us,{children:["You are changing the slug from “",a.slug,"” to “",G,"”. This may break external bookmarks and SEO links."]})]}),e.jsx(hi,{host:r,contentId:i}),e.jsxs(Fs,{children:[e.jsx(P,{variant:"outline",onClick:()=>_e(!1),children:"Cancel"}),e.jsx(P,{onClick:()=>{_e(!1),vs()},children:"Publish Anyway"})]})]})}),e.jsx(Es,{open:Zt,onOpenChange:Me,children:e.jsxs(Ls,{children:[e.jsxs(Ts,{children:[e.jsx(Is,{children:"Schedule publishing"}),e.jsx(Us,{children:"Choose a date and time to automatically publish this content. Times are rounded to the nearest 15-minute interval."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(Ze,{htmlFor:"schedule-date",children:"Publish at"}),e.jsx("input",{id:"schedule-date",type:"datetime-local",value:He,onChange:n=>Hs(n.target.value),min:ys(Date.now()+1200*1e3),className:"w-full rounded-md border px-3 py-2 text-sm",step:"900"})]}),e.jsxs(Fs,{children:[e.jsx(P,{variant:"outline",onClick:()=>Me(!1),children:"Cancel"}),e.jsxs(P,{onClick:Cn,disabled:!He||j.isPending,children:[j.isPending&&e.jsx(ve,{className:"mr-2 h-4 w-4 animate-spin"}),"Schedule"]})]})]})})]})})}function hi({host:r,contentId:t}){const{data:i}=wt(r,t,!0);return!i||i.count===0?null:e.jsxs("div",{className:"rounded-md border border-yellow-500/50 bg-yellow-50 p-3 text-sm dark:bg-yellow-950/30",children:[e.jsxs("p",{className:"font-medium text-yellow-800 dark:text-yellow-200",children:["This content is referenced by ",i.count," other"," ",i.count===1?"item":"items",":"]}),e.jsxs("ul",{className:"mt-1 list-disc pl-5 text-yellow-700 dark:text-yellow-300",children:[i.items.slice(0,5).map(a=>e.jsxs("li",{children:[a.title," (",a.collection,")"]},`${a.contentId}-${a.fieldName}`)),i.items.length>5&&e.jsxs("li",{children:["and ",i.items.length-5," more..."]})]})]})}function fi({deleteOpen:r,setDeleteOpen:t,onDelete:i,host:a,contentId:l}){const{data:c}=wt(a,l,r);return e.jsxs(e.Fragment,{children:[e.jsx(Dt,{}),e.jsxs(Es,{open:r,onOpenChange:t,children:[e.jsx(oa,{asChild:!0,children:e.jsxs(P,{variant:"destructive",className:"w-full",children:[e.jsx(da,{className:"mr-2 h-4 w-4"}),"Delete"]})}),e.jsxs(Ls,{children:[e.jsxs(Ts,{children:[e.jsx(Is,{children:"Delete content?"}),e.jsx(Us,{children:"This action cannot be undone. The content will be permanently deleted."})]}),c&&c.count>0&&e.jsxs("div",{className:"rounded-md border border-yellow-500/50 bg-yellow-50 p-3 text-sm dark:bg-yellow-950/30",children:[e.jsxs("p",{className:"font-medium text-yellow-800 dark:text-yellow-200",children:["This content is referenced by ",c.count," other"," ",c.count===1?"item":"items",":"]}),e.jsxs("ul",{className:"mt-1 list-disc pl-5 text-yellow-700 dark:text-yellow-300",children:[c.items.slice(0,5).map(f=>e.jsxs("li",{children:[f.title," (",f.collection,")"]},`${f.contentId}-${f.fieldName}`)),c.items.length>5&&e.jsxs("li",{children:["and ",c.items.length-5," more..."]})]})]}),e.jsxs(Fs,{children:[e.jsx(P,{variant:"outline",onClick:()=>t(!1),children:"Cancel"}),e.jsx(P,{variant:"destructive",onClick:i,children:"Delete"})]})]})]})]})}function mi({host:r,contentId:t,onViewVersion:i}){const{data:a}=Ct(r,t),[l,c]=s.useState(!1),f=a?.items??[],h=f.map(u=>u.createdBy).filter(Boolean),{resolve:m}=Vt(h);return f.length===0?null:e.jsx(Ue,{children:e.jsx(Fe,{className:"pt-4",children:e.jsxs(_t,{open:l,onOpenChange:c,children:[e.jsxs(Mt,{className:"flex w-full items-center gap-2 text-sm font-medium",children:[e.jsx(Lt,{className:cs("h-4 w-4 transition",l&&"rotate-90")}),"Version History (",f.length,")"]}),e.jsx(Ht,{className:"mt-2",children:e.jsx("div",{className:"space-y-1",children:f.map((u,v)=>e.jsxs("button",{className:"py-1 text-sm hover:bg-muted rounded px-1 -mx-1 transition-colors w-full text-left",onClick:()=>i(u),children:[e.jsx("span",{children:Se(u.createdAt)}),u.createdBy&&e.jsx("span",{className:"ml-2 text-muted-foreground",children:m(u.createdBy)}),u.title&&e.jsx("span",{className:"ml-2 text-muted-foreground",children:u.title})]},`${u.createdAt}-${v}`))})})]})})})}export{Hi as ContentEditPage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{j as s}from"./tanstack-Bs3zYPPV.js";import{u as Ce,f as ke,r as S}from"./react-vendor-C2CvUxFh.js";import{w as ye,x as Ae,B as R,P as ie,v as w,z as de,I as oe,X as B,A as Pe,L as z,j as T,S as Te,a as _e,y as Ie}from"./index-Ce5pmRMj.js";import{d as $e,e as Fe,a as Ve,b as Be,c as De}from"./useContent-Bs7nel7C.js";import{u as Le}from"./useTags-B-HgMVwo.js";import{u as Ue}from"./useContentSearch-B3aTjuCu.js";import{u as qe}from"./usePageTitle-C1r1-C00.js";import{u as Me}from"./useFilterParams-DYdEuWPE.js";import{m as ue}from"./media-url-DdCoIedP.js";import{u as Re,F as ze}from"./FilterBar-BZoa63zh.js";import{C as Oe,c as Ee}from"./card-C9hfyHXf.js";import{C as Z}from"./checkbox-DVJcwUt1.js";import{P as He,a as We,b as Xe}from"./popover-CzaQYEEP.js";import{S as C,a as k,b as y,c as A,d as o}from"./select-CrRhFGIi.js";import{T as Ze,a as Ge,b as he,c as D,d as Qe,e as L}from"./table-_3bMY0_z.js";import{a as I,f as xe}from"./format-C88SDH8g.js";import{g as me,a as ge}from"./contentStatus-CkPi9Dh6.js";import{B as Je}from"./BulkActionBar-BxdfUSrN.js";import{P as Ke}from"./Pagination-Df9nQ7Z0.js";import"./radix-C5ZmWuuL.js";import"./command-Bfmj0MEL.js";const O=3,fe=[{value:"updated_desc",label:"Last updated"},{value:"updated_asc",label:"Oldest updated"},{value:"title_asc",label:"Title A–Z",requiresCollection:!0},{value:"title_desc",label:"Title Z–A",requiresCollection:!0},{value:"created_desc",label:"Newest created"},{value:"created_asc",label:"Oldest created"}],G=[{value:"all",label:"All statuses"},{value:"draft",label:"Draft"},{value:"published",label:"Published"},{value:"changed",label:"Changed"},{value:"unpublished",label:"Unpublished"},{value:"scheduled",label:"Scheduled"}];function bs(){const{host:c,collection:r}=Ce(),_=ke(),{collections:pe}=ye(),[i,a]=Me([{key:"q",defaultValue:""},{key:"search",defaultValue:"prefix"},{key:"tag",defaultValue:""},{key:"status",defaultValue:""},{key:"sort",defaultValue:"updated_desc"},{key:"relatedTo",defaultValue:""},{key:"relField",defaultValue:""},{key:"page",defaultValue:"1"},{key:"perPage",defaultValue:"20"},{key:"after",defaultValue:""}]),$=i.search,x=i.tag||void 0,m=i.status||void 0,g=i.sort,j=i.relatedTo,v=i.relField,b=Number(i.page)||1,E=Number(i.perPage)||20,Q=S.useMemo(()=>{const e=i.after;return e?e.split(","):[]},[i.after]),[F,V]=S.useState(i.q),[u,t]=S.useState(new Set),H=Ae(),f=pe.find(e=>e.name===r),U=f?.relationships??[],{data:J}=Re(c,j||void 0),K=S.useMemo(()=>{if(!j||!v)return null;const e=U.find(n=>n.name===v);return{type:"relationship",relName:v,relLabel:e?.label??v,contentId:j,contentTitle:J??"Loading..."}},[j,v,U,J]);qe({title:f?.label??r??"",actions:f?.singleton?void 0:s.jsx(R,{size:"sm",onClick:()=>_(`/sites/${c}/content/${r}/new`),children:s.jsx(ie,{className:"h-4 w-4"})})});const h=Ue(F,300);S.useEffect(()=>{h!==i.q&&a({q:h})},[h,i.q,a]);const N=S.useCallback(()=>{a({page:"1",after:""}),t(new Set)},[a]),je=S.useMemo(()=>{const e={};return h&&(e.q=h,e.search=$),x&&(e.tag=x),m&&(e.status=m),g!=="updated_desc"&&(e.sort=g),j&&(e.relatedTo=j),v&&(e.relField=v),e.limit=E,e},[h,$,x,m,g,j,v,E]),ve=b>1?Q[b-2]:void 0,{data:P,isLoading:be}=$e(c,r,je,ve),W=Fe(c),Y=Ve(c),ee=Be(c),se=De(c),{data:ae}=Le(c),q=S.useMemo(()=>ae?.map(e=>e.tag)??[],[ae]);if(f?.singleton&&P?.items.length===1)return _(`/sites/${c}/content/${r}/${P.items[0].contentId}`,{replace:!0}),null;const M=P?.items,X=M?.map(e=>e.contentId)??[],te=X.length>0&&X.every(e=>u.has(e));function le(e){t(n=>{const l=new Set(n);return l.has(e)?l.delete(e):l.add(e),l})}function Ne(){t(te?new Set:new Set(X))}const ne=!!(h||x||m||j),re=!!h,ce=[$!=="prefix"?1:0,x?1:0,m?1:0,g!=="updated_desc"?1:0].reduce((e,n)=>e+n,0),Se=Y.isPending||ee.isPending||se.isPending;async function we(){try{const e=await W.mutateAsync({collection:r,title:f?.label??r});w.success("Singleton content recreated"),_(`/sites/${c}/content/${r}/${e.contentId}`)}catch(e){w.error("Failed to recreate singleton",{description:e instanceof Error?e.message:void 0})}}return s.jsxs("div",{children:[!H&&s.jsxs("div",{className:"mb-6 flex items-center justify-between",children:[s.jsx("h1",{className:"text-2xl font-semibold",children:f?.label??r}),!f?.singleton&&s.jsxs(R,{onClick:()=>_(`/sites/${c}/content/${r}/new`),children:[s.jsx(ie,{className:"mr-2 h-4 w-4"}),"New"]})]}),u.size>0?s.jsx(Je,{selectedCount:u.size,onPublish:async()=>{const e=[...u],l=(await Y.mutateAsync(e)).filter(d=>d.status==="rejected").length;l?w.error(`${l} of ${e.length} failed to publish`):w.success(`${e.length} item(s) published`),N()},onUnpublish:async()=>{const e=[...u],l=(await ee.mutateAsync(e)).filter(d=>d.status==="rejected").length;l?w.error(`${l} of ${e.length} failed to unpublish`):w.success(`${e.length} item(s) unpublished`),N()},onDelete:async()=>{const e=[...u],l=(await se.mutateAsync(e)).filter(d=>d.status==="rejected").length;l?w.error(`${l} of ${e.length} failed to delete`):w.success(`${e.length} item(s) deleted`),N()},onClear:()=>t(new Set),isPending:Se}):H?s.jsxs("div",{className:"mb-4 flex items-center gap-2",children:[s.jsxs("div",{className:"relative flex-1",children:[s.jsx(de,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),s.jsx(oe,{placeholder:"Search...",value:F,onChange:e=>{V(e.target.value),N()},className:"pl-8 pr-8"}),F&&s.jsx("button",{onClick:()=>{V(""),N()},className:"absolute right-2 top-2.5 text-muted-foreground hover:text-foreground",children:s.jsx(B,{className:"h-4 w-4"})})]}),s.jsxs(He,{children:[s.jsx(We,{asChild:!0,children:s.jsxs(R,{variant:"outline",size:"icon",className:"relative shrink-0","aria-label":"Filters",children:[s.jsx(Pe,{className:"h-4 w-4"}),ce>0&&s.jsx("span",{className:"absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground",children:ce})]})}),s.jsxs(Xe,{className:"w-64 space-y-3",align:"end",children:[s.jsxs("div",{className:"space-y-2",children:[s.jsx(z,{className:"text-xs font-medium",children:"Search Mode"}),s.jsxs(C,{value:$,onValueChange:e=>{a({search:e,page:"1",after:""}),t(new Set)},children:[s.jsx(k,{children:s.jsx(y,{})}),s.jsxs(A,{children:[s.jsx(o,{value:"prefix",children:"Starts with"}),s.jsx(o,{value:"full",children:"Contains"})]})]})]}),q.length>0&&s.jsxs("div",{className:"space-y-2",children:[s.jsx(z,{className:"text-xs font-medium",children:"Tag"}),s.jsxs(C,{value:x??"__all__",onValueChange:e=>{a({tag:e==="__all__"?"":e,page:"1",after:""}),t(new Set)},children:[s.jsx(k,{children:s.jsx(y,{})}),s.jsxs(A,{children:[s.jsx(o,{value:"__all__",children:"All tags"}),q.map(e=>s.jsx(o,{value:e,children:e},e))]})]})]}),s.jsxs("div",{className:"space-y-2",children:[s.jsx(z,{className:"text-xs font-medium",children:"Status"}),s.jsxs(C,{value:m??"all",onValueChange:e=>{a({status:e==="all"?"":e,page:"1",after:""}),t(new Set)},children:[s.jsx(k,{children:s.jsx(y,{})}),s.jsx(A,{children:G.map(e=>s.jsx(o,{value:e.value??"all",children:e.label},e.value??"all"))})]})]}),s.jsxs("div",{className:"space-y-2",children:[s.jsx(z,{className:"text-xs font-medium",children:"Sort"}),s.jsxs(C,{value:g,onValueChange:e=>{a({sort:e,page:"1",after:""}),t(new Set)},disabled:re,children:[s.jsx(k,{children:s.jsx(y,{})}),s.jsx(A,{children:fe.map(e=>s.jsx(o,{value:e.value,disabled:e.requiresCollection&&!r,children:e.label},e.value))})]})]})]})]})]}):s.jsxs("div",{className:"mb-4 flex flex-wrap items-center gap-2",children:[s.jsxs("div",{className:"relative flex items-center",children:[s.jsx(de,{className:"absolute left-2.5 h-4 w-4 text-muted-foreground"}),s.jsx(oe,{placeholder:"Search titles...",value:F,onChange:e=>{V(e.target.value),N()},className:"w-56 pl-8 pr-8"}),F&&s.jsx("button",{onClick:()=>{V(""),N()},className:"absolute right-2 text-muted-foreground hover:text-foreground",children:s.jsx(B,{className:"h-4 w-4"})})]}),s.jsxs(C,{value:$,onValueChange:e=>{a({search:e,page:"1",after:""}),t(new Set)},children:[s.jsx(k,{className:"w-[130px]",children:s.jsx(y,{})}),s.jsxs(A,{children:[s.jsx(o,{value:"prefix",children:"Starts with"}),s.jsx(o,{value:"full",children:"Contains"})]})]}),q.length>0&&s.jsxs(C,{value:x??"__all__",onValueChange:e=>{a({tag:e==="__all__"?"":e,page:"1",after:""}),t(new Set)},children:[s.jsx(k,{className:"w-[140px]",children:s.jsx(y,{placeholder:"Tag"})}),s.jsxs(A,{children:[s.jsx(o,{value:"__all__",children:"All tags"}),q.map(e=>s.jsx(o,{value:e,children:e},e))]})]}),s.jsxs(C,{value:m??"all",onValueChange:e=>{a({status:e==="all"?"":e,page:"1",after:""}),t(new Set)},children:[s.jsx(k,{className:"w-[150px]",children:s.jsx(y,{})}),s.jsx(A,{children:G.map(e=>s.jsx(o,{value:e.value??"all",children:e.label},e.value??"all"))})]}),s.jsx("div",{className:"ml-auto",children:s.jsxs(C,{value:g,onValueChange:e=>{a({sort:e,page:"1",after:""}),t(new Set)},disabled:re,children:[s.jsx(k,{className:"w-[170px]",children:s.jsx(y,{})}),s.jsx(A,{children:fe.map(e=>s.jsx(o,{value:e.value,disabled:e.requiresCollection&&!r,children:e.label},e.value))})]})})]}),U.length>0&&s.jsx("div",{className:"mb-3",children:s.jsx(ze,{relationships:U,activeFilters:K?[K]:[],onFilterAdd:e=>{a({relatedTo:e.contentId,relField:e.relName,page:"1",after:""}),t(new Set)},onFilterRemove:()=>{a({relatedTo:"",relField:"",page:"1",after:""}),t(new Set)}})}),ne&&u.size===0&&s.jsxs("div",{className:"mb-3 flex flex-wrap items-center gap-1.5",children:[h&&s.jsxs(T,{variant:"secondary",className:"gap-1",children:["Search: ",h,s.jsx("button",{onClick:()=>{V(""),N()},children:s.jsx(B,{className:"h-3 w-3"})})]}),x&&s.jsxs(T,{variant:"secondary",className:"gap-1",children:["Tag: ",x,s.jsx("button",{onClick:()=>{a({tag:"",page:"1",after:""}),t(new Set)},children:s.jsx(B,{className:"h-3 w-3"})})]}),m&&s.jsxs(T,{variant:"secondary",className:"gap-1",children:["Status: ",G.find(e=>e.value===m)?.label,s.jsx("button",{onClick:()=>{a({status:"",page:"1",after:""}),t(new Set)},children:s.jsx(B,{className:"h-3 w-3"})})]})]}),be?s.jsx("div",{className:"space-y-2",children:Array.from({length:5}).map((e,n)=>s.jsx(Te,{className:"h-12 w-full"},n))}):M?.length?s.jsxs(s.Fragment,{children:[H?s.jsx("div",{className:"grid gap-3 sm:grid-cols-2","data-testid":"content-card-view",children:M.map(e=>{const n=me(e.publishedAt,e.lastPublishedAt,e.publishedBlockId,e.lastDraftBlockId,e.scheduledAt,e.scheduledFailed),l=ge(n),d=e.tags??[];return s.jsx(Oe,{className:Ie("cursor-pointer gap-0 overflow-hidden py-0 transition-shadow hover:shadow-md",u.has(e.contentId)&&"ring-2 ring-primary"),onClick:()=>_(`/sites/${c}/content/${r}/${e.contentId}`),children:s.jsxs(Ee,{className:"p-3",children:[s.jsxs("div",{className:"flex items-start gap-3 min-w-0",children:[e.cover?.url&&s.jsx("img",{src:ue(e.cover.url),alt:e.cover.alt??"",className:"h-12 w-12 rounded object-cover flex-shrink-0"}),s.jsxs("div",{className:"min-w-0 flex-1",children:[s.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[s.jsx("span",{className:"font-medium truncate",children:e.draftTitle||e.title||"Untitled"}),s.jsx(T,{variant:l.variant,className:"shrink-0",children:l.label})]}),(e.draftSlug||e.slug)&&s.jsxs("p",{className:"text-xs text-muted-foreground truncate mt-0.5",children:["/",e.draftSlug||e.slug]}),s.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:g.startsWith("created")?e.createdAt?I(e.createdAt):"—":e.lastDraftAt?I(e.lastDraftAt):"—"})]}),s.jsx(Z,{checked:u.has(e.contentId),onCheckedChange:()=>le(e.contentId),onClick:p=>p.stopPropagation(),className:"mt-1"})]}),d.length>0&&s.jsx("div",{className:"mt-2 flex flex-wrap gap-1",children:d.slice(0,O).map(p=>s.jsx(T,{variant:"outline",className:"text-[10px] px-1.5 py-0",children:p},p))})]})},e.contentId)})}):s.jsxs(Ze,{children:[s.jsx(Ge,{children:s.jsxs(he,{children:[s.jsx(D,{className:"w-10",children:s.jsx(Z,{checked:te,onCheckedChange:Ne,"aria-label":"Select all"})}),s.jsx(D,{children:"Title"}),s.jsx(D,{children:"Slug"}),s.jsx(D,{children:"Status"}),s.jsx(D,{children:g.startsWith("created")?"Created":"Updated"})]})}),s.jsx(Qe,{children:M.map(e=>{const n=me(e.publishedAt,e.lastPublishedAt,e.publishedBlockId,e.lastDraftBlockId),l=ge(n),d=e.tags??[];return s.jsxs(he,{className:"cursor-pointer",onClick:()=>_(`/sites/${c}/content/${r}/${e.contentId}`),children:[s.jsx(L,{onClick:p=>p.stopPropagation(),children:s.jsx(Z,{checked:u.has(e.contentId),onCheckedChange:()=>le(e.contentId),"aria-label":`Select ${e.draftTitle||e.title||"Untitled"}`})}),s.jsx(L,{className:"font-medium",children:s.jsxs("div",{className:"flex items-center gap-3",children:[e.cover?.url&&s.jsx("img",{src:ue(e.cover.url),alt:e.cover.alt??"",className:"h-8 w-8 rounded object-cover flex-shrink-0"}),s.jsxs("div",{className:"min-w-0",children:[s.jsx("span",{children:e.draftTitle||e.title||"Untitled"}),d.length>0&&s.jsxs("div",{className:"mt-0.5 flex flex-wrap gap-1",children:[d.slice(0,O).map(p=>s.jsx(T,{variant:"outline",className:"text-[10px] px-1.5 py-0 font-normal text-muted-foreground",children:p},p)),d.length>O&&s.jsxs("span",{className:"text-[10px] text-muted-foreground",children:["+",d.length-O," more"]})]})]})]})}),s.jsx(L,{className:"text-muted-foreground text-sm",children:e.draftSlug||e.slug||"—"}),s.jsx(L,{children:s.jsx(T,{variant:l.variant,children:l.label})}),s.jsx(L,{className:"text-muted-foreground",children:g.startsWith("created")?e.createdAt?I(e.createdAt):"—":e.scheduledAt&&!e.publishedAt?s.jsxs("span",{title:xe(e.scheduledAt),children:["Scheduled ",I(e.scheduledAt)]}):e.publishedAt?s.jsx("span",{title:xe(e.publishedAt),children:I(e.publishedAt)}):e.lastDraftAt?I(e.lastDraftAt):"—"})]},e.contentId)})})]}),s.jsx(Ke,{page:b,hasNext:!!P?.hasMore,hasPrevious:b>1,onNext:()=>{if(P?.items.length){const e=P.items[P.items.length-1].contentId,n=[...Q.slice(0,b-1),e];a({page:String(b+1),after:n.join(",")})}else a({page:String(b+1)});t(new Set)},onPrevious:()=>{const e=b-1;a(e<=1?{page:"1",after:""}:{page:String(e)}),t(new Set)},perPage:E,onPerPageChange:e=>{a({perPage:String(e),page:"1",after:""}),t(new Set)}})]}):f?.singleton?s.jsxs("div",{className:"space-y-4",children:[s.jsx("p",{className:"text-muted-foreground",children:"Singleton content is missing. Click below to recreate it."}),s.jsxs(R,{onClick:we,disabled:W.isPending,children:[W.isPending&&s.jsx(_e,{className:"mr-2 h-4 w-4 animate-spin"}),"Recreate ",f.label]})]}):s.jsx("p",{className:"text-muted-foreground",children:ne?"No content matches the current filters.":"No content yet."})]})}export{bs as ContentListPage};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/BlockEditor-3wnisTOZ.js","assets/tanstack-Bs3zYPPV.js","assets/react-vendor-C2CvUxFh.js","assets/index-Ce5pmRMj.js","assets/radix-C5ZmWuuL.js","assets/index-BB9Syqw2.css","assets/yjs-tXBm_srz.js","assets/command-Bfmj0MEL.js","assets/MediaField-CxccCFGQ.js","assets/useMedia-ae3s_ajC.js","assets/select-CrRhFGIi.js","assets/card-C9hfyHXf.js","assets/media-url-DdCoIedP.js","assets/CustomBlockPreview-DNnTFM0z.js","assets/ContentField-pilCbdnA.js","assets/core.esm-DdQHdRkd.js","assets/sortable.esm-qVEMoaTg.js","assets/popover-CzaQYEEP.js","assets/useContentSearch-B3aTjuCu.js","assets/BlockEditor-CQpF8tYb.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{j as t}from"./tanstack-Bs3zYPPV.js";import{I as h,B as g,P as A,ai as I,T as D,aJ as B,x as _,S as $,aK as z,y as N,Y as E,Z as L,_ as M,L as P}from"./index-Ce5pmRMj.js";import{T as q}from"./textarea-6fq0R6VV.js";import{C as w}from"./checkbox-DVJcwUt1.js";import{S as O,a as R,b as V,c as U,d as K}from"./select-CrRhFGIi.js";import{a as H}from"./MediaField-CxccCFGQ.js";import{b as Y,c as G,P as J,D as X,e as Z,C as Q}from"./core.esm-DdQHdRkd.js";import{S as W,v as ee,a as te,u as se}from"./sortable.esm-qVEMoaTg.js";import{C as y,c as C}from"./card-C9hfyHXf.js";import{r as x}from"./react-vendor-C2CvUxFh.js";import{C as re}from"./ContentField-pilCbdnA.js";import{K as ne,M as ae}from"./radix-C5ZmWuuL.js";function j({field:e,value:s,onChange:r}){const n=e.options;return t.jsx(h,{value:s??"",onChange:a=>r(a.target.value),placeholder:n?.placeholder,maxLength:n?.maxLength,required:!!n?.required,type:e.type==="url"?"url":e.type==="email"?"email":"text"})}function oe({field:e,value:s,onChange:r}){const n=e.options;return t.jsx(q,{value:s??"",onChange:a=>r(a.target.value),placeholder:n?.placeholder,maxLength:n?.maxLength,required:!!n?.required,rows:4})}function ie({field:e,value:s,onChange:r}){const n=e.options;return t.jsx(h,{type:"number",value:s??"",onChange:a=>r(a.target.value===""?void 0:Number(a.target.value)),min:n?.min,max:n?.max,step:n?.step,required:!!n?.required})}function ce({field:e,value:s,onChange:r}){return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(w,{id:`field-${e.name}`,checked:!!s,onCheckedChange:n=>r(!!n)}),t.jsx("label",{htmlFor:`field-${e.name}`,className:"text-sm text-muted-foreground",children:e.label})]})}function le({field:e,value:s,onChange:r}){const a=e.options?.choices??[];return t.jsxs(O,{value:s??"",onValueChange:i=>r(i),children:[t.jsx(R,{children:t.jsx(V,{placeholder:"Select..."})}),t.jsx(U,{children:a.map(i=>t.jsx(K,{value:i,children:i},i))})]})}function de({field:e,value:s,onChange:r}){const n=Y(G(J)),a=Array.isArray(s)?s:[],l=e.options?.itemFields??[],o=a.map((m,c)=>`item-${c}`);function d(){r([...a,{}])}function p(m){r(a.filter((c,u)=>u!==m))}function f(m,c){const u=[...a];u[m]=c,r(u)}function v(m){const{active:c,over:u}=m;if(u&&c.id!==u.id){const T=o.indexOf(String(c.id)),k=o.indexOf(String(u.id));r(te(a,T,k))}}return t.jsx(X,{sensors:n,collisionDetection:Z,onDragEnd:v,children:t.jsx(W,{items:o,strategy:ee,children:t.jsxs("div",{className:"space-y-3",children:[a.map((m,c)=>t.jsx(ue,{id:`item-${c}`,itemFields:l,item:m,onUpdate:u=>f(c,u),onRemove:()=>p(c)},`item-${c}`)),t.jsxs(g,{type:"button",variant:"outline",size:"sm",onClick:d,children:[t.jsx(A,{className:"mr-2 h-3 w-3"})," Add Item"]})]})})})}function ue({id:e,itemFields:s,item:r,onUpdate:n,onRemove:a}){const{attributes:i,listeners:l,setNodeRef:o,transform:d,transition:p}=se({id:e}),f={transform:Q.Transform.toString(d),transition:p};return t.jsx(y,{ref:o,style:f,children:t.jsxs(C,{className:"flex gap-2 p-3",children:[t.jsx("button",{type:"button",className:"cursor-grab touch-none text-muted-foreground hover:text-foreground",...i,...l,children:t.jsx(I,{className:"h-4 w-4"})}),t.jsx("div",{className:"flex-1",children:t.jsx(F,{fields:s,values:r,onChange:n})}),t.jsx(g,{type:"button",variant:"ghost",size:"sm",onClick:a,className:"text-destructive",children:t.jsx(D,{className:"h-3 w-3"})})]})})}const me=x.createContext(null);function S(){return x.useContext(me)}const xe=x.lazy(()=>z(()=>import("./BlockEditor-3wnisTOZ.js").then(e=>e.a),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]))),pe=2,b=x.createContext(0);function fe({field:e,value:s,onChange:r,compact:n=!0}){const a=x.useContext(b),l=B()?.blockTypes??[],o=_(),p=S()?.getBlockNoteCollab(e.name);return a>=pe?t.jsx("div",{className:"rounded-md border border-muted p-4 text-sm text-muted-foreground",children:"Maximum nesting depth reached. Cannot embed another block editor here."}):t.jsx(b.Provider,{value:a+1,children:t.jsx("div",{className:o?"":"rounded-md border",children:t.jsx(x.Suspense,{fallback:t.jsx($,{className:"h-48"}),children:t.jsx(xe,{initialBlocks:Array.isArray(s)?s:[],onChange:r,blockTypes:l,compact:n,collaboration:p})})})})}function he({field:e,value:s,onChange:r}){const a=e.options?.fields??[],i=s&&typeof s=="object"&&!Array.isArray(s)?s:{};return t.jsx(y,{children:t.jsx(C,{className:"p-3",children:t.jsx(F,{fields:a,values:i,onChange:l=>r(l)})})})}function je({field:e,value:s,onChange:r}){const n=e.options,a=e.type==="datetime",i=be(s,a);function l(o){if(!o){r(void 0);return}const d=a?new Date(o).getTime():Date.UTC(Number(o.slice(0,4)),Number(o.slice(5,7))-1,Number(o.slice(8,10)));if(Number.isNaN(d)){r(void 0);return}r(d)}return t.jsx(h,{type:a?"datetime-local":"date",value:i,onChange:o=>l(o.target.value),required:!!n?.required})}function be(e,s){if(e==null||e==="")return"";let r;if(typeof e=="number")r=e;else if(typeof e=="string"){const a=/^-?\d+$/.test(e)?Number(e):Date.parse(e);if(Number.isNaN(a))return"";r=a}else return"";const n=new Date(r);if(Number.isNaN(n.getTime()))return"";if(s){const a=i=>String(i).padStart(2,"0");return`${n.getFullYear()}-${a(n.getMonth()+1)}-${a(n.getDate())}T${a(n.getHours())}:${a(n.getMinutes())}`}return n.toISOString().slice(0,10)}function ge({className:e,size:s="default",...r}){return t.jsx(ne,{"data-slot":"avatar","data-size":s,className:N("group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6",e),...r})}function Ne({className:e,...s}){return t.jsx(ae,{"data-slot":"avatar-fallback",className:N("bg-muted text-muted-foreground flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs",e),...s})}function ye(e){const s=e.trim().split(/\s+/).filter(Boolean);return s.length>=2?(s[0][0]+s[1][0]).toUpperCase():(s[0]?.[0]??"?").toUpperCase()}function Ce({field:e,editors:s}){const r=s.filter(n=>n.activeField===e);return r.length===0?null:t.jsx("span",{className:"inline-flex items-center -space-x-1 ml-2 align-middle","data-testid":"field-presence-indicator",children:r.map(n=>t.jsxs(E,{children:[t.jsx(L,{asChild:!0,children:t.jsx(ge,{className:"h-4 w-4 border-2 ring-1 ring-background",style:{borderColor:n.color},"aria-label":`${n.name} is editing`,children:t.jsx(Ne,{className:"text-[8px] font-medium",style:{backgroundColor:n.color+"20",color:n.color},children:ye(n.name)})})}),t.jsxs(M,{children:[n.name," is editing"]})]},n.sub))})}function F({fields:e,values:s,onChange:r}){const n=S();function a(o,d){r({...s,[o]:d})}function i(o){n?.setActiveField(o)}function l(o){o.currentTarget.contains(o.relatedTarget)||n?.setActiveField(null)}return t.jsx("div",{className:"space-y-4",children:e.map(o=>t.jsxs("div",{className:"space-y-2",onFocusCapture:()=>i(o.name),onBlurCapture:l,children:[o.type!=="boolean"&&t.jsxs(P,{className:"flex items-center",children:[o.label,n&&t.jsx(Ce,{field:o.name,editors:n.editors})]}),Se(o,s[o.name],d=>a(o.name,d))]},o.name))})}function Se(e,s,r){switch(e.type){case"text":case"url":case"email":return t.jsx(j,{field:e,value:s,onChange:r});case"textarea":return t.jsx(oe,{field:e,value:s,onChange:r});case"number":return t.jsx(ie,{field:e,value:s,onChange:r});case"boolean":return t.jsx(ce,{field:e,value:s,onChange:r});case"select":return t.jsx(le,{field:e,value:s,onChange:r});case"media":return t.jsx(H,{field:e,value:s,onChange:r});case"content":return t.jsx(re,{field:e,value:s,onChange:r});case"blocks":return t.jsx(fe,{field:e,value:s,onChange:r});case"array":return t.jsx(de,{field:e,value:s,onChange:r});case"container":return t.jsx(he,{field:e,value:s,onChange:r});case"date":case"datetime":return t.jsx(je,{field:e,value:s,onChange:r});default:return t.jsx(j,{field:e,value:s,onChange:r})}}export{ge as A,me as C,F,Ne as a,Ce as b,ye as i};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as N,j as e}from"./tanstack-Bs3zYPPV.js";import{u as v,r as h}from"./react-vendor-C2CvUxFh.js";import{e as w,j as x,X as y,a6 as S,a7 as F,B as p,ba as j,a9 as R,aa as I,ad as P}from"./index-Ce5pmRMj.js";import{P as T,a as L,b as D}from"./popover-CzaQYEEP.js";import{C as B,a as M,b as $,c as k,d as q,e as E}from"./command-Bfmj0MEL.js";import{u as Q,a as z}from"./useContentSearch-B3aTjuCu.js";function H({relationships:s,activeFilters:a,onFilterAdd:o,onFilterRemove:i}){const{host:u}=v(),[l,c]=h.useState(null),[d,r]=h.useState(""),n=Q(d,300);if(s.length===0)return null;const g=new Set(a.map(t=>t.relName)),m=s.filter(t=>!g.has(t.name));function C(t){c(t),r("")}function f(t){l&&(o({type:"relationship",relName:l.name,relLabel:l.label,contentId:t.contentId,contentTitle:t.title}),c(null),r(""))}function b(){c(null),r("")}return e.jsxs("div",{className:"flex flex-wrap items-center gap-2","data-testid":"filter-bar",children:[a.map(t=>e.jsxs(x,{variant:"secondary",className:"gap-1 pl-2",children:[t.relLabel,": ",t.contentTitle,e.jsx("button",{onClick:()=>i(t.relName),className:"ml-0.5 hover:text-foreground","aria-label":`Remove ${t.relLabel} filter`,children:e.jsx(y,{className:"h-3 w-3"})})]},t.relName)),m.length>0&&(l?e.jsx(A,{host:u,rel:l,query:d,debouncedQuery:n,onQueryChange:r,onSelect:f,onClose:b}):e.jsxs(S,{children:[e.jsx(F,{asChild:!0,children:e.jsxs(p,{variant:"outline",size:"sm","data-testid":"add-filter-button",children:[e.jsx(j,{className:"mr-1.5 h-3.5 w-3.5"}),"Add filter"]})}),e.jsx(R,{align:"start",children:m.map(t=>e.jsx(I,{onSelect:()=>C(t),children:t.label},t.name))})]}))]})}function A({host:s,rel:a,query:o,debouncedQuery:i,onQueryChange:u,onSelect:l,onClose:c}){const{data:d,isLoading:r}=z(s,i,[a.targetCollection],"published");return e.jsxs(T,{open:!0,onOpenChange:n=>{n||c()},children:[e.jsx(L,{asChild:!0,children:e.jsxs(p,{variant:"outline",size:"sm",children:[e.jsx(j,{className:"mr-1.5 h-3.5 w-3.5"}),a.label,"..."]})}),e.jsx(D,{className:"w-80 p-0",align:"start",children:e.jsxs(B,{shouldFilter:!1,children:[e.jsx(M,{placeholder:`Search ${a.label.toLowerCase()}...`,value:o,onValueChange:u,autoFocus:!0}),e.jsx($,{children:r?e.jsx("p",{className:"py-6 text-center text-sm text-muted-foreground",children:"Searching..."}):e.jsxs(e.Fragment,{children:[e.jsx(k,{children:"No published content found."}),e.jsx(q,{heading:i.length===0?"Recent":void 0,children:d?.items.map(n=>e.jsxs(E,{value:n.contentId,onSelect:()=>l({contentId:n.contentId,collection:n.collection,slug:n.slug??"",title:n.title}),children:[e.jsx(P,{className:"h-4 w-4"}),e.jsx("span",{className:"flex-1 truncate",children:n.title}),e.jsx(x,{variant:"outline",className:"text-xs",children:n.collection})]},n.contentId))})]})})]})})]})}function J(s,a){const o=w();return N({queryKey:["sites",s,"content-detail",a,"filter-title"],queryFn:async()=>(await o.apiFetch(`/v1/admin/sites/${s}/content/${a}`)).content?.title||"Untitled",enabled:!!s&&!!a,staleTime:6e4})}export{H as F,J as u};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as c,N as m,v as s,z as d,B as f,G as u,X as b,K as g,w as h,M as x,P as v,U as C,o as j,s as y,f as O,W as P}from"./BlockEditor-3wnisTOZ.js";import{r as I}from"./react-vendor-C2CvUxFh.js";import{j as r}from"./tanstack-Bs3zYPPV.js";import"./index-Ce5pmRMj.js";import"./radix-C5ZmWuuL.js";import"./yjs-tXBm_srz.js";import"./command-Bfmj0MEL.js";import"./MediaField-CxccCFGQ.js";import"./useMedia-ae3s_ajC.js";import"./select-CrRhFGIi.js";import"./card-C9hfyHXf.js";import"./media-url-DdCoIedP.js";import"./FieldRenderer-DiOKvkWV.js";import"./textarea-6fq0R6VV.js";import"./checkbox-DVJcwUt1.js";import"./core.esm-DdQHdRkd.js";import"./sortable.esm-qVEMoaTg.js";import"./ContentField-pilCbdnA.js";import"./popover-CzaQYEEP.js";import"./useContentSearch-B3aTjuCu.js";import"./CustomBlockPreview-DNnTFM0z.js";function S(){let o=m(s),t=d(),n=f(),e=u({trailingBlock:!1,dictionary:{...n,placeholders:{emptyDocument:n.placeholders.new_comment}},schema:o.commentEditorSchema||b});return r.jsx(t.Comments.Card,{className:"bn-thread",children:r.jsx(g,{autoFocus:!0,editable:!0,editor:e,actions:({isEmpty:a})=>r.jsx(t.Generic.Toolbar.Root,{className:h("bn-action-toolbar","bn-comment-actions"),variant:"action-toolbar",children:r.jsx(t.Generic.Toolbar.Button,{className:"bn-button",mainTooltip:"Save",variant:"compact",isDisabled:a,onClick:async()=>{await o.createThread({initialComment:{body:e.document}}),o.stopPendingComment()},children:"Save"})})})})}var L=c({default:()=>U});function U(o){let t=x(),n=m(s),e=v(s,{editor:t,selector:i=>i.pendingComment}),a=C({editor:t,selector:({editor:i})=>e?{from:i.prosemirrorState.selection.from,to:i.prosemirrorState.selection.to}:void 0}),p=I.useMemo(()=>({...o.floatingUIOptions,useFloatingOptions:{open:!!e,onOpenChange:i=>{i||(n.stopPendingComment(),t.focus())},placement:"bottom",middleware:[j(10),y(),O()],...o.floatingUIOptions?.useFloatingOptions},focusManagerProps:{disabled:!1},elementProps:{style:{zIndex:60},...o.floatingUIOptions?.elementProps}}),[n,t,e,o.floatingUIOptions]),l=o.floatingComposer||S;return r.jsx(P,{position:a,...p,children:r.jsx(l,{})})}export{L as n,S as r,U as t};
|