@byline/host-tanstack-start 3.2.1 → 3.3.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.
|
@@ -4,7 +4,7 @@ import { FormRenderer } from "@byline/admin/react";
|
|
|
4
4
|
import { getDefaultStatus, getWorkflowStatuses } from "@byline/core";
|
|
5
5
|
import { useTranslation } from "@byline/i18n/react";
|
|
6
6
|
import { Container, Section, useToastManager } from "@byline/ui/react";
|
|
7
|
-
import { copyDocumentToLocale, deleteDocument, deleteDocumentLocale, duplicateCollectionDocument, unpublishDocument, updateCollectionDocumentWithPatches, updateDocumentStatus } from "../../server-fns/collections/index.js";
|
|
7
|
+
import { copyDocumentToLocale, deleteDocument, deleteDocumentLocale, duplicateCollectionDocument, unpublishDocument, updateCollectionDocumentSystemFields, updateCollectionDocumentWithPatches, updateDocumentStatus } from "../../server-fns/collections/index.js";
|
|
8
8
|
import { useNavigate } from "../chrome/loose-router.js";
|
|
9
9
|
import { useTanStackNavigationGuard } from "./tanstack-navigation-guard.js";
|
|
10
10
|
import { ViewMenu } from "./view-menu.js";
|
|
@@ -409,23 +409,30 @@ const EditView = ({ collectionDefinition, adminConfig, initialData, locale, cont
|
|
|
409
409
|
});
|
|
410
410
|
}
|
|
411
411
|
};
|
|
412
|
-
const handleSubmit = async ({ data: _data, patches, systemPath, systemAvailableLocales })=>{
|
|
412
|
+
const handleSubmit = async ({ data: _data, patches, contentDirty, pathDirty, systemPath, availableLocalesDirty, systemAvailableLocales })=>{
|
|
413
413
|
try {
|
|
414
|
-
await
|
|
414
|
+
if (pathDirty || availableLocalesDirty) await updateCollectionDocumentSystemFields({
|
|
415
415
|
data: {
|
|
416
416
|
collection: path,
|
|
417
417
|
id: String(initialData.id),
|
|
418
|
-
patches,
|
|
419
|
-
versionId: initialData.versionId,
|
|
420
418
|
locale,
|
|
421
|
-
...
|
|
422
|
-
path: systemPath
|
|
419
|
+
...pathDirty ? {
|
|
420
|
+
path: systemPath ?? null
|
|
423
421
|
} : {},
|
|
424
|
-
...
|
|
425
|
-
availableLocales: systemAvailableLocales
|
|
422
|
+
...availableLocalesDirty ? {
|
|
423
|
+
availableLocales: systemAvailableLocales ?? []
|
|
426
424
|
} : {}
|
|
427
425
|
}
|
|
428
426
|
});
|
|
427
|
+
if (contentDirty) await updateCollectionDocumentWithPatches({
|
|
428
|
+
data: {
|
|
429
|
+
collection: path,
|
|
430
|
+
id: String(initialData.id),
|
|
431
|
+
patches,
|
|
432
|
+
versionId: initialData.versionId,
|
|
433
|
+
locale
|
|
434
|
+
}
|
|
435
|
+
});
|
|
429
436
|
const description = t("collections.edit.updatedDescription", {
|
|
430
437
|
label: singularLower
|
|
431
438
|
});
|
|
@@ -12,15 +12,30 @@ export declare const updateCollectionDocumentWithPatches: import("@tanstack/reac
|
|
|
12
12
|
patches: DocumentPatch[];
|
|
13
13
|
versionId?: string;
|
|
14
14
|
locale?: string;
|
|
15
|
-
path?: string;
|
|
16
|
-
availableLocales?: string[];
|
|
17
15
|
}) => {
|
|
18
16
|
collection: string;
|
|
19
17
|
id: string;
|
|
20
18
|
patches: DocumentPatch[];
|
|
21
19
|
versionId?: string;
|
|
22
20
|
locale?: string;
|
|
23
|
-
|
|
21
|
+
}, Promise<{
|
|
22
|
+
status: "ok";
|
|
23
|
+
}>>;
|
|
24
|
+
export declare const updateCollectionDocumentSystemFields: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
|
|
25
|
+
collection: string;
|
|
26
|
+
id: string;
|
|
27
|
+
locale?: string;
|
|
28
|
+
/** Path override; `null`/omitted means no path write. */
|
|
29
|
+
path?: string | null;
|
|
30
|
+
/** Editorial advertised-locale set; omitted means no advertised-locale write. */
|
|
31
|
+
availableLocales?: string[];
|
|
32
|
+
}) => {
|
|
33
|
+
collection: string;
|
|
34
|
+
id: string;
|
|
35
|
+
locale?: string;
|
|
36
|
+
/** Path override; `null`/omitted means no path write. */
|
|
37
|
+
path?: string | null;
|
|
38
|
+
/** Editorial advertised-locale set; omitted means no advertised-locale write. */
|
|
24
39
|
availableLocales?: string[];
|
|
25
40
|
}, Promise<{
|
|
26
41
|
status: "ok";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createServerFn } from "@tanstack/react-start";
|
|
2
2
|
import { ERR_NOT_FOUND, getLogger, getServerConfig } from "@byline/core";
|
|
3
|
-
import { updateDocumentWithPatches } from "@byline/core/services";
|
|
3
|
+
import { updateDocumentSystemFields, updateDocumentWithPatches } from "@byline/core/services";
|
|
4
4
|
import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
5
5
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
6
6
|
const updateCollectionDocumentWithPatches = createServerFn({
|
|
7
7
|
method: 'POST'
|
|
8
8
|
}).inputValidator((input)=>input).handler(async ({ data: input })=>{
|
|
9
|
-
const { collection: path, id, patches, versionId, locale
|
|
9
|
+
const { collection: path, id, patches, versionId, locale } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
12
12
|
if (!config) throw ERR_NOT_FOUND({
|
|
@@ -31,6 +31,38 @@ const updateCollectionDocumentWithPatches = createServerFn({
|
|
|
31
31
|
documentId: id,
|
|
32
32
|
patches,
|
|
33
33
|
documentVersionId: versionId,
|
|
34
|
+
locale: locale ?? serverConfig.i18n.content.defaultLocale
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
status: 'ok'
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
const updateCollectionDocumentSystemFields = createServerFn({
|
|
41
|
+
method: 'POST'
|
|
42
|
+
}).inputValidator((input)=>input).handler(async ({ data: input })=>{
|
|
43
|
+
const { collection: path, id, locale, path: explicitPath, availableLocales } = input;
|
|
44
|
+
const logger = getLogger();
|
|
45
|
+
const config = await ensureCollection(path);
|
|
46
|
+
if (!config) throw ERR_NOT_FOUND({
|
|
47
|
+
message: 'Collection not found',
|
|
48
|
+
details: {
|
|
49
|
+
collectionPath: path
|
|
50
|
+
}
|
|
51
|
+
}).log(logger);
|
|
52
|
+
const serverConfig = getServerConfig();
|
|
53
|
+
const ctx = {
|
|
54
|
+
db: serverConfig.db,
|
|
55
|
+
definition: config.definition,
|
|
56
|
+
collectionId: config.collection.id,
|
|
57
|
+
collectionVersion: config.collection.version,
|
|
58
|
+
collectionPath: path,
|
|
59
|
+
logger,
|
|
60
|
+
defaultLocale: serverConfig.i18n.content.defaultLocale,
|
|
61
|
+
slugifier: serverConfig.slugifier,
|
|
62
|
+
requestContext: await getAdminRequestContext()
|
|
63
|
+
};
|
|
64
|
+
await updateDocumentSystemFields(ctx, {
|
|
65
|
+
documentId: id,
|
|
34
66
|
locale: locale ?? serverConfig.i18n.content.defaultLocale,
|
|
35
67
|
path: explicitPath,
|
|
36
68
|
availableLocales
|
|
@@ -39,4 +71,4 @@ const updateCollectionDocumentWithPatches = createServerFn({
|
|
|
39
71
|
status: 'ok'
|
|
40
72
|
};
|
|
41
73
|
});
|
|
42
|
-
export { updateCollectionDocumentWithPatches };
|
|
74
|
+
export { updateCollectionDocumentSystemFields, updateCollectionDocumentWithPatches };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": false,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
|
-
"version": "3.
|
|
6
|
+
"version": "3.3.0",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=20.9.0"
|
|
9
9
|
},
|
|
@@ -115,13 +115,13 @@
|
|
|
115
115
|
"react-swipeable": "^7.0.2",
|
|
116
116
|
"uuid": "^14.0.0",
|
|
117
117
|
"zod": "^4.4.3",
|
|
118
|
-
"@byline/
|
|
119
|
-
"@byline/auth": "3.
|
|
120
|
-
"@byline/
|
|
121
|
-
"@byline/
|
|
122
|
-
"@byline/
|
|
123
|
-
"@byline/
|
|
124
|
-
"@byline/
|
|
118
|
+
"@byline/admin": "3.3.0",
|
|
119
|
+
"@byline/auth": "3.3.0",
|
|
120
|
+
"@byline/i18n": "3.3.0",
|
|
121
|
+
"@byline/core": "3.3.0",
|
|
122
|
+
"@byline/ui": "3.3.0",
|
|
123
|
+
"@byline/client": "3.3.0",
|
|
124
|
+
"@byline/ai": "3.3.0"
|
|
125
125
|
},
|
|
126
126
|
"peerDependencies": {
|
|
127
127
|
"@tanstack/react-router": "^1.167.0",
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
deleteDocumentLocale,
|
|
22
22
|
duplicateCollectionDocument,
|
|
23
23
|
unpublishDocument,
|
|
24
|
+
updateCollectionDocumentSystemFields,
|
|
24
25
|
updateCollectionDocumentWithPatches,
|
|
25
26
|
updateDocumentStatus,
|
|
26
27
|
} from '../../server-fns/collections/index.js'
|
|
@@ -386,28 +387,57 @@ export const EditView = ({
|
|
|
386
387
|
const handleSubmit = async ({
|
|
387
388
|
data: _data,
|
|
388
389
|
patches,
|
|
390
|
+
contentDirty,
|
|
391
|
+
pathDirty,
|
|
389
392
|
systemPath,
|
|
393
|
+
availableLocalesDirty,
|
|
390
394
|
systemAvailableLocales,
|
|
391
395
|
}: {
|
|
392
396
|
// biome-ignore lint/suspicious/noExplicitAny: data is collection-specific
|
|
393
397
|
data: any
|
|
394
398
|
// biome-ignore lint/suspicious/noExplicitAny: patches list shape
|
|
395
399
|
patches: any[]
|
|
400
|
+
/** Document field data / patches changed → versioned write. */
|
|
401
|
+
contentDirty: boolean
|
|
402
|
+
/** Path widget changed → non-versioned direct write. */
|
|
403
|
+
pathDirty: boolean
|
|
396
404
|
systemPath?: string | null
|
|
405
|
+
/** Available-locales widget changed → non-versioned direct write. */
|
|
406
|
+
availableLocalesDirty: boolean
|
|
397
407
|
systemAvailableLocales?: string[]
|
|
398
408
|
}) => {
|
|
399
409
|
try {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
410
|
+
// Document-grain system fields write first via their own non-versioned
|
|
411
|
+
// path — so a path conflict surfaces before we mint a content version,
|
|
412
|
+
// and these immediate writes never reset workflow status. See
|
|
413
|
+
// docs/I18N.md.
|
|
414
|
+
if (pathDirty || availableLocalesDirty) {
|
|
415
|
+
await updateCollectionDocumentSystemFields({
|
|
416
|
+
data: {
|
|
417
|
+
collection: path,
|
|
418
|
+
id: String(initialData.id),
|
|
419
|
+
locale,
|
|
420
|
+
...(pathDirty ? { path: systemPath ?? null } : {}),
|
|
421
|
+
...(availableLocalesDirty ? { availableLocales: systemAvailableLocales ?? [] } : {}),
|
|
422
|
+
},
|
|
423
|
+
})
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Content (field data / patches) follows the normal versioned path —
|
|
427
|
+
// mints a new draft version. Skipped entirely when only the system
|
|
428
|
+
// fields changed, so a path/advertising edit never creates an empty
|
|
429
|
+
// content version.
|
|
430
|
+
if (contentDirty) {
|
|
431
|
+
await updateCollectionDocumentWithPatches({
|
|
432
|
+
data: {
|
|
433
|
+
collection: path,
|
|
434
|
+
id: String(initialData.id),
|
|
435
|
+
patches,
|
|
436
|
+
versionId: initialData.versionId as string | undefined,
|
|
437
|
+
locale,
|
|
438
|
+
},
|
|
439
|
+
})
|
|
440
|
+
}
|
|
411
441
|
|
|
412
442
|
const description = t('collections.edit.updatedDescription', { label: singularLower })
|
|
413
443
|
toastManager.add({
|
|
@@ -11,13 +11,18 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
11
11
|
import { ERR_NOT_FOUND, getLogger, getServerConfig } from '@byline/core'
|
|
12
12
|
import type { DocumentPatch } from '@byline/core/patches'
|
|
13
13
|
import type { DocumentLifecycleContext } from '@byline/core/services'
|
|
14
|
-
import { updateDocumentWithPatches } from '@byline/core/services'
|
|
14
|
+
import { updateDocumentSystemFields, updateDocumentWithPatches } from '@byline/core/services'
|
|
15
15
|
|
|
16
16
|
import { getAdminRequestContext } from '../../auth/auth-context.js'
|
|
17
17
|
import { ensureCollection } from '../../integrations/api-utils.js'
|
|
18
18
|
|
|
19
19
|
// ---------------------------------------------------------------------------
|
|
20
20
|
// Apply patches (patch-based update — creates a new immutable version)
|
|
21
|
+
//
|
|
22
|
+
// Document-grain system fields (`path`, `availableLocales`) are deliberately
|
|
23
|
+
// NOT handled here: they are written through their own non-versioned path
|
|
24
|
+
// (`updateCollectionDocumentSystemFields` below) so that editing them does not
|
|
25
|
+
// mint a new version or reset workflow status. See docs/I18N.md.
|
|
21
26
|
// ---------------------------------------------------------------------------
|
|
22
27
|
|
|
23
28
|
export const updateCollectionDocumentWithPatches = createServerFn({ method: 'POST' })
|
|
@@ -28,20 +33,10 @@ export const updateCollectionDocumentWithPatches = createServerFn({ method: 'POS
|
|
|
28
33
|
patches: DocumentPatch[]
|
|
29
34
|
versionId?: string
|
|
30
35
|
locale?: string
|
|
31
|
-
path?: string
|
|
32
|
-
availableLocales?: string[]
|
|
33
36
|
}) => input
|
|
34
37
|
)
|
|
35
38
|
.handler(async ({ data: input }) => {
|
|
36
|
-
const {
|
|
37
|
-
collection: path,
|
|
38
|
-
id,
|
|
39
|
-
patches,
|
|
40
|
-
versionId,
|
|
41
|
-
locale,
|
|
42
|
-
path: explicitPath,
|
|
43
|
-
availableLocales,
|
|
44
|
-
} = input
|
|
39
|
+
const { collection: path, id, patches, versionId, locale } = input
|
|
45
40
|
const logger = getLogger()
|
|
46
41
|
const config = await ensureCollection(path)
|
|
47
42
|
if (!config) {
|
|
@@ -69,6 +64,58 @@ export const updateCollectionDocumentWithPatches = createServerFn({ method: 'POS
|
|
|
69
64
|
patches,
|
|
70
65
|
documentVersionId: versionId,
|
|
71
66
|
locale: locale ?? serverConfig.i18n.content.defaultLocale,
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
return { status: 'ok' as const }
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// System-managed, document-grain fields (path + advertised locales)
|
|
74
|
+
//
|
|
75
|
+
// Non-versioned, immediate write — does NOT create a new version or change
|
|
76
|
+
// workflow status. Backs the admin path / available-locales widgets'
|
|
77
|
+
// direct-write Save (the `direct-write` and `both` dirty-reason cases).
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
export const updateCollectionDocumentSystemFields = createServerFn({ method: 'POST' })
|
|
81
|
+
.inputValidator(
|
|
82
|
+
(input: {
|
|
83
|
+
collection: string
|
|
84
|
+
id: string
|
|
85
|
+
locale?: string
|
|
86
|
+
/** Path override; `null`/omitted means no path write. */
|
|
87
|
+
path?: string | null
|
|
88
|
+
/** Editorial advertised-locale set; omitted means no advertised-locale write. */
|
|
89
|
+
availableLocales?: string[]
|
|
90
|
+
}) => input
|
|
91
|
+
)
|
|
92
|
+
.handler(async ({ data: input }) => {
|
|
93
|
+
const { collection: path, id, locale, path: explicitPath, availableLocales } = input
|
|
94
|
+
const logger = getLogger()
|
|
95
|
+
const config = await ensureCollection(path)
|
|
96
|
+
if (!config) {
|
|
97
|
+
throw ERR_NOT_FOUND({
|
|
98
|
+
message: 'Collection not found',
|
|
99
|
+
details: { collectionPath: path },
|
|
100
|
+
}).log(logger)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const serverConfig = getServerConfig()
|
|
104
|
+
const ctx: DocumentLifecycleContext = {
|
|
105
|
+
db: serverConfig.db,
|
|
106
|
+
definition: config.definition,
|
|
107
|
+
collectionId: config.collection.id,
|
|
108
|
+
collectionVersion: config.collection.version,
|
|
109
|
+
collectionPath: path,
|
|
110
|
+
logger,
|
|
111
|
+
defaultLocale: serverConfig.i18n.content.defaultLocale,
|
|
112
|
+
slugifier: serverConfig.slugifier,
|
|
113
|
+
requestContext: await getAdminRequestContext(),
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
await updateDocumentSystemFields(ctx, {
|
|
117
|
+
documentId: id,
|
|
118
|
+
locale: locale ?? serverConfig.i18n.content.defaultLocale,
|
|
72
119
|
path: explicitPath,
|
|
73
120
|
availableLocales,
|
|
74
121
|
})
|