@byline/host-tanstack-start 3.9.0 → 3.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin-shell/collections/document-history.d.ts +53 -0
- package/dist/admin-shell/collections/document-history.js +103 -0
- package/dist/admin-shell/collections/document-history.module.js +9 -0
- package/dist/admin-shell/collections/document-history_module.css +28 -0
- package/dist/admin-shell/collections/history.d.ts +8 -1
- package/dist/admin-shell/collections/history.js +73 -29
- package/dist/admin-shell/collections/history.module.js +1 -0
- package/dist/admin-shell/collections/history_module.css +4 -0
- package/dist/routes/create-collection-history-route.js +23 -6
- package/dist/server-fns/admin-account/change-password.js +1 -1
- package/dist/server-fns/admin-account/get.js +1 -1
- package/dist/server-fns/admin-account/update.js +1 -1
- package/dist/server-fns/admin-permissions/get-role-abilities.js +1 -1
- package/dist/server-fns/admin-permissions/set-role-abilities.js +1 -1
- package/dist/server-fns/admin-permissions/who-has.js +1 -1
- package/dist/server-fns/admin-roles/create.js +1 -1
- package/dist/server-fns/admin-roles/delete.js +1 -1
- package/dist/server-fns/admin-roles/get.js +1 -1
- package/dist/server-fns/admin-roles/reorder.js +1 -1
- package/dist/server-fns/admin-roles/update.js +1 -1
- package/dist/server-fns/admin-users/create.js +1 -1
- package/dist/server-fns/admin-users/delete.js +1 -1
- package/dist/server-fns/admin-users/disable.js +1 -1
- package/dist/server-fns/admin-users/enable.js +1 -1
- package/dist/server-fns/admin-users/get-user-roles.js +1 -1
- package/dist/server-fns/admin-users/get.js +1 -1
- package/dist/server-fns/admin-users/list.js +1 -1
- package/dist/server-fns/admin-users/set-password.js +1 -1
- package/dist/server-fns/admin-users/set-user-roles.js +1 -1
- package/dist/server-fns/admin-users/update.js +1 -1
- package/dist/server-fns/ai/execute.js +1 -1
- package/dist/server-fns/auth/sign-in.js +1 -1
- package/dist/server-fns/collections/audit.d.ts +50 -0
- package/dist/server-fns/collections/audit.js +40 -0
- package/dist/server-fns/collections/copy-to-locale.js +1 -1
- package/dist/server-fns/collections/create.js +1 -1
- package/dist/server-fns/collections/delete-locale.js +1 -1
- package/dist/server-fns/collections/delete.js +1 -1
- package/dist/server-fns/collections/duplicate.js +1 -1
- package/dist/server-fns/collections/get.js +2 -2
- package/dist/server-fns/collections/history.js +1 -1
- package/dist/server-fns/collections/index.d.ts +1 -0
- package/dist/server-fns/collections/index.js +1 -0
- package/dist/server-fns/collections/list.js +1 -1
- package/dist/server-fns/collections/reorder.js +1 -1
- package/dist/server-fns/collections/restore-version.js +1 -1
- package/dist/server-fns/collections/stats.js +1 -1
- package/dist/server-fns/collections/status.js +2 -2
- package/dist/server-fns/collections/update.js +2 -2
- package/dist/server-fns/collections/upload.js +1 -1
- package/dist/server-fns/i18n/set-locale.js +1 -1
- package/package.json +10 -10
- package/src/admin-shell/collections/document-history.module.css +46 -0
- package/src/admin-shell/collections/document-history.tsx +156 -0
- package/src/admin-shell/collections/history.module.css +6 -0
- package/src/admin-shell/collections/history.tsx +331 -281
- package/src/routes/create-collection-history-route.tsx +25 -3
- package/src/server-fns/admin-account/change-password.ts +1 -1
- package/src/server-fns/admin-account/get.ts +1 -1
- package/src/server-fns/admin-account/update.ts +1 -1
- package/src/server-fns/admin-permissions/get-role-abilities.ts +1 -1
- package/src/server-fns/admin-permissions/set-role-abilities.ts +1 -1
- package/src/server-fns/admin-permissions/who-has.ts +1 -1
- package/src/server-fns/admin-roles/create.ts +1 -1
- package/src/server-fns/admin-roles/delete.ts +1 -1
- package/src/server-fns/admin-roles/get.ts +1 -1
- package/src/server-fns/admin-roles/reorder.ts +1 -1
- package/src/server-fns/admin-roles/update.ts +1 -1
- package/src/server-fns/admin-users/create.ts +1 -1
- package/src/server-fns/admin-users/delete.ts +1 -1
- package/src/server-fns/admin-users/disable.ts +1 -1
- package/src/server-fns/admin-users/enable.ts +1 -1
- package/src/server-fns/admin-users/get-user-roles.ts +1 -1
- package/src/server-fns/admin-users/get.ts +1 -1
- package/src/server-fns/admin-users/list.ts +1 -1
- package/src/server-fns/admin-users/set-password.ts +1 -1
- package/src/server-fns/admin-users/set-user-roles.ts +1 -1
- package/src/server-fns/admin-users/update.ts +1 -1
- package/src/server-fns/ai/execute.ts +1 -1
- package/src/server-fns/auth/sign-in.ts +1 -1
- package/src/server-fns/collections/audit.ts +95 -0
- package/src/server-fns/collections/copy-to-locale.ts +1 -1
- package/src/server-fns/collections/create.ts +1 -1
- package/src/server-fns/collections/delete-locale.ts +1 -1
- package/src/server-fns/collections/delete.ts +1 -1
- package/src/server-fns/collections/duplicate.ts +1 -1
- package/src/server-fns/collections/get.ts +2 -2
- package/src/server-fns/collections/history.ts +1 -1
- package/src/server-fns/collections/index.ts +1 -0
- package/src/server-fns/collections/list.ts +1 -1
- package/src/server-fns/collections/reorder.ts +1 -1
- package/src/server-fns/collections/restore-version.ts +1 -1
- package/src/server-fns/collections/stats.ts +1 -1
- package/src/server-fns/collections/status.ts +2 -2
- package/src/server-fns/collections/update.ts +2 -2
- package/src/server-fns/collections/upload.ts +1 -1
- package/src/server-fns/i18n/set-locale.ts +1 -1
|
@@ -4,7 +4,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
4
4
|
import { bylineCore } from "../../integrations/byline-core.js";
|
|
5
5
|
const setAdminUserPassword = createServerFn({
|
|
6
6
|
method: 'POST'
|
|
7
|
-
}).
|
|
7
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
8
8
|
const context = await getAdminRequestContext();
|
|
9
9
|
return setAdminUserPasswordCommand(context, data, {
|
|
10
10
|
store: bylineCore().adminStore
|
|
@@ -4,7 +4,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
4
4
|
import { bylineCore } from "../../integrations/byline-core.js";
|
|
5
5
|
const setUserRoles = createServerFn({
|
|
6
6
|
method: 'POST'
|
|
7
|
-
}).
|
|
7
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
8
8
|
const context = await getAdminRequestContext();
|
|
9
9
|
return setRolesForUserCommand(context, data, {
|
|
10
10
|
store: bylineCore().adminStore
|
|
@@ -4,7 +4,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
4
4
|
import { bylineCore } from "../../integrations/byline-core.js";
|
|
5
5
|
const updateAdminUser = createServerFn({
|
|
6
6
|
method: 'POST'
|
|
7
|
-
}).
|
|
7
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
8
8
|
const context = await getAdminRequestContext();
|
|
9
9
|
return updateAdminUserCommand(context, data, {
|
|
10
10
|
store: bylineCore().adminStore
|
|
@@ -3,7 +3,7 @@ import { executeInstruction, executeInstructionStreaming } from "@byline/ai/serv
|
|
|
3
3
|
import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
4
4
|
const executeAiInstruction = createServerFn({
|
|
5
5
|
method: 'POST'
|
|
6
|
-
}).
|
|
6
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
7
7
|
await getAdminRequestContext();
|
|
8
8
|
if (data.options?.streaming) {
|
|
9
9
|
const streamResult = executeInstructionStreaming(data.params, data.options);
|
|
@@ -6,7 +6,7 @@ import { readAdminLocaleCookie } from "../../i18n/locale-cookie.js";
|
|
|
6
6
|
import { bylineCore } from "../../integrations/byline-core.js";
|
|
7
7
|
const adminSignIn = createServerFn({
|
|
8
8
|
method: 'POST'
|
|
9
|
-
}).
|
|
9
|
+
}).validator((input)=>{
|
|
10
10
|
if ('string' != typeof input?.email || 0 === input.email.length) throw new Error('email is required');
|
|
11
11
|
if ('string' != typeof input?.password || 0 === input.password.length) throw new Error('password is required');
|
|
12
12
|
return {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import { type ActorLabelMap } from './actors.js';
|
|
9
|
+
export interface AuditLogSearchParams {
|
|
10
|
+
page?: number;
|
|
11
|
+
page_size?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Audit entry as it crosses the server-fn boundary. `occurredAt` is an ISO
|
|
15
|
+
* string (Date doesn't survive serialization) and `before` / `after` are
|
|
16
|
+
* narrowed from the storage layer's `unknown` jsonb to the concrete shapes the
|
|
17
|
+
* shipped actions actually carry (path/status strings, the available-locales
|
|
18
|
+
* array, or null for the deletion event) — `unknown` is not a serializable
|
|
19
|
+
* type the TanStack server-fn validator accepts.
|
|
20
|
+
*/
|
|
21
|
+
export interface AuditLogEntryDto {
|
|
22
|
+
id: string;
|
|
23
|
+
documentId: string | null;
|
|
24
|
+
collectionId: string | null;
|
|
25
|
+
actorId: string | null;
|
|
26
|
+
actorRealm: string;
|
|
27
|
+
action: string;
|
|
28
|
+
field: string | null;
|
|
29
|
+
before: string | string[] | null;
|
|
30
|
+
after: string | string[] | null;
|
|
31
|
+
occurredAt: string;
|
|
32
|
+
}
|
|
33
|
+
export declare const getCollectionDocumentAuditLog: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
|
|
34
|
+
collection: string;
|
|
35
|
+
id: string;
|
|
36
|
+
params?: AuditLogSearchParams;
|
|
37
|
+
}) => {
|
|
38
|
+
collection: string;
|
|
39
|
+
id: string;
|
|
40
|
+
params?: AuditLogSearchParams;
|
|
41
|
+
}, Promise<{
|
|
42
|
+
entries: AuditLogEntryDto[];
|
|
43
|
+
meta: {
|
|
44
|
+
total: number;
|
|
45
|
+
page: number;
|
|
46
|
+
pageSize: number;
|
|
47
|
+
totalPages: number;
|
|
48
|
+
};
|
|
49
|
+
actors: ActorLabelMap;
|
|
50
|
+
}>>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createServerFn } from "@tanstack/react-start";
|
|
2
|
+
import { ERR_NOT_FOUND, getLogger } from "@byline/core";
|
|
3
|
+
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
4
|
+
import { getAdminBylineClient } from "../../integrations/byline-client.js";
|
|
5
|
+
import { resolveActorLabels } from "./actors.js";
|
|
6
|
+
const getCollectionDocumentAuditLog = createServerFn({
|
|
7
|
+
method: 'GET'
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
9
|
+
const { collection: path, id, params } = data;
|
|
10
|
+
const config = await ensureCollection(path);
|
|
11
|
+
if (!config) throw ERR_NOT_FOUND({
|
|
12
|
+
message: 'Collection not found',
|
|
13
|
+
details: {
|
|
14
|
+
collectionPath: path
|
|
15
|
+
}
|
|
16
|
+
}).log(getLogger());
|
|
17
|
+
const result = await getAdminBylineClient().collection(path).auditLog(id, {
|
|
18
|
+
page: params?.page,
|
|
19
|
+
pageSize: params?.page_size
|
|
20
|
+
});
|
|
21
|
+
const actors = await resolveActorLabels(result.entries.map((e)=>e.actorId));
|
|
22
|
+
const entries = result.entries.map((e)=>({
|
|
23
|
+
id: e.id,
|
|
24
|
+
documentId: e.documentId,
|
|
25
|
+
collectionId: e.collectionId,
|
|
26
|
+
actorId: e.actorId,
|
|
27
|
+
actorRealm: e.actorRealm,
|
|
28
|
+
action: e.action,
|
|
29
|
+
field: e.field,
|
|
30
|
+
before: e.before,
|
|
31
|
+
after: e.after,
|
|
32
|
+
occurredAt: e.occurredAt instanceof Date ? e.occurredAt.toISOString() : String(e.occurredAt)
|
|
33
|
+
}));
|
|
34
|
+
return {
|
|
35
|
+
entries,
|
|
36
|
+
meta: result.meta,
|
|
37
|
+
actors
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
export { getCollectionDocumentAuditLog };
|
|
@@ -5,7 +5,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
5
5
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
6
6
|
const copyDocumentToLocale = createServerFn({
|
|
7
7
|
method: 'POST'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
9
9
|
const { collection: path, id, sourceLocale, targetLocale, overwrite } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -5,7 +5,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
5
5
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
6
6
|
const createCollectionDocument = createServerFn({
|
|
7
7
|
method: 'POST'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
9
9
|
const { collection: path, data: documentData, locale, path: explicitPath, availableLocales } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -5,7 +5,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
5
5
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
6
6
|
const deleteDocumentLocale = createServerFn({
|
|
7
7
|
method: 'POST'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
9
9
|
const { collection: path, id, locale } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -5,7 +5,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
5
5
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
6
6
|
const delete_deleteDocument = createServerFn({
|
|
7
7
|
method: 'POST'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
9
9
|
const { collection: path, id } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -5,7 +5,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
5
5
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
6
6
|
const duplicateCollectionDocument = createServerFn({
|
|
7
7
|
method: 'POST'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
9
9
|
const { collection: path, id: sourceDocumentId } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -5,7 +5,7 @@ import { getAdminBylineClient } from "../../integrations/byline-client.js";
|
|
|
5
5
|
import { serialise } from "./utils.js";
|
|
6
6
|
const getDocumentFn = createServerFn({
|
|
7
7
|
method: 'GET'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
9
9
|
const { collection: path, id, locale, depth, populateRelations } = data;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -88,7 +88,7 @@ const getDocumentFn = createServerFn({
|
|
|
88
88
|
});
|
|
89
89
|
const getDocumentByVersionFn = createServerFn({
|
|
90
90
|
method: 'GET'
|
|
91
|
-
}).
|
|
91
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
92
92
|
const { collection: path, versionId, locale } = data;
|
|
93
93
|
const resolvedLocale = locale ?? 'all';
|
|
94
94
|
const logger = getLogger();
|
|
@@ -6,7 +6,7 @@ import { resolveActorLabels } from "./actors.js";
|
|
|
6
6
|
import { serialise } from "./utils.js";
|
|
7
7
|
const getCollectionDocumentHistory = createServerFn({
|
|
8
8
|
method: 'GET'
|
|
9
|
-
}).
|
|
9
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
10
10
|
const { collection: path, id, params } = data;
|
|
11
11
|
const config = await ensureCollection(path);
|
|
12
12
|
if (!config) throw ERR_NOT_FOUND({
|
|
@@ -5,7 +5,7 @@ import { getAdminBylineClient } from "../../integrations/byline-client.js";
|
|
|
5
5
|
import { serialise } from "./utils.js";
|
|
6
6
|
const getCollectionDocuments = createServerFn({
|
|
7
7
|
method: 'GET'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
9
9
|
const { collection: path, params } = data;
|
|
10
10
|
const config = await ensureCollection(path);
|
|
11
11
|
if (!config) throw ERR_NOT_FOUND({
|
|
@@ -4,7 +4,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
4
4
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
5
5
|
const reorderCollectionDocument = createServerFn({
|
|
6
6
|
method: 'POST'
|
|
7
|
-
}).
|
|
7
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
8
8
|
const { collection: path, documentId, beforeDocumentId, afterDocumentId } = input;
|
|
9
9
|
const logger = getLogger();
|
|
10
10
|
const config = await ensureCollection(path);
|
|
@@ -5,7 +5,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
5
5
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
6
6
|
const restore_version_restoreDocumentVersion = createServerFn({
|
|
7
7
|
method: 'POST'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
9
9
|
const { collection: path, id, versionId } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -3,7 +3,7 @@ import { ensureCollection } from "../../integrations/api-utils.js";
|
|
|
3
3
|
import { getAdminBylineClient } from "../../integrations/byline-client.js";
|
|
4
4
|
const getCollectionStatsFn = createServerFn({
|
|
5
5
|
method: 'GET'
|
|
6
|
-
}).
|
|
6
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
7
7
|
const config = await ensureCollection(data.collection);
|
|
8
8
|
if (!config) return {
|
|
9
9
|
stats: []
|
|
@@ -5,7 +5,7 @@ import { getAdminRequestContext } from "../../auth/auth-context.js";
|
|
|
5
5
|
import { ensureCollection } from "../../integrations/api-utils.js";
|
|
6
6
|
const updateDocumentStatus = createServerFn({
|
|
7
7
|
method: 'POST'
|
|
8
|
-
}).
|
|
8
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
9
9
|
const { collection: path, id, status: nextStatus } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -39,7 +39,7 @@ const updateDocumentStatus = createServerFn({
|
|
|
39
39
|
});
|
|
40
40
|
const status_unpublishDocument = createServerFn({
|
|
41
41
|
method: 'POST'
|
|
42
|
-
}).
|
|
42
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
43
43
|
const { collection: path, id } = input;
|
|
44
44
|
const logger = getLogger();
|
|
45
45
|
const config = await ensureCollection(path);
|
|
@@ -5,7 +5,7 @@ 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
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
9
9
|
const { collection: path, id, patches, versionId, locale } = input;
|
|
10
10
|
const logger = getLogger();
|
|
11
11
|
const config = await ensureCollection(path);
|
|
@@ -39,7 +39,7 @@ const updateCollectionDocumentWithPatches = createServerFn({
|
|
|
39
39
|
});
|
|
40
40
|
const updateCollectionDocumentSystemFields = createServerFn({
|
|
41
41
|
method: 'POST'
|
|
42
|
-
}).
|
|
42
|
+
}).validator((input)=>input).handler(async ({ data: input })=>{
|
|
43
43
|
const { collection: path, id, locale, path: explicitPath, availableLocales } = input;
|
|
44
44
|
const logger = getLogger();
|
|
45
45
|
const config = await ensureCollection(path);
|
|
@@ -56,7 +56,7 @@ function resolveUploadFieldName(definition, collectionPath, requested) {
|
|
|
56
56
|
}
|
|
57
57
|
const uploadCollectionField = createServerFn({
|
|
58
58
|
method: 'POST'
|
|
59
|
-
}).
|
|
59
|
+
}).validator(parseUploadFormData).handler(async ({ data })=>{
|
|
60
60
|
const { collectionPath, shouldCreateDocument, fieldName, file, fields } = data;
|
|
61
61
|
const logger = getLogger();
|
|
62
62
|
return withLogContext({
|
|
@@ -6,7 +6,7 @@ import { clearAdminLocaleCookie, setAdminLocaleCookie } from "../../i18n/locale-
|
|
|
6
6
|
import { bylineCore } from "../../integrations/byline-core.js";
|
|
7
7
|
const setInterfaceLocaleFn = createServerFn({
|
|
8
8
|
method: 'POST'
|
|
9
|
-
}).
|
|
9
|
+
}).validator((input)=>input).handler(async ({ data })=>{
|
|
10
10
|
const core = bylineCore();
|
|
11
11
|
const locales = core.config.i18n.interface.locales;
|
|
12
12
|
if (null != data.locale && !locales.includes(data.locale)) throw new Error(`[setInterfaceLocaleFn] locale '${data.locale}' is not in i18n.interface.locales [${locales.join(', ')}].`);
|
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.10.1",
|
|
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/
|
|
120
|
-
"@byline/
|
|
121
|
-
"@byline/
|
|
122
|
-
"@byline/client": "3.
|
|
123
|
-
"@byline/
|
|
124
|
-
"@byline/
|
|
118
|
+
"@byline/admin": "3.10.1",
|
|
119
|
+
"@byline/ui": "3.10.1",
|
|
120
|
+
"@byline/i18n": "3.10.1",
|
|
121
|
+
"@byline/core": "3.10.1",
|
|
122
|
+
"@byline/client": "3.10.1",
|
|
123
|
+
"@byline/ai": "3.10.1",
|
|
124
|
+
"@byline/auth": "3.10.1"
|
|
125
125
|
},
|
|
126
126
|
"peerDependencies": {
|
|
127
127
|
"@tanstack/react-router": "^1.167.0",
|
|
@@ -133,8 +133,8 @@
|
|
|
133
133
|
"@biomejs/biome": "2.4.15",
|
|
134
134
|
"@rsbuild/plugin-react": "^2.0.0",
|
|
135
135
|
"@rslib/core": "^0.21.5",
|
|
136
|
-
"@tanstack/react-router": "^1.170.
|
|
137
|
-
"@tanstack/react-start": "^1.168.
|
|
136
|
+
"@tanstack/react-router": "^1.170.15",
|
|
137
|
+
"@tanstack/react-start": "^1.168.25",
|
|
138
138
|
"@types/node": "^25.9.1",
|
|
139
139
|
"@types/react": "19.2.15",
|
|
140
140
|
"@types/react-dom": "19.2.3",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentHistoryView — the document-grain audit log tab (docs/AUDIT.md — W3).
|
|
3
|
+
*
|
|
4
|
+
* Override handles:
|
|
5
|
+
* .byline-coll-dochistory-empty — empty-state explanation
|
|
6
|
+
* .byline-coll-dochistory-table-wrap — table container
|
|
7
|
+
* .byline-coll-dochistory-when — timestamp cell
|
|
8
|
+
* .byline-coll-dochistory-change — before → after cell
|
|
9
|
+
* .byline-coll-dochistory-before — pre-change value
|
|
10
|
+
* .byline-coll-dochistory-arrow — muted transition arrow
|
|
11
|
+
* .byline-coll-dochistory-after — post-change value
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
.empty,
|
|
15
|
+
:global(.byline-coll-dochistory-empty) {
|
|
16
|
+
margin: 1.5rem 0;
|
|
17
|
+
color: var(--gray-500);
|
|
18
|
+
font-size: 0.875rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
:is([data-theme="dark"], :global(.dark)) .empty,
|
|
22
|
+
:is([data-theme="dark"], :global(.dark)) :global(.byline-coll-dochistory-empty) {
|
|
23
|
+
color: var(--gray-400);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.tableWrap,
|
|
27
|
+
:global(.byline-coll-dochistory-table-wrap) {
|
|
28
|
+
margin-top: 0.5rem;
|
|
29
|
+
margin-bottom: 0.75rem;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.when,
|
|
33
|
+
:global(.byline-coll-dochistory-when) {
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
font-variant-numeric: tabular-nums;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.change,
|
|
39
|
+
:global(.byline-coll-dochistory-change) {
|
|
40
|
+
font-variant-numeric: tabular-nums;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.arrow,
|
|
44
|
+
:global(.byline-coll-dochistory-arrow) {
|
|
45
|
+
color: var(--gray-400);
|
|
46
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useTranslation } from '@byline/i18n/react'
|
|
10
|
+
import { Container, Section, Table } from '@byline/ui/react'
|
|
11
|
+
import cx from 'classnames'
|
|
12
|
+
|
|
13
|
+
import styles from './document-history.module.css'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* One serialised audit-log entry as it reaches the admin UI. Mirrors
|
|
17
|
+
* `@byline/client`'s `AuditLogEntry` but with `occurredAt` as an ISO string —
|
|
18
|
+
* the value crosses the TanStack server-fn boundary through `serialise()`,
|
|
19
|
+
* which turns Dates into strings (docs/AUDIT.md — Workstream 3).
|
|
20
|
+
*/
|
|
21
|
+
export interface AuditLogEntryView {
|
|
22
|
+
id: string
|
|
23
|
+
documentId: string | null
|
|
24
|
+
collectionId: string | null
|
|
25
|
+
actorId: string | null
|
|
26
|
+
actorRealm: string
|
|
27
|
+
action: string
|
|
28
|
+
field: string | null
|
|
29
|
+
before: unknown
|
|
30
|
+
after: unknown
|
|
31
|
+
occurredAt: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The document-history payload attached to the history loader: the page of
|
|
36
|
+
* audit entries plus the admin-side resolved actor labels (`actors`, keyed by
|
|
37
|
+
* actor id — ids absent from the map belong to deleted users; system/tooling
|
|
38
|
+
* rows carry a NULL actorId).
|
|
39
|
+
*/
|
|
40
|
+
export interface DocumentHistoryData {
|
|
41
|
+
entries: AuditLogEntryView[]
|
|
42
|
+
meta: { total: number; page: number; pageSize: number; totalPages: number }
|
|
43
|
+
actors?: Record<string, { label: string }>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Maps namespaced audit `action` values to their i18n label keys. Unknown
|
|
48
|
+
* actions fall back to the raw value rather than a missing-key warning.
|
|
49
|
+
*/
|
|
50
|
+
const ACTION_KEYS: Record<string, string> = {
|
|
51
|
+
'document.path.changed': 'collections.documentHistory.actionPathChanged',
|
|
52
|
+
'document.locales.changed': 'collections.documentHistory.actionLocalesChanged',
|
|
53
|
+
'document.status.changed': 'collections.documentHistory.actionStatusChanged',
|
|
54
|
+
'document.deleted': 'collections.documentHistory.actionDeleted',
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Render an audit before/after value inline: arrays comma-join, nullish → em-dash. */
|
|
58
|
+
function formatAuditValue(value: unknown): string {
|
|
59
|
+
if (value == null) return '—'
|
|
60
|
+
if (Array.isArray(value)) return value.length > 0 ? value.join(', ') : '—'
|
|
61
|
+
return String(value)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Document-grain audit log for a single document (docs/AUDIT.md — Workstream
|
|
66
|
+
* 3, "Document history" tab): a chronological, newest-first list of the
|
|
67
|
+
* non-versioned changes the version stream does not record — path /
|
|
68
|
+
* available-locales writes, in-place status transitions, and the deletion
|
|
69
|
+
* event. No diff viewer; before/after render inline.
|
|
70
|
+
*/
|
|
71
|
+
export const DocumentHistoryView = ({ data }: { data: DocumentHistoryData }) => {
|
|
72
|
+
const { t } = useTranslation('byline-admin')
|
|
73
|
+
const entries = data?.entries ?? []
|
|
74
|
+
|
|
75
|
+
if (entries.length === 0) {
|
|
76
|
+
return (
|
|
77
|
+
<Section>
|
|
78
|
+
<Container>
|
|
79
|
+
<p className={cx('byline-coll-dochistory-empty', styles.empty)}>
|
|
80
|
+
{t('collections.documentHistory.empty')}
|
|
81
|
+
</p>
|
|
82
|
+
</Container>
|
|
83
|
+
</Section>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<Section>
|
|
89
|
+
<Container>
|
|
90
|
+
<Table.Container className={cx('byline-coll-dochistory-table-wrap', styles.tableWrap)}>
|
|
91
|
+
<Table>
|
|
92
|
+
<Table.Header>
|
|
93
|
+
<Table.Row>
|
|
94
|
+
<Table.HeadingCell scope="col">
|
|
95
|
+
{t('collections.documentHistory.colWhen')}
|
|
96
|
+
</Table.HeadingCell>
|
|
97
|
+
<Table.HeadingCell scope="col">
|
|
98
|
+
{t('collections.documentHistory.colAction')}
|
|
99
|
+
</Table.HeadingCell>
|
|
100
|
+
<Table.HeadingCell scope="col">
|
|
101
|
+
{t('collections.documentHistory.colActor')}
|
|
102
|
+
</Table.HeadingCell>
|
|
103
|
+
<Table.HeadingCell scope="col">
|
|
104
|
+
{t('collections.documentHistory.colChange')}
|
|
105
|
+
</Table.HeadingCell>
|
|
106
|
+
</Table.Row>
|
|
107
|
+
</Table.Header>
|
|
108
|
+
<Table.Body>
|
|
109
|
+
{entries.map((entry) => {
|
|
110
|
+
const actionKey = ACTION_KEYS[entry.action]
|
|
111
|
+
const actionLabel = actionKey ? t(actionKey) : entry.action
|
|
112
|
+
// System/tooling write (NULL actor or 'system' realm) → the
|
|
113
|
+
// system label; an unresolved id is a deleted user; otherwise
|
|
114
|
+
// the admin-resolved label.
|
|
115
|
+
const actorLabel =
|
|
116
|
+
entry.actorId == null || entry.actorRealm === 'system'
|
|
117
|
+
? t('collections.documentHistory.systemActor')
|
|
118
|
+
: (data.actors?.[entry.actorId]?.label ??
|
|
119
|
+
t('collections.history.audit.formerUser'))
|
|
120
|
+
// The deletion event carries no before/after; everything else
|
|
121
|
+
// renders "before → after".
|
|
122
|
+
const hasChange = entry.before != null || entry.after != null
|
|
123
|
+
return (
|
|
124
|
+
<Table.Row key={entry.id}>
|
|
125
|
+
<Table.Cell className={cx('byline-coll-dochistory-when', styles.when)}>
|
|
126
|
+
{new Date(entry.occurredAt).toLocaleString()}
|
|
127
|
+
</Table.Cell>
|
|
128
|
+
<Table.Cell>{actionLabel}</Table.Cell>
|
|
129
|
+
<Table.Cell>{actorLabel}</Table.Cell>
|
|
130
|
+
<Table.Cell className={cx('byline-coll-dochistory-change', styles.change)}>
|
|
131
|
+
{hasChange ? (
|
|
132
|
+
<>
|
|
133
|
+
<span className={cx('byline-coll-dochistory-before', styles.before)}>
|
|
134
|
+
{formatAuditValue(entry.before)}
|
|
135
|
+
</span>
|
|
136
|
+
<span className={cx('byline-coll-dochistory-arrow', styles.arrow)}>
|
|
137
|
+
{' → '}
|
|
138
|
+
</span>
|
|
139
|
+
<span className={cx('byline-coll-dochistory-after', styles.after)}>
|
|
140
|
+
{formatAuditValue(entry.after)}
|
|
141
|
+
</span>
|
|
142
|
+
</>
|
|
143
|
+
) : (
|
|
144
|
+
'—'
|
|
145
|
+
)}
|
|
146
|
+
</Table.Cell>
|
|
147
|
+
</Table.Row>
|
|
148
|
+
)
|
|
149
|
+
})}
|
|
150
|
+
</Table.Body>
|
|
151
|
+
</Table>
|
|
152
|
+
</Table.Container>
|
|
153
|
+
</Container>
|
|
154
|
+
</Section>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
@@ -67,6 +67,12 @@
|
|
|
67
67
|
background-color: var(--canvas-700);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/* Sub-view tab bar (Content versions / Document history — docs/AUDIT.md W3). */
|
|
71
|
+
.tabs,
|
|
72
|
+
:global(.byline-coll-history-tabs) {
|
|
73
|
+
margin-top: 0.25rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
70
76
|
.options,
|
|
71
77
|
:global(.byline-coll-history-options) {
|
|
72
78
|
display: flex;
|