@anthusai/papyrus 5.43.0-next.43 → 5.43.0-next.45
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.
|
@@ -1431,7 +1431,9 @@ async function appendMessageToThread(thread: MessageThreadRecord, build: (sequen
|
|
|
1431
1431
|
list: () => listMessagesByThreadId(threadId, 1000),
|
|
1432
1432
|
create: (sequenceNumber) => {
|
|
1433
1433
|
now = new Date().toISOString();
|
|
1434
|
-
|
|
1434
|
+
// `createdAt` is part of the composite sort key of messagesByResponseTargetStatusCreatedAt, so AppSync refuses a Message that
|
|
1435
|
+
// sets it without `responseStatus`. A person's message waits on no responder: COMPLETED, as the Python message contract writes.
|
|
1436
|
+
built = { responseStatus: "COMPLETED", ...build(sequenceNumber, now) };
|
|
1435
1437
|
return runGraphql<{ createMessage?: MessageRecord | null }>(CREATE_MESSAGE_MUTATION, { input: built });
|
|
1436
1438
|
},
|
|
1437
1439
|
});
|
|
@@ -1905,10 +1907,17 @@ async function runGraphql<T extends Record<string, unknown>>(
|
|
|
1905
1907
|
const client = generateClient<Schema>() as unknown as {
|
|
1906
1908
|
graphql: (options: Record<string, unknown>) => Promise<{ data?: T | null; errors?: unknown[] | null }>;
|
|
1907
1909
|
};
|
|
1910
|
+
// The Amplify client rejects with the raw `{ data, errors }` response when the API returns errors; turn that into an
|
|
1911
|
+
// Error carrying the API's own words, so a refusal is said in words instead of as an unknown failure.
|
|
1908
1912
|
const response = await client.graphql({
|
|
1909
1913
|
query,
|
|
1910
1914
|
variables,
|
|
1911
1915
|
authMode: USER_POOL_AUTH_MODE,
|
|
1916
|
+
}).catch((failure: unknown) => {
|
|
1917
|
+
if (failure && typeof failure === "object" && Array.isArray((failure as { errors?: unknown }).errors)) {
|
|
1918
|
+
assertNoGraphQLErrors((failure as { errors: unknown[] }).errors);
|
|
1919
|
+
}
|
|
1920
|
+
throw failure;
|
|
1912
1921
|
});
|
|
1913
1922
|
assertNoGraphQLErrors(response.errors);
|
|
1914
1923
|
return (response.data ?? {}) as T;
|
|
@@ -4,7 +4,7 @@ import { generateClient } from "aws-amplify/data";
|
|
|
4
4
|
import type { Schema } from "../amplify/data/resource";
|
|
5
5
|
import { isLocalPreviewEnabled } from "../lib/local-preview";
|
|
6
6
|
import { createLocalPreviewReportingTrail, createLocalPreviewStoriesForReference } from "../lib/local-preview-seed";
|
|
7
|
-
import { EMPTY_STORY_REPORTING_TRAIL, referencesByRole, siteNameOf, type ReferenceStory, type StoryReportingTrail, type TrailAssignment, type TrailAttachment, type TrailReference, type TrailThread, type TrailVersion } from "../lib/story-reporting-trail";
|
|
7
|
+
import { EMPTY_STORY_REPORTING_TRAIL, referencesByRole, siteNameOf, stageMovesOf, type ReferenceStory, type StoryReportingTrail, type TrailAssignment, type TrailAttachment, type TrailReference, type TrailThread, type TrailVersion } from "../lib/story-reporting-trail";
|
|
8
8
|
import { configureAmplifyClient } from "./amplify-client-provider";
|
|
9
9
|
|
|
10
10
|
type GraphqlResponse = { data?: Record<string, { items?: Record<string, unknown>[] | null; nextToken?: string | null } | null> | null; errors?: { message?: string }[] | null };
|
|
@@ -89,7 +89,7 @@ export async function loadStoryReportingTrail(lineageId: string, itemId: string,
|
|
|
89
89
|
configureAmplifyClient();
|
|
90
90
|
const client = generateClient<Schema>() as unknown as GraphqlClient;
|
|
91
91
|
const [versionRows, assignmentRows, attachmentRows, relationRows] = await Promise.all([
|
|
92
|
-
listAll(client, "listItemsByLineageAndVersion", "id versionNumber versionState status stage headline title changeReason versionCreatedBy versionCreatedAt updatedAt", ", $lineageId: ID!", ", lineageId: $lineageId", { lineageId }).catch(() => []),
|
|
92
|
+
listAll(client, "listItemsByLineageAndVersion", "id versionNumber versionState status stage headline title changeReason versionCreatedBy versionCreatedAt updatedAt metadata", ", $lineageId: ID!", ", lineageId: $lineageId", { lineageId }).catch(() => []),
|
|
93
93
|
listAll(client, "listAssignmentsByItemLineageAndCreatedAt", "id title assignmentTypeKey status assigneeKey summary createdAt", ", $itemLineageId: ID!", ", itemLineageId: $itemLineageId", { itemLineageId: lineageId }).catch(() => []),
|
|
94
94
|
listAll(client, "listModelAttachmentsByOwnerRoleAndSortKey", "id role filename mediaType byteSize", ", $ownerId: ID!", ", ownerId: $ownerId", { ownerId: itemId }).catch(() => []),
|
|
95
95
|
listAll(client, "listSemanticRelations", "id predicate subjectKind subjectLineageId objectKind objectId objectLineageId metadata", ", $filter: ModelSemanticRelationFilterInput", ", filter: $filter", { filter: { or: [{ subjectLineageId: { eq: lineageId } }, { objectLineageId: { eq: lineageId } }] } }).catch(() => []),
|
|
@@ -124,5 +124,6 @@ export async function loadStoryReportingTrail(lineageId: string, itemId: string,
|
|
|
124
124
|
};
|
|
125
125
|
})));
|
|
126
126
|
const attachments: TrailAttachment[] = attachmentRows.map(row => ({ id: String(row.id), role: text(row.role), filename: text(row.filename), mediaType: text(row.mediaType), byteSize: typeof row.byteSize === "number" ? row.byteSize : null }));
|
|
127
|
-
|
|
127
|
+
const latestRow = [...versionRows].sort((left, right) => Number(right.versionNumber ?? 0) - Number(left.versionNumber ?? 0))[0];
|
|
128
|
+
return { ...EMPTY_STORY_REPORTING_TRAIL, versions, assignments, threads, references, attachments, stageMoves: stageMovesOf(latestRow?.metadata) };
|
|
128
129
|
}
|
|
@@ -91,6 +91,14 @@ export function StoryReportingTrailView({ citedKeys = [], demo = false, focusedR
|
|
|
91
91
|
</li>)}
|
|
92
92
|
</ol>
|
|
93
93
|
</TrailSection>
|
|
94
|
+
{trail.stageMoves.length > 0 && <TrailSection count={trail.stageMoves.length} title="Stage moves">
|
|
95
|
+
<ol className="story-trail-list" data-story-trail-stage-moves>
|
|
96
|
+
{[...trail.stageMoves].reverse().map(move => <li key={`${move.at}-${move.to}`}>
|
|
97
|
+
<div className="story-trail-row"><strong>{move.from ?? "start"} → {move.to}</strong>{move.by && <span className="story-trail-chip">{move.by}</span>}<span className="story-trail-meta">{formatTimestamp(move.at)}</span></div>
|
|
98
|
+
{move.reason && <p className="story-trail-meta">{move.reason}</p>}
|
|
99
|
+
</li>)}
|
|
100
|
+
</ol>
|
|
101
|
+
</TrailSection>}
|
|
94
102
|
<TrailSection count={trail.versions.length} title="Draft versions">
|
|
95
103
|
<ol className="story-trail-list">
|
|
96
104
|
{trail.versions.map((version, versionIndex) => <li key={version.id}>
|
|
@@ -17,6 +17,15 @@ export type TrailVersion = {
|
|
|
17
17
|
updatedAt: string | null;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
/** One stage move of the story, read from the latest Item version's `metadata.stageMoves` (not from Messages). */
|
|
21
|
+
export type TrailStageMove = {
|
|
22
|
+
at: string;
|
|
23
|
+
from: string | null;
|
|
24
|
+
to: string;
|
|
25
|
+
by: string | null;
|
|
26
|
+
reason: string | null;
|
|
27
|
+
};
|
|
28
|
+
|
|
20
29
|
export type TrailAssignmentEvent = {
|
|
21
30
|
id: string;
|
|
22
31
|
eventType: string;
|
|
@@ -89,12 +98,29 @@ export type StoryReportingTrail = {
|
|
|
89
98
|
threads: TrailThread[];
|
|
90
99
|
references: TrailReference[];
|
|
91
100
|
attachments: TrailAttachment[];
|
|
101
|
+
stageMoves: TrailStageMove[];
|
|
92
102
|
};
|
|
93
103
|
|
|
94
|
-
export const EMPTY_STORY_REPORTING_TRAIL: StoryReportingTrail = { versions: [], assignments: [], threads: [], references: [], attachments: [] };
|
|
104
|
+
export const EMPTY_STORY_REPORTING_TRAIL: StoryReportingTrail = { versions: [], assignments: [], threads: [], references: [], attachments: [], stageMoves: [] };
|
|
105
|
+
|
|
106
|
+
/** The stage moves recorded on an Item version's metadata, oldest first. Anything that is not a well-formed move is skipped. */
|
|
107
|
+
export function stageMovesOf(metadata: unknown): TrailStageMove[] {
|
|
108
|
+
let parsed: unknown = metadata;
|
|
109
|
+
if (typeof metadata === "string") {
|
|
110
|
+
try { parsed = JSON.parse(metadata); } catch { return []; }
|
|
111
|
+
}
|
|
112
|
+
const moves = typeof parsed === "object" && parsed ? (parsed as Record<string, unknown>).stageMoves : null;
|
|
113
|
+
if (!Array.isArray(moves)) return [];
|
|
114
|
+
return moves.flatMap(entry => {
|
|
115
|
+
if (typeof entry !== "object" || !entry) return [];
|
|
116
|
+
const move = entry as Record<string, unknown>;
|
|
117
|
+
if (typeof move.at !== "string" || typeof move.to !== "string") return [];
|
|
118
|
+
return [{ at: move.at, from: typeof move.from === "string" ? move.from : null, to: move.to, by: typeof move.by === "string" ? move.by : null, reason: typeof move.reason === "string" ? move.reason : null }];
|
|
119
|
+
});
|
|
120
|
+
}
|
|
95
121
|
|
|
96
122
|
export function storyReportingTrailIsEmpty(trail: StoryReportingTrail): boolean {
|
|
97
|
-
return trail.assignments.length === 0 && trail.threads.length === 0 && trail.references.length === 0 && trail.attachments.length === 0 && trail.versions.length <= 1;
|
|
123
|
+
return trail.assignments.length === 0 && trail.threads.length === 0 && trail.stageMoves.length === 0 && trail.references.length === 0 && trail.attachments.length === 0 && trail.versions.length <= 1;
|
|
98
124
|
}
|
|
99
125
|
|
|
100
126
|
export type StoryFeedEntry =
|
package/package.json
CHANGED
package/routes.manifest.json
CHANGED