mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 14:54:05 +00:00
fix(workboard): tighten controls and track card events
This commit is contained in:
@@ -48,10 +48,16 @@ Each card stores:
|
||||
- optional agent id
|
||||
- optional linked session, run, task, or source URL
|
||||
- optional execution metadata for a Codex or Claude session started from the card
|
||||
- recent card events such as created, moved, linked, or agent-updated changes
|
||||
|
||||
Cards are stored in the plugin's Gateway state. They are local to the Gateway
|
||||
state directory and move with the rest of that Gateway's OpenClaw state.
|
||||
|
||||
Workboard keeps a compact per-card event history so operators can see how a
|
||||
card moved through the board without opening the linked session. The event trail
|
||||
is intentionally local metadata; it does not replace session transcripts or
|
||||
GitHub issue history.
|
||||
|
||||
## Card executions
|
||||
|
||||
Unlinked cards can start work from the card. Start uses the Gateway's configured
|
||||
@@ -74,6 +80,9 @@ Cards can be linked to existing dashboard sessions or to the session created
|
||||
when you start work from a card. Linked cards show the session lifecycle inline:
|
||||
running, linked idle, done, failed, or missing.
|
||||
|
||||
If the linked session is missing, the card stays linked for context and still
|
||||
offers start controls so you can restart work into a fresh dashboard session.
|
||||
|
||||
You can also capture an existing dashboard session from the Sessions tab with
|
||||
Add to Workboard. The card is linked to that session, uses the session label or
|
||||
recent user prompt as the title, and seeds notes from the recent user prompt plus
|
||||
|
||||
@@ -34,6 +34,15 @@ describe("WorkboardStore", () => {
|
||||
expect((await store.list()).map((card) => card.id)).toEqual([todo.id, review.id]);
|
||||
expect(review.labels).toEqual(["release", "docs"]);
|
||||
expect(review.priority).toBe("high");
|
||||
expect(review.events?.[0]).toMatchObject({ kind: "created", toStatus: "review" });
|
||||
});
|
||||
|
||||
it("preserves explicit zero positions", async () => {
|
||||
const store = new WorkboardStore(createMemoryStore());
|
||||
|
||||
const card = await store.create({ title: "Top card", status: "todo", position: 0 });
|
||||
|
||||
expect(card.position).toBe(0);
|
||||
});
|
||||
|
||||
it("keeps initial session, run, and task links when creating cards", async () => {
|
||||
@@ -77,6 +86,11 @@ describe("WorkboardStore", () => {
|
||||
expect(running.status).toBe("running");
|
||||
expect(running.position).toBe(500);
|
||||
expect(running.startedAt).toBeGreaterThanOrEqual(card.createdAt);
|
||||
expect(running.events?.at(-1)).toMatchObject({
|
||||
kind: "moved",
|
||||
fromStatus: "todo",
|
||||
toStatus: "running",
|
||||
});
|
||||
|
||||
const done = await store.update(card.id, { status: "done" });
|
||||
expect(done.completedAt).toBeGreaterThanOrEqual(done.startedAt ?? 0);
|
||||
@@ -103,6 +117,10 @@ describe("WorkboardStore", () => {
|
||||
const relinked = await store.update(card.id, { sessionKey: "agent:main:dashboard:2" });
|
||||
expect(relinked.sessionKey).toBe("agent:main:dashboard:2");
|
||||
expect(relinked.execution?.sessionKey).toBe("agent:main:dashboard:2");
|
||||
expect(relinked.events?.at(-1)).toMatchObject({
|
||||
kind: "linked",
|
||||
sessionKey: "agent:main:dashboard:2",
|
||||
});
|
||||
|
||||
const unlinked = await store.update(card.id, { sessionKey: "" });
|
||||
expect(unlinked.sessionKey).toBeUndefined();
|
||||
|
||||
@@ -3,9 +3,12 @@ import {
|
||||
WORKBOARD_EXECUTION_ENGINES,
|
||||
WORKBOARD_EXECUTION_MODES,
|
||||
WORKBOARD_EXECUTION_STATUSES,
|
||||
WORKBOARD_EVENT_KINDS,
|
||||
WORKBOARD_PRIORITIES,
|
||||
WORKBOARD_STATUSES,
|
||||
type WorkboardCard,
|
||||
type WorkboardEvent,
|
||||
type WorkboardEventKind,
|
||||
type WorkboardExecution,
|
||||
type WorkboardExecutionEngine,
|
||||
type WorkboardExecutionMode,
|
||||
@@ -16,6 +19,7 @@ import {
|
||||
|
||||
const POSITION_STEP = 1000;
|
||||
const MAX_CARDS = 2000;
|
||||
const MAX_CARD_EVENTS = 50;
|
||||
|
||||
export type PersistedWorkboardCard = {
|
||||
version: 1;
|
||||
@@ -170,6 +174,52 @@ function normalizeTimestamp(value: unknown, fallback: number): number {
|
||||
: fallback;
|
||||
}
|
||||
|
||||
function normalizeEvent(value: unknown): WorkboardEvent | null {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
return null;
|
||||
}
|
||||
const record = value as Record<string, unknown>;
|
||||
const id = normalizeOptionalString(record.id);
|
||||
const kind = WORKBOARD_EVENT_KINDS.includes(record.kind as WorkboardEventKind)
|
||||
? (record.kind as WorkboardEventKind)
|
||||
: null;
|
||||
const at = normalizeTimestamp(record.at, 0);
|
||||
if (!id || !kind || !at) {
|
||||
return null;
|
||||
}
|
||||
const fromStatus =
|
||||
typeof record.fromStatus === "string" &&
|
||||
WORKBOARD_STATUSES.includes(record.fromStatus as WorkboardStatus)
|
||||
? (record.fromStatus as WorkboardStatus)
|
||||
: undefined;
|
||||
const toStatus =
|
||||
typeof record.toStatus === "string" &&
|
||||
WORKBOARD_STATUSES.includes(record.toStatus as WorkboardStatus)
|
||||
? (record.toStatus as WorkboardStatus)
|
||||
: undefined;
|
||||
const sessionKey = normalizeOptionalString(record.sessionKey);
|
||||
const runId = normalizeOptionalString(record.runId);
|
||||
return {
|
||||
id,
|
||||
kind,
|
||||
at,
|
||||
...(fromStatus ? { fromStatus } : {}),
|
||||
...(toStatus ? { toStatus } : {}),
|
||||
...(sessionKey ? { sessionKey } : {}),
|
||||
...(runId ? { runId } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeEvents(value: unknown): WorkboardEvent[] {
|
||||
if (!Array.isArray(value)) {
|
||||
return [];
|
||||
}
|
||||
return value
|
||||
.map(normalizeEvent)
|
||||
.filter((event): event is WorkboardEvent => event !== null)
|
||||
.slice(-MAX_CARD_EVENTS);
|
||||
}
|
||||
|
||||
function normalizeExecution(value: unknown): WorkboardExecution | undefined {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
return undefined;
|
||||
@@ -234,6 +284,60 @@ function compareCards(left: WorkboardCard, right: WorkboardCard): number {
|
||||
return left.createdAt - right.createdAt;
|
||||
}
|
||||
|
||||
function cardSessionKey(card: WorkboardCard): string | undefined {
|
||||
return card.sessionKey ?? card.execution?.sessionKey;
|
||||
}
|
||||
|
||||
function cardRunId(card: WorkboardCard): string | undefined {
|
||||
return card.runId ?? card.execution?.runId;
|
||||
}
|
||||
|
||||
function appendEvent(
|
||||
card: WorkboardCard,
|
||||
event: Omit<WorkboardEvent, "id" | "at">,
|
||||
at = Date.now(),
|
||||
): WorkboardEvent[] {
|
||||
return [
|
||||
...normalizeEvents(card.events),
|
||||
{
|
||||
id: randomUUID(),
|
||||
at,
|
||||
...event,
|
||||
},
|
||||
].slice(-MAX_CARD_EVENTS);
|
||||
}
|
||||
|
||||
function updateEvent(
|
||||
existing: WorkboardCard,
|
||||
next: WorkboardCard,
|
||||
): Omit<WorkboardEvent, "id" | "at"> {
|
||||
if (existing.status !== next.status || existing.position !== next.position) {
|
||||
return {
|
||||
kind: "moved",
|
||||
fromStatus: existing.status,
|
||||
toStatus: next.status,
|
||||
};
|
||||
}
|
||||
if (cardSessionKey(existing) !== cardSessionKey(next)) {
|
||||
return {
|
||||
kind: "linked",
|
||||
...(cardSessionKey(next) ? { sessionKey: cardSessionKey(next) } : {}),
|
||||
};
|
||||
}
|
||||
if (
|
||||
existing.execution?.status !== next.execution?.status ||
|
||||
existing.execution?.engine !== next.execution?.engine ||
|
||||
cardRunId(existing) !== cardRunId(next)
|
||||
) {
|
||||
return {
|
||||
kind: "execution_updated",
|
||||
...(cardSessionKey(next) ? { sessionKey: cardSessionKey(next) } : {}),
|
||||
...(cardRunId(next) ? { runId: cardRunId(next) } : {}),
|
||||
};
|
||||
}
|
||||
return { kind: "edited" };
|
||||
}
|
||||
|
||||
function removeUndefinedCardFields(card: WorkboardCard): WorkboardCard {
|
||||
const next = { ...card };
|
||||
for (const key of [
|
||||
@@ -277,10 +381,13 @@ export class WorkboardStore {
|
||||
const now = Date.now();
|
||||
const status = normalizeStatus(input.status, "todo");
|
||||
const cards = await this.list();
|
||||
const position =
|
||||
normalizePosition(input.position, 0) ||
|
||||
Math.max(0, ...cards.filter((card) => card.status === status).map((card) => card.position)) +
|
||||
POSITION_STEP;
|
||||
const normalizedPosition = normalizePosition(input.position, Number.NaN);
|
||||
const position = Number.isFinite(normalizedPosition)
|
||||
? normalizedPosition
|
||||
: Math.max(
|
||||
0,
|
||||
...cards.filter((card) => card.status === status).map((card) => card.position),
|
||||
) + POSITION_STEP;
|
||||
const notes = normalizeNotes(input.notes);
|
||||
const agentId = normalizeOptionalString(input.agentId);
|
||||
const sessionKey = normalizeOptionalString(input.sessionKey);
|
||||
@@ -297,6 +404,16 @@ export class WorkboardStore {
|
||||
position,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
events: [
|
||||
{
|
||||
id: randomUUID(),
|
||||
kind: "created",
|
||||
at: now,
|
||||
toStatus: status,
|
||||
...(sessionKey ? { sessionKey } : {}),
|
||||
...(runId ? { runId } : {}),
|
||||
},
|
||||
],
|
||||
...(notes ? { notes } : {}),
|
||||
...(agentId ? { agentId } : {}),
|
||||
...(sessionKey ? { sessionKey } : {}),
|
||||
@@ -356,6 +473,7 @@ export class WorkboardStore {
|
||||
...(startedAt ? { startedAt } : {}),
|
||||
...(completedAt ? { completedAt } : {}),
|
||||
});
|
||||
next.events = appendEvent(next, updateEvent(existing, next), now);
|
||||
if (status !== "done") {
|
||||
delete next.completedAt;
|
||||
}
|
||||
|
||||
@@ -17,12 +17,20 @@ export const WORKBOARD_EXECUTION_STATUSES = [
|
||||
"blocked",
|
||||
"done",
|
||||
] as const;
|
||||
export const WORKBOARD_EVENT_KINDS = [
|
||||
"created",
|
||||
"edited",
|
||||
"moved",
|
||||
"linked",
|
||||
"execution_updated",
|
||||
] as const;
|
||||
|
||||
export type WorkboardStatus = (typeof WORKBOARD_STATUSES)[number];
|
||||
export type WorkboardPriority = (typeof WORKBOARD_PRIORITIES)[number];
|
||||
export type WorkboardExecutionEngine = (typeof WORKBOARD_EXECUTION_ENGINES)[number];
|
||||
export type WorkboardExecutionMode = (typeof WORKBOARD_EXECUTION_MODES)[number];
|
||||
export type WorkboardExecutionStatus = (typeof WORKBOARD_EXECUTION_STATUSES)[number];
|
||||
export type WorkboardEventKind = (typeof WORKBOARD_EVENT_KINDS)[number];
|
||||
|
||||
export type WorkboardExecution = {
|
||||
id: string;
|
||||
@@ -37,6 +45,16 @@ export type WorkboardExecution = {
|
||||
updatedAt: number;
|
||||
};
|
||||
|
||||
export type WorkboardEvent = {
|
||||
id: string;
|
||||
kind: WorkboardEventKind;
|
||||
at: number;
|
||||
fromStatus?: WorkboardStatus;
|
||||
toStatus?: WorkboardStatus;
|
||||
sessionKey?: string;
|
||||
runId?: string;
|
||||
};
|
||||
|
||||
export type WorkboardCard = {
|
||||
id: string;
|
||||
title: string;
|
||||
@@ -55,6 +73,7 @@ export type WorkboardCard = {
|
||||
updatedAt: number;
|
||||
startedAt?: number;
|
||||
completedAt?: number;
|
||||
events?: WorkboardEvent[];
|
||||
};
|
||||
|
||||
export type WorkboardListResult = {
|
||||
|
||||
8
ui/src/i18n/.i18n/ar.meta.json
generated
8
ui/src/i18n/.i18n/ar.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:31.545Z",
|
||||
"generatedAt": "2026-05-28T23:49:35.013Z",
|
||||
"locale": "ar",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/de.meta.json
generated
8
ui/src/i18n/.i18n/de.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:21.334Z",
|
||||
"generatedAt": "2026-05-28T23:49:02.619Z",
|
||||
"locale": "de",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/es.meta.json
generated
8
ui/src/i18n/.i18n/es.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:23.802Z",
|
||||
"generatedAt": "2026-05-28T23:49:07.283Z",
|
||||
"locale": "es",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/fa.meta.json
generated
8
ui/src/i18n/.i18n/fa.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:52.280Z",
|
||||
"generatedAt": "2026-05-28T23:51:04.444Z",
|
||||
"locale": "fa",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/fr.meta.json
generated
8
ui/src/i18n/.i18n/fr.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:29.028Z",
|
||||
"generatedAt": "2026-05-28T23:49:27.030Z",
|
||||
"locale": "fr",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/id.meta.json
generated
8
ui/src/i18n/.i18n/id.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:42.075Z",
|
||||
"generatedAt": "2026-05-28T23:50:00.392Z",
|
||||
"locale": "id",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/it.meta.json
generated
8
ui/src/i18n/.i18n/it.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:33.241Z",
|
||||
"generatedAt": "2026-05-28T23:49:40.467Z",
|
||||
"locale": "it",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/ja-JP.meta.json
generated
8
ui/src/i18n/.i18n/ja-JP.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:25.623Z",
|
||||
"generatedAt": "2026-05-28T23:49:14.097Z",
|
||||
"locale": "ja-JP",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/ko.meta.json
generated
8
ui/src/i18n/.i18n/ko.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:27.331Z",
|
||||
"generatedAt": "2026-05-28T23:49:19.581Z",
|
||||
"locale": "ko",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/nl.meta.json
generated
8
ui/src/i18n/.i18n/nl.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:49.875Z",
|
||||
"generatedAt": "2026-05-28T23:50:48.437Z",
|
||||
"locale": "nl",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/pl.meta.json
generated
8
ui/src/i18n/.i18n/pl.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:43.834Z",
|
||||
"generatedAt": "2026-05-28T23:50:12.160Z",
|
||||
"locale": "pl",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/pt-BR.meta.json
generated
8
ui/src/i18n/.i18n/pt-BR.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:18.990Z",
|
||||
"generatedAt": "2026-05-28T23:48:56.314Z",
|
||||
"locale": "pt-BR",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
77
ui/src/i18n/.i18n/raw-copy-baseline.json
generated
77
ui/src/i18n/.i18n/raw-copy-baseline.json
generated
@@ -4655,83 +4655,6 @@
|
||||
"name": "aria-label",
|
||||
"path": "ui/src/ui/views/usage-render-overview.ts",
|
||||
"text": "Remove session filter"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-attribute",
|
||||
"name": "placeholder",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "Card title"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-attribute",
|
||||
"name": "placeholder",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "Notes, acceptance criteria, links"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-attribute",
|
||||
"name": "placeholder",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "Search cards"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-attribute",
|
||||
"name": "title",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "Delete card"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-attribute",
|
||||
"name": "title",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "Open session"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-attribute",
|
||||
"name": "title",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "Start session"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-text",
|
||||
"name": "text",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "All priorities"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-text",
|
||||
"name": "text",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "default agent"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-text",
|
||||
"name": "text",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "Default agent"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-text",
|
||||
"name": "text",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "Drop work here"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"kind": "html-text",
|
||||
"name": "text",
|
||||
"path": "ui/src/ui/views/workboard.ts",
|
||||
"text": "live"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/th.meta.json
generated
8
ui/src/i18n/.i18n/th.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:45.871Z",
|
||||
"generatedAt": "2026-05-28T23:50:26.593Z",
|
||||
"locale": "th",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/tr.meta.json
generated
8
ui/src/i18n/.i18n/tr.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:35.897Z",
|
||||
"generatedAt": "2026-05-28T23:49:47.972Z",
|
||||
"locale": "tr",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/uk.meta.json
generated
8
ui/src/i18n/.i18n/uk.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:39.972Z",
|
||||
"generatedAt": "2026-05-28T23:49:54.214Z",
|
||||
"locale": "uk",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/vi.meta.json
generated
8
ui/src/i18n/.i18n/vi.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:47.804Z",
|
||||
"generatedAt": "2026-05-28T23:50:37.343Z",
|
||||
"locale": "vi",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/zh-CN.meta.json
generated
8
ui/src/i18n/.i18n/zh-CN.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:15.047Z",
|
||||
"generatedAt": "2026-05-28T23:48:43.195Z",
|
||||
"locale": "zh-CN",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
8
ui/src/i18n/.i18n/zh-TW.meta.json
generated
8
ui/src/i18n/.i18n/zh-TW.meta.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-05-28T18:48:17.187Z",
|
||||
"generatedAt": "2026-05-28T23:48:49.571Z",
|
||||
"locale": "zh-TW",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "7c867296be27a09ab0e35f76d2518f479e24ab667179c5b3fabf83d6c57f3ef9",
|
||||
"totalKeys": 1158,
|
||||
"translatedKeys": 1158,
|
||||
"sourceHash": "b966847cbbaca64097b1e105dcc26ad803434cfb2d3b39cae3edc2be3874cfda",
|
||||
"totalKeys": 1238,
|
||||
"translatedKeys": 1238,
|
||||
"workflow": 1
|
||||
}
|
||||
|
||||
26
ui/src/i18n/locales/ar.ts
generated
26
ui/src/i18n/locales/ar.ts
generated
@@ -492,6 +492,18 @@ export const ar: TranslationMap = {
|
||||
noLinkedSession: "لا توجد جلسة مرتبطة",
|
||||
stopSession: "إيقاف الجلسة",
|
||||
editCard: "تعديل البطاقة",
|
||||
editCardHelp: "حدّث بيانات تعريف قائمة الانتظار وتسليم الجلسة.",
|
||||
newCard: "بطاقة جديدة",
|
||||
newCardHelp: "أضف العمل إلى قائمة الانتظار لجلسة وكيل.",
|
||||
deleteCard: "حذف البطاقة",
|
||||
openSession: "فتح الجلسة",
|
||||
openLinkedSession: "فتح الجلسة المرتبطة",
|
||||
defaultAgent: "الوكيل الافتراضي",
|
||||
runEngine: "تشغيل {engine}",
|
||||
openEngine: "فتح {engine}",
|
||||
runDefaultAgent: "تشغيل الوكيل الافتراضي",
|
||||
start: "بدء",
|
||||
live: "مباشر",
|
||||
fieldTitle: "العنوان",
|
||||
fieldNotes: "ملاحظات",
|
||||
fieldStatus: "الحالة",
|
||||
@@ -499,7 +511,12 @@ export const ar: TranslationMap = {
|
||||
fieldAgent: "الوكيل",
|
||||
fieldSession: "الجلسة",
|
||||
fieldLabels: "التصنيفات",
|
||||
titlePlaceholder: "عنوان البطاقة",
|
||||
notesPlaceholder: "ملاحظات، معايير القبول، روابط",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "البحث في البطاقات",
|
||||
allPriorities: "كل الأولويات",
|
||||
emptyColumn: "أفلِت العمل هنا",
|
||||
lifecycleUnlinked: "لا توجد جلسة",
|
||||
lifecycleUnlinkedDetail: "ابدأ جلسة أو اربطها",
|
||||
lifecycleMissing: "الجلسة مفقودة",
|
||||
@@ -512,6 +529,13 @@ export const ar: TranslationMap = {
|
||||
lifecycleDoneDetail: "تم النقل إلى المراجعة",
|
||||
lifecycleNeedsReview: "تحتاج إلى مراجعة",
|
||||
lifecycleNeedsReviewDetail: "توقف التشغيل أو فشل",
|
||||
eventsLabel: "أحداث البطاقة",
|
||||
eventCreated: "تم الإنشاء",
|
||||
eventEdited: "تم التعديل",
|
||||
eventMoved: "تم النقل",
|
||||
eventMovedTo: "تم النقل إلى {status}",
|
||||
eventLinked: "تم ربط الجلسة",
|
||||
eventExecutionUpdated: "تم تحديث الوكيل",
|
||||
gameButton: "لعبة مصغرة",
|
||||
gameTitle: "مطاردة البطاقات",
|
||||
gameStart: "صِل إلى مربع الإطلاق.",
|
||||
@@ -1172,7 +1196,7 @@ export const ar: TranslationMap = {
|
||||
},
|
||||
queue: {
|
||||
retry: "إعادة المحاولة",
|
||||
retrySend: "إعادة الإرسال",
|
||||
retrySend: "إعادة محاولة الإرسال",
|
||||
retryQueuedMessage: "إعادة محاولة الرسالة في قائمة الانتظار",
|
||||
},
|
||||
composer: {
|
||||
|
||||
30
ui/src/i18n/locales/de.ts
generated
30
ui/src/i18n/locales/de.ts
generated
@@ -496,6 +496,18 @@ export const de: TranslationMap = {
|
||||
noLinkedSession: "Keine verknüpfte Sitzung",
|
||||
stopSession: "Sitzung stoppen",
|
||||
editCard: "Karte bearbeiten",
|
||||
editCardHelp: "Warteschlangen-Metadaten und Sitzungsübergabe aktualisieren.",
|
||||
newCard: "Neue Karte",
|
||||
newCardHelp: "Arbeit für eine Agentensitzung in die Warteschlange einreihen.",
|
||||
deleteCard: "Karte löschen",
|
||||
openSession: "Sitzung öffnen",
|
||||
openLinkedSession: "Verknüpfte Sitzung öffnen",
|
||||
defaultAgent: "Standard-Agent",
|
||||
runEngine: "{engine} ausführen",
|
||||
openEngine: "{engine} öffnen",
|
||||
runDefaultAgent: "Standard-Agent ausführen",
|
||||
start: "Starten",
|
||||
live: "live",
|
||||
fieldTitle: "Titel",
|
||||
fieldNotes: "Notizen",
|
||||
fieldStatus: "Status",
|
||||
@@ -503,7 +515,12 @@ export const de: TranslationMap = {
|
||||
fieldAgent: "Agent",
|
||||
fieldSession: "Sitzung",
|
||||
fieldLabels: "Labels",
|
||||
titlePlaceholder: "Kartentitel",
|
||||
notesPlaceholder: "Notizen, Akzeptanzkriterien, Links",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Karten suchen",
|
||||
allPriorities: "Alle Prioritäten",
|
||||
emptyColumn: "Arbeit hier ablegen",
|
||||
lifecycleUnlinked: "Keine Sitzung",
|
||||
lifecycleUnlinkedDetail: "Sitzung starten oder verknüpfen",
|
||||
lifecycleMissing: "Sitzung fehlt",
|
||||
@@ -516,6 +533,13 @@ export const de: TranslationMap = {
|
||||
lifecycleDoneDetail: "Zur Überprüfung verschoben",
|
||||
lifecycleNeedsReview: "Überprüfung erforderlich",
|
||||
lifecycleNeedsReviewDetail: "Lauf gestoppt oder fehlgeschlagen",
|
||||
eventsLabel: "Kartenereignisse",
|
||||
eventCreated: "Erstellt",
|
||||
eventEdited: "Bearbeitet",
|
||||
eventMoved: "Verschoben",
|
||||
eventMovedTo: "Verschoben nach {status}",
|
||||
eventLinked: "Sitzung verknüpft",
|
||||
eventExecutionUpdated: "Agent aktualisiert",
|
||||
gameButton: "Minispiel",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Erreiche das Startfeld.",
|
||||
@@ -1195,9 +1219,9 @@ export const de: TranslationMap = {
|
||||
sendMessage: "Send message",
|
||||
},
|
||||
queue: {
|
||||
retry: "Erneut versuchen",
|
||||
retrySend: "Senden erneut versuchen",
|
||||
retryQueuedMessage: "Nachricht in der Warteschlange erneut versuchen",
|
||||
retry: "Wiederholen",
|
||||
retrySend: "Senden wiederholen",
|
||||
retryQueuedMessage: "Nachricht in der Warteschlange erneut senden",
|
||||
},
|
||||
composer: {
|
||||
placeholder: "Message {name} (Enter to send)",
|
||||
|
||||
@@ -491,6 +491,18 @@ export const en: TranslationMap = {
|
||||
noLinkedSession: "No linked session",
|
||||
stopSession: "Stop session",
|
||||
editCard: "Edit card",
|
||||
editCardHelp: "Update queue metadata and session handoff.",
|
||||
newCard: "New card",
|
||||
newCardHelp: "Queue work for an agent session.",
|
||||
deleteCard: "Delete card",
|
||||
openSession: "Open session",
|
||||
openLinkedSession: "Open linked session",
|
||||
defaultAgent: "Default agent",
|
||||
runEngine: "Run {engine}",
|
||||
openEngine: "Open {engine}",
|
||||
runDefaultAgent: "Run default agent",
|
||||
start: "Start",
|
||||
live: "live",
|
||||
fieldTitle: "Title",
|
||||
fieldNotes: "Notes",
|
||||
fieldStatus: "Status",
|
||||
@@ -498,7 +510,12 @@ export const en: TranslationMap = {
|
||||
fieldAgent: "Agent",
|
||||
fieldSession: "Session",
|
||||
fieldLabels: "Labels",
|
||||
titlePlaceholder: "Card title",
|
||||
notesPlaceholder: "Notes, acceptance criteria, links",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Search cards",
|
||||
allPriorities: "All priorities",
|
||||
emptyColumn: "Drop work here",
|
||||
lifecycleUnlinked: "No session",
|
||||
lifecycleUnlinkedDetail: "Start or link a session",
|
||||
lifecycleMissing: "Session missing",
|
||||
@@ -511,6 +528,13 @@ export const en: TranslationMap = {
|
||||
lifecycleDoneDetail: "Moved to review",
|
||||
lifecycleNeedsReview: "Needs review",
|
||||
lifecycleNeedsReviewDetail: "Run stopped or failed",
|
||||
eventsLabel: "Card events",
|
||||
eventCreated: "Created",
|
||||
eventEdited: "Edited",
|
||||
eventMoved: "Moved",
|
||||
eventMovedTo: "Moved to {status}",
|
||||
eventLinked: "Linked session",
|
||||
eventExecutionUpdated: "Agent updated",
|
||||
gameButton: "Mini game",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Reach the launch tile.",
|
||||
|
||||
24
ui/src/i18n/locales/es.ts
generated
24
ui/src/i18n/locales/es.ts
generated
@@ -493,6 +493,18 @@ export const es: TranslationMap = {
|
||||
noLinkedSession: "Sin sesión vinculada",
|
||||
stopSession: "Detener sesión",
|
||||
editCard: "Editar tarjeta",
|
||||
editCardHelp: "Actualiza los metadatos de la cola y la transferencia de sesión.",
|
||||
newCard: "Nueva tarjeta",
|
||||
newCardHelp: "Pon trabajo en cola para una sesión de agente.",
|
||||
deleteCard: "Eliminar tarjeta",
|
||||
openSession: "Abrir sesión",
|
||||
openLinkedSession: "Abrir sesión vinculada",
|
||||
defaultAgent: "Agente predeterminado",
|
||||
runEngine: "Ejecutar {engine}",
|
||||
openEngine: "Abrir {engine}",
|
||||
runDefaultAgent: "Ejecutar agente predeterminado",
|
||||
start: "Iniciar",
|
||||
live: "en vivo",
|
||||
fieldTitle: "Título",
|
||||
fieldNotes: "Notas",
|
||||
fieldStatus: "Estado",
|
||||
@@ -500,7 +512,12 @@ export const es: TranslationMap = {
|
||||
fieldAgent: "Agente",
|
||||
fieldSession: "Sesión",
|
||||
fieldLabels: "Etiquetas",
|
||||
titlePlaceholder: "Título de la tarjeta",
|
||||
notesPlaceholder: "Notas, criterios de aceptación, enlaces",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Buscar tarjetas",
|
||||
allPriorities: "Todas las prioridades",
|
||||
emptyColumn: "Suelta el trabajo aquí",
|
||||
lifecycleUnlinked: "Sin sesión",
|
||||
lifecycleUnlinkedDetail: "Inicia o vincula una sesión",
|
||||
lifecycleMissing: "Falta la sesión",
|
||||
@@ -513,6 +530,13 @@ export const es: TranslationMap = {
|
||||
lifecycleDoneDetail: "Movido a revisión",
|
||||
lifecycleNeedsReview: "Necesita revisión",
|
||||
lifecycleNeedsReviewDetail: "La ejecución se detuvo o falló",
|
||||
eventsLabel: "Eventos de la tarjeta",
|
||||
eventCreated: "Creada",
|
||||
eventEdited: "Editada",
|
||||
eventMoved: "Movido",
|
||||
eventMovedTo: "Movido a {status}",
|
||||
eventLinked: "Sesión vinculada",
|
||||
eventExecutionUpdated: "Agente actualizado",
|
||||
gameButton: "Minijuego",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Alcanza la casilla de lanzamiento.",
|
||||
|
||||
58
ui/src/i18n/locales/fa.ts
generated
58
ui/src/i18n/locales/fa.ts
generated
@@ -493,6 +493,32 @@ export const fa: TranslationMap = {
|
||||
},
|
||||
noLinkedSession: "جلسهای پیوند نشده است",
|
||||
stopSession: "توقف جلسه",
|
||||
editCard: "ویرایش کارت",
|
||||
editCardHelp: "بهروزرسانی فرادادهٔ صف و واگذاری نشست.",
|
||||
newCard: "کارت جدید",
|
||||
newCardHelp: "کار را برای یک نشست عامل در صف قرار دهید.",
|
||||
deleteCard: "حذف کارت",
|
||||
openSession: "باز کردن نشست",
|
||||
openLinkedSession: "باز کردن نشست پیوندشده",
|
||||
defaultAgent: "عامل پیشفرض",
|
||||
runEngine: "اجرای {engine}",
|
||||
openEngine: "باز کردن {engine}",
|
||||
runDefaultAgent: "اجرای عامل پیشفرض",
|
||||
start: "شروع",
|
||||
live: "زنده",
|
||||
fieldTitle: "عنوان",
|
||||
fieldNotes: "یادداشتها",
|
||||
fieldStatus: "وضعیت",
|
||||
fieldPriority: "اولویت",
|
||||
fieldAgent: "عامل",
|
||||
fieldSession: "نشست",
|
||||
fieldLabels: "برچسبها",
|
||||
titlePlaceholder: "عنوان کارت",
|
||||
notesPlaceholder: "یادداشتها، معیارهای پذیرش، پیوندها",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "جستجوی کارتها",
|
||||
allPriorities: "همه اولویتها",
|
||||
emptyColumn: "کار را اینجا رها کنید",
|
||||
lifecycleUnlinked: "بدون جلسه",
|
||||
lifecycleUnlinkedDetail: "یک جلسه را شروع یا پیوند کنید",
|
||||
lifecycleMissing: "جلسه پیدا نشد",
|
||||
@@ -505,6 +531,32 @@ export const fa: TranslationMap = {
|
||||
lifecycleDoneDetail: "به بازبینی منتقل شد",
|
||||
lifecycleNeedsReview: "نیازمند بازبینی",
|
||||
lifecycleNeedsReviewDetail: "اجرا متوقف شد یا ناموفق بود",
|
||||
eventsLabel: "رویدادهای کارت",
|
||||
eventCreated: "ایجاد شد",
|
||||
eventEdited: "ویرایش شد",
|
||||
eventMoved: "منتقل شد",
|
||||
eventMovedTo: "به {status} منتقل شد",
|
||||
eventLinked: "نشست پیوند داده شد",
|
||||
eventExecutionUpdated: "Agent بهروزرسانی شد",
|
||||
gameButton: "بازی کوچک",
|
||||
gameTitle: "تعقیب کارت",
|
||||
gameStart: "به کاشی راهاندازی برسید.",
|
||||
gameBoundary: "به مرز رسیدید.",
|
||||
gameBlocked: "مسدود شده است.",
|
||||
gameContinue: "ادامه دهید.",
|
||||
gameWin: "راهاندازی با موفقیت انجام شد.",
|
||||
gameMoves: "حرکتها {count}",
|
||||
gameWins: "بردها {count}",
|
||||
gameBoard: "صفحه Card Chase",
|
||||
gameControls: "کنترلهای Card Chase",
|
||||
gameAgent: "عامل",
|
||||
gameLaunch: "راهاندازی",
|
||||
gameBlockedCell: "مسدود",
|
||||
gameOpenCell: "باز",
|
||||
gameMoveUp: "حرکت به بالا",
|
||||
gameMoveLeft: "حرکت به چپ",
|
||||
gameMoveDown: "حرکت به پایین",
|
||||
gameMoveRight: "حرکت به راست",
|
||||
},
|
||||
overview: {
|
||||
access: {
|
||||
@@ -1160,9 +1212,9 @@ export const fa: TranslationMap = {
|
||||
sendMessage: "Send message",
|
||||
},
|
||||
queue: {
|
||||
retry: "تلاش مجدد",
|
||||
retrySend: "ارسال مجدد",
|
||||
retryQueuedMessage: "تلاش مجدد برای پیام در صف",
|
||||
retry: "تلاش دوباره",
|
||||
retrySend: "تلاش دوباره برای ارسال",
|
||||
retryQueuedMessage: "تلاش دوباره برای پیام در صف",
|
||||
},
|
||||
composer: {
|
||||
placeholder: "Message {name} (Enter to send)",
|
||||
|
||||
24
ui/src/i18n/locales/fr.ts
generated
24
ui/src/i18n/locales/fr.ts
generated
@@ -495,6 +495,18 @@ export const fr: TranslationMap = {
|
||||
noLinkedSession: "Aucune session liée",
|
||||
stopSession: "Arrêter la session",
|
||||
editCard: "Modifier la carte",
|
||||
editCardHelp: "Mettez à jour les métadonnées de la file d’attente et le transfert de session.",
|
||||
newCard: "Nouvelle carte",
|
||||
newCardHelp: "Mettez du travail en file d’attente pour une session d’agent.",
|
||||
deleteCard: "Supprimer la carte",
|
||||
openSession: "Ouvrir la session",
|
||||
openLinkedSession: "Ouvrir la session liée",
|
||||
defaultAgent: "Agent par défaut",
|
||||
runEngine: "Exécuter {engine}",
|
||||
openEngine: "Ouvrir {engine}",
|
||||
runDefaultAgent: "Exécuter l’agent par défaut",
|
||||
start: "Démarrer",
|
||||
live: "en direct",
|
||||
fieldTitle: "Titre",
|
||||
fieldNotes: "Notes",
|
||||
fieldStatus: "Statut",
|
||||
@@ -502,7 +514,12 @@ export const fr: TranslationMap = {
|
||||
fieldAgent: "Agent",
|
||||
fieldSession: "Session",
|
||||
fieldLabels: "Étiquettes",
|
||||
titlePlaceholder: "Titre de la carte",
|
||||
notesPlaceholder: "Notes, critères d’acceptation, liens",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Rechercher des cartes",
|
||||
allPriorities: "Toutes les priorités",
|
||||
emptyColumn: "Déposez le travail ici",
|
||||
lifecycleUnlinked: "Aucune session",
|
||||
lifecycleUnlinkedDetail: "Démarrer ou lier une session",
|
||||
lifecycleMissing: "Session manquante",
|
||||
@@ -515,6 +532,13 @@ export const fr: TranslationMap = {
|
||||
lifecycleDoneDetail: "Déplacé vers la révision",
|
||||
lifecycleNeedsReview: "Nécessite une révision",
|
||||
lifecycleNeedsReviewDetail: "Exécution arrêtée ou échouée",
|
||||
eventsLabel: "Événements de la carte",
|
||||
eventCreated: "Créé",
|
||||
eventEdited: "Modifié",
|
||||
eventMoved: "Déplacé",
|
||||
eventMovedTo: "Déplacé vers {status}",
|
||||
eventLinked: "Session liée",
|
||||
eventExecutionUpdated: "Agent mis à jour",
|
||||
gameButton: "Mini-jeu",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Atteignez la tuile de lancement.",
|
||||
|
||||
24
ui/src/i18n/locales/id.ts
generated
24
ui/src/i18n/locales/id.ts
generated
@@ -493,6 +493,18 @@ export const id: TranslationMap = {
|
||||
noLinkedSession: "Tidak ada sesi tertaut",
|
||||
stopSession: "Hentikan sesi",
|
||||
editCard: "Edit kartu",
|
||||
editCardHelp: "Perbarui metadata antrean dan serah terima sesi.",
|
||||
newCard: "Kartu baru",
|
||||
newCardHelp: "Antrekan pekerjaan untuk sesi agen.",
|
||||
deleteCard: "Hapus kartu",
|
||||
openSession: "Buka sesi",
|
||||
openLinkedSession: "Buka sesi tertaut",
|
||||
defaultAgent: "Agen default",
|
||||
runEngine: "Jalankan {engine}",
|
||||
openEngine: "Buka {engine}",
|
||||
runDefaultAgent: "Jalankan agen default",
|
||||
start: "Mulai",
|
||||
live: "langsung",
|
||||
fieldTitle: "Judul",
|
||||
fieldNotes: "Catatan",
|
||||
fieldStatus: "Status",
|
||||
@@ -500,7 +512,12 @@ export const id: TranslationMap = {
|
||||
fieldAgent: "Agen",
|
||||
fieldSession: "Sesi",
|
||||
fieldLabels: "Label",
|
||||
titlePlaceholder: "Judul kartu",
|
||||
notesPlaceholder: "Catatan, kriteria penerimaan, tautan",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Cari kartu",
|
||||
allPriorities: "Semua prioritas",
|
||||
emptyColumn: "Letakkan pekerjaan di sini",
|
||||
lifecycleUnlinked: "Tidak ada sesi",
|
||||
lifecycleUnlinkedDetail: "Mulai atau tautkan sesi",
|
||||
lifecycleMissing: "Sesi hilang",
|
||||
@@ -513,6 +530,13 @@ export const id: TranslationMap = {
|
||||
lifecycleDoneDetail: "Dipindahkan ke peninjauan",
|
||||
lifecycleNeedsReview: "Perlu ditinjau",
|
||||
lifecycleNeedsReviewDetail: "Run dihentikan atau gagal",
|
||||
eventsLabel: "Peristiwa kartu",
|
||||
eventCreated: "Dibuat",
|
||||
eventEdited: "Diedit",
|
||||
eventMoved: "Dipindahkan",
|
||||
eventMovedTo: "Dipindahkan ke {status}",
|
||||
eventLinked: "Sesi ditautkan",
|
||||
eventExecutionUpdated: "Agen diperbarui",
|
||||
gameButton: "Mini game",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Capai petak peluncuran.",
|
||||
|
||||
24
ui/src/i18n/locales/it.ts
generated
24
ui/src/i18n/locales/it.ts
generated
@@ -495,6 +495,18 @@ export const it: TranslationMap = {
|
||||
noLinkedSession: "Nessuna sessione collegata",
|
||||
stopSession: "Interrompi sessione",
|
||||
editCard: "Modifica scheda",
|
||||
editCardHelp: "Aggiorna i metadati della coda e il passaggio di sessione.",
|
||||
newCard: "Nuova scheda",
|
||||
newCardHelp: "Metti in coda il lavoro per una sessione dell'agente.",
|
||||
deleteCard: "Elimina scheda",
|
||||
openSession: "Apri sessione",
|
||||
openLinkedSession: "Apri sessione collegata",
|
||||
defaultAgent: "Agente predefinito",
|
||||
runEngine: "Esegui {engine}",
|
||||
openEngine: "Apri {engine}",
|
||||
runDefaultAgent: "Esegui agente predefinito",
|
||||
start: "Avvia",
|
||||
live: "live",
|
||||
fieldTitle: "Titolo",
|
||||
fieldNotes: "Note",
|
||||
fieldStatus: "Stato",
|
||||
@@ -502,7 +514,12 @@ export const it: TranslationMap = {
|
||||
fieldAgent: "Agente",
|
||||
fieldSession: "Sessione",
|
||||
fieldLabels: "Etichette",
|
||||
titlePlaceholder: "Titolo scheda",
|
||||
notesPlaceholder: "Note, criteri di accettazione, link",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Cerca schede",
|
||||
allPriorities: "Tutte le priorità",
|
||||
emptyColumn: "Rilascia qui il lavoro",
|
||||
lifecycleUnlinked: "Nessuna sessione",
|
||||
lifecycleUnlinkedDetail: "Avvia o collega una sessione",
|
||||
lifecycleMissing: "Sessione mancante",
|
||||
@@ -515,6 +532,13 @@ export const it: TranslationMap = {
|
||||
lifecycleDoneDetail: "Spostata in revisione",
|
||||
lifecycleNeedsReview: "Richiede revisione",
|
||||
lifecycleNeedsReviewDetail: "Esecuzione interrotta o non riuscita",
|
||||
eventsLabel: "Eventi della scheda",
|
||||
eventCreated: "Creato",
|
||||
eventEdited: "Modificato",
|
||||
eventMoved: "Spostato",
|
||||
eventMovedTo: "Spostato in {status}",
|
||||
eventLinked: "Sessione collegata",
|
||||
eventExecutionUpdated: "Agente aggiornato",
|
||||
gameButton: "Mini gioco",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Raggiungi la casella di lancio.",
|
||||
|
||||
24
ui/src/i18n/locales/ja-JP.ts
generated
24
ui/src/i18n/locales/ja-JP.ts
generated
@@ -496,6 +496,18 @@ export const ja_JP: TranslationMap = {
|
||||
noLinkedSession: "リンクされたセッションがありません",
|
||||
stopSession: "セッションを停止",
|
||||
editCard: "カードを編集",
|
||||
editCardHelp: "キューのメタデータとセッションの引き継ぎを更新します。",
|
||||
newCard: "新規カード",
|
||||
newCardHelp: "エージェントセッションの作業をキューに追加します。",
|
||||
deleteCard: "カードを削除",
|
||||
openSession: "セッションを開く",
|
||||
openLinkedSession: "リンクされたセッションを開く",
|
||||
defaultAgent: "デフォルトエージェント",
|
||||
runEngine: "{engine} を実行",
|
||||
openEngine: "{engine} を開く",
|
||||
runDefaultAgent: "デフォルトエージェントを実行",
|
||||
start: "開始",
|
||||
live: "ライブ",
|
||||
fieldTitle: "タイトル",
|
||||
fieldNotes: "メモ",
|
||||
fieldStatus: "ステータス",
|
||||
@@ -503,7 +515,12 @@ export const ja_JP: TranslationMap = {
|
||||
fieldAgent: "エージェント",
|
||||
fieldSession: "セッション",
|
||||
fieldLabels: "ラベル",
|
||||
titlePlaceholder: "カードのタイトル",
|
||||
notesPlaceholder: "メモ、受け入れ条件、リンク",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "カードを検索",
|
||||
allPriorities: "すべての優先度",
|
||||
emptyColumn: "ここに作業をドロップ",
|
||||
lifecycleUnlinked: "セッションなし",
|
||||
lifecycleUnlinkedDetail: "セッションを開始またはリンク",
|
||||
lifecycleMissing: "セッションが見つかりません",
|
||||
@@ -516,6 +533,13 @@ export const ja_JP: TranslationMap = {
|
||||
lifecycleDoneDetail: "レビューに移動しました",
|
||||
lifecycleNeedsReview: "レビューが必要",
|
||||
lifecycleNeedsReviewDetail: "実行が停止または失敗しました",
|
||||
eventsLabel: "カードイベント",
|
||||
eventCreated: "作成済み",
|
||||
eventEdited: "編集済み",
|
||||
eventMoved: "移動しました",
|
||||
eventMovedTo: "{status} に移動しました",
|
||||
eventLinked: "セッションをリンクしました",
|
||||
eventExecutionUpdated: "Agent が更新されました",
|
||||
gameButton: "ミニゲーム",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "ローンチタイルに到達してください。",
|
||||
|
||||
26
ui/src/i18n/locales/ko.ts
generated
26
ui/src/i18n/locales/ko.ts
generated
@@ -492,6 +492,18 @@ export const ko: TranslationMap = {
|
||||
noLinkedSession: "연결된 세션 없음",
|
||||
stopSession: "세션 중지",
|
||||
editCard: "카드 편집",
|
||||
editCardHelp: "대기열 메타데이터와 세션 인계를 업데이트합니다.",
|
||||
newCard: "새 카드",
|
||||
newCardHelp: "에이전트 세션을 위한 작업을 대기열에 추가합니다.",
|
||||
deleteCard: "카드 삭제",
|
||||
openSession: "세션 열기",
|
||||
openLinkedSession: "연결된 세션 열기",
|
||||
defaultAgent: "기본 에이전트",
|
||||
runEngine: "{engine} 실행",
|
||||
openEngine: "{engine} 열기",
|
||||
runDefaultAgent: "기본 에이전트 실행",
|
||||
start: "시작",
|
||||
live: "라이브",
|
||||
fieldTitle: "제목",
|
||||
fieldNotes: "메모",
|
||||
fieldStatus: "상태",
|
||||
@@ -499,7 +511,12 @@ export const ko: TranslationMap = {
|
||||
fieldAgent: "에이전트",
|
||||
fieldSession: "세션",
|
||||
fieldLabels: "레이블",
|
||||
titlePlaceholder: "카드 제목",
|
||||
notesPlaceholder: "메모, 승인 기준, 링크",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "카드 검색",
|
||||
allPriorities: "모든 우선순위",
|
||||
emptyColumn: "여기에 작업을 놓으세요",
|
||||
lifecycleUnlinked: "세션 없음",
|
||||
lifecycleUnlinkedDetail: "세션을 시작하거나 연결하세요",
|
||||
lifecycleMissing: "세션 누락",
|
||||
@@ -512,6 +529,13 @@ export const ko: TranslationMap = {
|
||||
lifecycleDoneDetail: "검토로 이동됨",
|
||||
lifecycleNeedsReview: "검토 필요",
|
||||
lifecycleNeedsReviewDetail: "실행이 중지되었거나 실패했습니다",
|
||||
eventsLabel: "카드 이벤트",
|
||||
eventCreated: "생성됨",
|
||||
eventEdited: "편집됨",
|
||||
eventMoved: "이동됨",
|
||||
eventMovedTo: "{status}(으)로 이동됨",
|
||||
eventLinked: "연결된 세션",
|
||||
eventExecutionUpdated: "Agent 업데이트됨",
|
||||
gameButton: "미니 게임",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "출발 타일에 도달하세요.",
|
||||
@@ -1180,7 +1204,7 @@ export const ko: TranslationMap = {
|
||||
},
|
||||
queue: {
|
||||
retry: "다시 시도",
|
||||
retrySend: "전송 다시 시도",
|
||||
retrySend: "보내기 다시 시도",
|
||||
retryQueuedMessage: "대기 중인 메시지 다시 시도",
|
||||
},
|
||||
composer: {
|
||||
|
||||
52
ui/src/i18n/locales/nl.ts
generated
52
ui/src/i18n/locales/nl.ts
generated
@@ -494,6 +494,32 @@ export const nl: TranslationMap = {
|
||||
},
|
||||
noLinkedSession: "Geen gekoppelde sessie",
|
||||
stopSession: "Sessie stoppen",
|
||||
editCard: "Kaart bewerken",
|
||||
editCardHelp: "Werk wachtrijmetadata en sessieoverdracht bij.",
|
||||
newCard: "Nieuwe kaart",
|
||||
newCardHelp: "Zet werk in de wachtrij voor een agentsessie.",
|
||||
deleteCard: "Kaart verwijderen",
|
||||
openSession: "Sessie openen",
|
||||
openLinkedSession: "Gekoppelde sessie openen",
|
||||
defaultAgent: "Standaardagent",
|
||||
runEngine: "{engine} uitvoeren",
|
||||
openEngine: "{engine} openen",
|
||||
runDefaultAgent: "Standaardagent uitvoeren",
|
||||
start: "Starten",
|
||||
live: "live",
|
||||
fieldTitle: "Titel",
|
||||
fieldNotes: "Notities",
|
||||
fieldStatus: "Status",
|
||||
fieldPriority: "Prioriteit",
|
||||
fieldAgent: "Agent",
|
||||
fieldSession: "Sessie",
|
||||
fieldLabels: "Labels",
|
||||
titlePlaceholder: "Kaarttitel",
|
||||
notesPlaceholder: "Notities, acceptatiecriteria, links",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Kaarten zoeken",
|
||||
allPriorities: "Alle prioriteiten",
|
||||
emptyColumn: "Sleep werk hierheen",
|
||||
lifecycleUnlinked: "Geen sessie",
|
||||
lifecycleUnlinkedDetail: "Start of koppel een sessie",
|
||||
lifecycleMissing: "Sessie ontbreekt",
|
||||
@@ -506,6 +532,32 @@ export const nl: TranslationMap = {
|
||||
lifecycleDoneDetail: "Verplaatst naar review",
|
||||
lifecycleNeedsReview: "Review nodig",
|
||||
lifecycleNeedsReviewDetail: "Run gestopt of mislukt",
|
||||
eventsLabel: "Kaartgebeurtenissen",
|
||||
eventCreated: "Gemaakt",
|
||||
eventEdited: "Bewerkt",
|
||||
eventMoved: "Verplaatst",
|
||||
eventMovedTo: "Verplaatst naar {status}",
|
||||
eventLinked: "Gekoppelde sessie",
|
||||
eventExecutionUpdated: "Agent bijgewerkt",
|
||||
gameButton: "Minigame",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Bereik de lanceringstegel.",
|
||||
gameBoundary: "Grens bereikt.",
|
||||
gameBlocked: "Geblokkeerd.",
|
||||
gameContinue: "Ga door.",
|
||||
gameWin: "Lancering voltooid.",
|
||||
gameMoves: "Zetten {count}",
|
||||
gameWins: "Overwinningen {count}",
|
||||
gameBoard: "Card Chase-bord",
|
||||
gameControls: "Card Chase-bediening",
|
||||
gameAgent: "Agent",
|
||||
gameLaunch: "Starten",
|
||||
gameBlockedCell: "Geblokkeerd",
|
||||
gameOpenCell: "Open",
|
||||
gameMoveUp: "Omhoog verplaatsen",
|
||||
gameMoveLeft: "Naar links verplaatsen",
|
||||
gameMoveDown: "Omlaag verplaatsen",
|
||||
gameMoveRight: "Naar rechts verplaatsen",
|
||||
},
|
||||
overview: {
|
||||
access: {
|
||||
|
||||
56
ui/src/i18n/locales/pl.ts
generated
56
ui/src/i18n/locales/pl.ts
generated
@@ -493,6 +493,32 @@ export const pl: TranslationMap = {
|
||||
},
|
||||
noLinkedSession: "Brak połączonej sesji",
|
||||
stopSession: "Zatrzymaj sesję",
|
||||
editCard: "Edytuj kartę",
|
||||
editCardHelp: "Zaktualizuj metadane kolejki i przekazanie sesji.",
|
||||
newCard: "Nowa karta",
|
||||
newCardHelp: "Dodaj zadanie do kolejki dla sesji agenta.",
|
||||
deleteCard: "Usuń kartę",
|
||||
openSession: "Otwórz sesję",
|
||||
openLinkedSession: "Otwórz powiązaną sesję",
|
||||
defaultAgent: "Domyślny agent",
|
||||
runEngine: "Uruchom {engine}",
|
||||
openEngine: "Otwórz {engine}",
|
||||
runDefaultAgent: "Uruchom domyślnego agenta",
|
||||
start: "Rozpocznij",
|
||||
live: "na żywo",
|
||||
fieldTitle: "Tytuł",
|
||||
fieldNotes: "Notatki",
|
||||
fieldStatus: "Status",
|
||||
fieldPriority: "Priorytet",
|
||||
fieldAgent: "Agent",
|
||||
fieldSession: "Sesja",
|
||||
fieldLabels: "Etykiety",
|
||||
titlePlaceholder: "Tytuł karty",
|
||||
notesPlaceholder: "Notatki, kryteria akceptacji, linki",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Szukaj kart",
|
||||
allPriorities: "Wszystkie priorytety",
|
||||
emptyColumn: "Upuść pracę tutaj",
|
||||
lifecycleUnlinked: "Brak sesji",
|
||||
lifecycleUnlinkedDetail: "Rozpocznij lub połącz sesję",
|
||||
lifecycleMissing: "Brak sesji",
|
||||
@@ -505,6 +531,32 @@ export const pl: TranslationMap = {
|
||||
lifecycleDoneDetail: "Przeniesiono do przeglądu",
|
||||
lifecycleNeedsReview: "Wymaga przeglądu",
|
||||
lifecycleNeedsReviewDetail: "Uruchomienie zatrzymane lub nieudane",
|
||||
eventsLabel: "Zdarzenia karty",
|
||||
eventCreated: "Utworzono",
|
||||
eventEdited: "Edytowano",
|
||||
eventMoved: "Przeniesiono",
|
||||
eventMovedTo: "Przeniesiono do {status}",
|
||||
eventLinked: "Połączona sesja",
|
||||
eventExecutionUpdated: "Agent zaktualizowany",
|
||||
gameButton: "Minigra",
|
||||
gameTitle: "Pościg za kartą",
|
||||
gameStart: "Dotrzyj do pola uruchomienia.",
|
||||
gameBoundary: "Osiągnięto granicę.",
|
||||
gameBlocked: "Zablokowane.",
|
||||
gameContinue: "Kontynuuj.",
|
||||
gameWin: "Uruchomienie zakończone.",
|
||||
gameMoves: "Ruchy {count}",
|
||||
gameWins: "Wygrane {count}",
|
||||
gameBoard: "Plansza Card Chase",
|
||||
gameControls: "Sterowanie Card Chase",
|
||||
gameAgent: "Agent",
|
||||
gameLaunch: "Uruchom",
|
||||
gameBlockedCell: "Zablokowane",
|
||||
gameOpenCell: "Otwarte",
|
||||
gameMoveUp: "Przesuń w górę",
|
||||
gameMoveLeft: "Przesuń w lewo",
|
||||
gameMoveDown: "Przesuń w dół",
|
||||
gameMoveRight: "Przesuń w prawo",
|
||||
},
|
||||
overview: {
|
||||
access: {
|
||||
@@ -1164,8 +1216,8 @@ export const pl: TranslationMap = {
|
||||
},
|
||||
queue: {
|
||||
retry: "Ponów",
|
||||
retrySend: "Ponów wysyłanie",
|
||||
retryQueuedMessage: "Ponów wysłanie wiadomości w kolejce",
|
||||
retrySend: "Ponów wysłanie",
|
||||
retryQueuedMessage: "Ponów wiadomość w kolejce",
|
||||
},
|
||||
composer: {
|
||||
placeholder: "Message {name} (Enter to send)",
|
||||
|
||||
26
ui/src/i18n/locales/pt-BR.ts
generated
26
ui/src/i18n/locales/pt-BR.ts
generated
@@ -493,6 +493,18 @@ export const pt_BR: TranslationMap = {
|
||||
noLinkedSession: "Nenhuma sessão vinculada",
|
||||
stopSession: "Parar sessão",
|
||||
editCard: "Editar cartão",
|
||||
editCardHelp: "Atualize os metadados da fila e a transferência de sessão.",
|
||||
newCard: "Novo cartão",
|
||||
newCardHelp: "Enfileire trabalho para uma sessão de agente.",
|
||||
deleteCard: "Excluir cartão",
|
||||
openSession: "Abrir sessão",
|
||||
openLinkedSession: "Abrir sessão vinculada",
|
||||
defaultAgent: "Agente padrão",
|
||||
runEngine: "Executar {engine}",
|
||||
openEngine: "Abrir {engine}",
|
||||
runDefaultAgent: "Executar agente padrão",
|
||||
start: "Iniciar",
|
||||
live: "ao vivo",
|
||||
fieldTitle: "Título",
|
||||
fieldNotes: "Notas",
|
||||
fieldStatus: "Status",
|
||||
@@ -500,7 +512,12 @@ export const pt_BR: TranslationMap = {
|
||||
fieldAgent: "Agente",
|
||||
fieldSession: "Sessão",
|
||||
fieldLabels: "Etiquetas",
|
||||
titlePlaceholder: "Título do cartão",
|
||||
notesPlaceholder: "Notas, critérios de aceitação, links",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Pesquisar cartões",
|
||||
allPriorities: "Todas as prioridades",
|
||||
emptyColumn: "Solte o trabalho aqui",
|
||||
lifecycleUnlinked: "Nenhuma sessão",
|
||||
lifecycleUnlinkedDetail: "Inicie ou vincule uma sessão",
|
||||
lifecycleMissing: "Sessão ausente",
|
||||
@@ -513,6 +530,13 @@ export const pt_BR: TranslationMap = {
|
||||
lifecycleDoneDetail: "Movido para revisão",
|
||||
lifecycleNeedsReview: "Precisa de revisão",
|
||||
lifecycleNeedsReviewDetail: "A execução foi interrompida ou falhou",
|
||||
eventsLabel: "Eventos do cartão",
|
||||
eventCreated: "Criado",
|
||||
eventEdited: "Editado",
|
||||
eventMoved: "Movido",
|
||||
eventMovedTo: "Movido para {status}",
|
||||
eventLinked: "Sessão vinculada",
|
||||
eventExecutionUpdated: "Agente atualizado",
|
||||
gameButton: "Mini game",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Alcance o bloco de lançamento.",
|
||||
@@ -1189,7 +1213,7 @@ export const pt_BR: TranslationMap = {
|
||||
queue: {
|
||||
retry: "Tentar novamente",
|
||||
retrySend: "Tentar enviar novamente",
|
||||
retryQueuedMessage: "Tentar novamente a mensagem na fila",
|
||||
retryQueuedMessage: "Tentar novamente mensagem na fila",
|
||||
},
|
||||
composer: {
|
||||
placeholder: "Message {name} (Enter to send)",
|
||||
|
||||
52
ui/src/i18n/locales/th.ts
generated
52
ui/src/i18n/locales/th.ts
generated
@@ -490,6 +490,32 @@ export const th: TranslationMap = {
|
||||
},
|
||||
noLinkedSession: "ไม่มีเซสชันที่เชื่อมโยง",
|
||||
stopSession: "หยุดเซสชัน",
|
||||
editCard: "แก้ไขการ์ด",
|
||||
editCardHelp: "อัปเดตข้อมูลเมตาของคิวและการส่งต่อเซสชัน",
|
||||
newCard: "การ์ดใหม่",
|
||||
newCardHelp: "จัดคิวงานสำหรับเซสชันของเอเจนต์",
|
||||
deleteCard: "ลบการ์ด",
|
||||
openSession: "เปิดเซสชัน",
|
||||
openLinkedSession: "เปิดเซสชันที่ลิงก์ไว้",
|
||||
defaultAgent: "เอเจนต์เริ่มต้น",
|
||||
runEngine: "เรียกใช้ {engine}",
|
||||
openEngine: "เปิด {engine}",
|
||||
runDefaultAgent: "เรียกใช้เอเจนต์เริ่มต้น",
|
||||
start: "เริ่ม",
|
||||
live: "สด",
|
||||
fieldTitle: "ชื่อเรื่อง",
|
||||
fieldNotes: "บันทึก",
|
||||
fieldStatus: "สถานะ",
|
||||
fieldPriority: "ลำดับความสำคัญ",
|
||||
fieldAgent: "เอเจนต์",
|
||||
fieldSession: "เซสชัน",
|
||||
fieldLabels: "ป้ายกำกับ",
|
||||
titlePlaceholder: "ชื่อการ์ด",
|
||||
notesPlaceholder: "บันทึก, เกณฑ์การยอมรับ, ลิงก์",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "ค้นหาการ์ด",
|
||||
allPriorities: "ทุกลำดับความสำคัญ",
|
||||
emptyColumn: "วางงานที่นี่",
|
||||
lifecycleUnlinked: "ไม่มีเซสชัน",
|
||||
lifecycleUnlinkedDetail: "เริ่มหรือเชื่อมโยงเซสชัน",
|
||||
lifecycleMissing: "ไม่พบเซสชัน",
|
||||
@@ -502,6 +528,32 @@ export const th: TranslationMap = {
|
||||
lifecycleDoneDetail: "ย้ายไปยังการตรวจทานแล้ว",
|
||||
lifecycleNeedsReview: "ต้องตรวจทาน",
|
||||
lifecycleNeedsReviewDetail: "การรันหยุดหรือไม่สำเร็จ",
|
||||
eventsLabel: "เหตุการณ์ของการ์ด",
|
||||
eventCreated: "สร้างแล้ว",
|
||||
eventEdited: "แก้ไขแล้ว",
|
||||
eventMoved: "ย้ายแล้ว",
|
||||
eventMovedTo: "ย้ายไปยัง {status}",
|
||||
eventLinked: "เซสชันที่ลิงก์แล้ว",
|
||||
eventExecutionUpdated: "เอเจนต์อัปเดตแล้ว",
|
||||
gameButton: "มินิเกม",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "ไปให้ถึงช่องเปิดตัว",
|
||||
gameBoundary: "ถึงขอบเขตแล้ว",
|
||||
gameBlocked: "ถูกบล็อก",
|
||||
gameContinue: "ไปต่อ",
|
||||
gameWin: "เปิดตัวสำเร็จ",
|
||||
gameMoves: "การเดิน {count}",
|
||||
gameWins: "ชนะ {count}",
|
||||
gameBoard: "กระดาน Card Chase",
|
||||
gameControls: "ตัวควบคุม Card Chase",
|
||||
gameAgent: "Agent",
|
||||
gameLaunch: "เปิดใช้งาน",
|
||||
gameBlockedCell: "ถูกบล็อก",
|
||||
gameOpenCell: "เปิด",
|
||||
gameMoveUp: "เลื่อนขึ้น",
|
||||
gameMoveLeft: "เลื่อนไปทางซ้าย",
|
||||
gameMoveDown: "เลื่อนลง",
|
||||
gameMoveRight: "เลื่อนไปทางขวา",
|
||||
},
|
||||
overview: {
|
||||
access: {
|
||||
|
||||
26
ui/src/i18n/locales/tr.ts
generated
26
ui/src/i18n/locales/tr.ts
generated
@@ -495,6 +495,18 @@ export const tr: TranslationMap = {
|
||||
noLinkedSession: "Bağlı oturum yok",
|
||||
stopSession: "Oturumu durdur",
|
||||
editCard: "Kartı düzenle",
|
||||
editCardHelp: "Kuyruk meta verilerini ve oturum devrini güncelleyin.",
|
||||
newCard: "Yeni kart",
|
||||
newCardHelp: "Bir ajan oturumu için işi kuyruğa alın.",
|
||||
deleteCard: "Kartı sil",
|
||||
openSession: "Oturumu aç",
|
||||
openLinkedSession: "Bağlantılı oturumu aç",
|
||||
defaultAgent: "Varsayılan ajan",
|
||||
runEngine: "{engine} çalıştır",
|
||||
openEngine: "{engine} aç",
|
||||
runDefaultAgent: "Varsayılan ajanı çalıştır",
|
||||
start: "Başlat",
|
||||
live: "canlı",
|
||||
fieldTitle: "Başlık",
|
||||
fieldNotes: "Notlar",
|
||||
fieldStatus: "Durum",
|
||||
@@ -502,7 +514,12 @@ export const tr: TranslationMap = {
|
||||
fieldAgent: "Aracı",
|
||||
fieldSession: "Oturum",
|
||||
fieldLabels: "Etiketler",
|
||||
titlePlaceholder: "Kart başlığı",
|
||||
notesPlaceholder: "Notlar, kabul kriterleri, bağlantılar",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Kartlarda ara",
|
||||
allPriorities: "Tüm öncelikler",
|
||||
emptyColumn: "İşi buraya bırakın",
|
||||
lifecycleUnlinked: "Oturum yok",
|
||||
lifecycleUnlinkedDetail: "Bir oturum başlatın veya bağlayın",
|
||||
lifecycleMissing: "Oturum eksik",
|
||||
@@ -515,6 +532,13 @@ export const tr: TranslationMap = {
|
||||
lifecycleDoneDetail: "İncelemeye taşındı",
|
||||
lifecycleNeedsReview: "İnceleme gerekli",
|
||||
lifecycleNeedsReviewDetail: "Çalışma durduruldu veya başarısız oldu",
|
||||
eventsLabel: "Kart olayları",
|
||||
eventCreated: "Oluşturuldu",
|
||||
eventEdited: "Düzenlendi",
|
||||
eventMoved: "Taşındı",
|
||||
eventMovedTo: "{status} durumuna taşındı",
|
||||
eventLinked: "Oturum bağlandı",
|
||||
eventExecutionUpdated: "Aracı güncellendi",
|
||||
gameButton: "Mini oyun",
|
||||
gameTitle: "Kart Takibi",
|
||||
gameStart: "Başlatma karesine ulaşın.",
|
||||
@@ -1194,7 +1218,7 @@ export const tr: TranslationMap = {
|
||||
queue: {
|
||||
retry: "Yeniden dene",
|
||||
retrySend: "Göndermeyi yeniden dene",
|
||||
retryQueuedMessage: "Kuyruktaki mesajı yeniden dene",
|
||||
retryQueuedMessage: "Kuyruğa alınan iletiyi yeniden dene",
|
||||
},
|
||||
composer: {
|
||||
placeholder: "Message {name} (Enter to send)",
|
||||
|
||||
26
ui/src/i18n/locales/uk.ts
generated
26
ui/src/i18n/locales/uk.ts
generated
@@ -494,6 +494,18 @@ export const uk: TranslationMap = {
|
||||
noLinkedSession: "Немає пов’язаної сесії",
|
||||
stopSession: "Зупинити сесію",
|
||||
editCard: "Редагувати картку",
|
||||
editCardHelp: "Оновіть метадані черги та передавання сесії.",
|
||||
newCard: "Нова картка",
|
||||
newCardHelp: "Поставте роботу в чергу для сесії агента.",
|
||||
deleteCard: "Видалити картку",
|
||||
openSession: "Відкрити сесію",
|
||||
openLinkedSession: "Відкрити пов’язану сесію",
|
||||
defaultAgent: "Агент за замовчуванням",
|
||||
runEngine: "Запустити {engine}",
|
||||
openEngine: "Відкрити {engine}",
|
||||
runDefaultAgent: "Запустити агента за замовчуванням",
|
||||
start: "Почати",
|
||||
live: "наживо",
|
||||
fieldTitle: "Заголовок",
|
||||
fieldNotes: "Нотатки",
|
||||
fieldStatus: "Статус",
|
||||
@@ -501,7 +513,12 @@ export const uk: TranslationMap = {
|
||||
fieldAgent: "Агент",
|
||||
fieldSession: "Сеанс",
|
||||
fieldLabels: "Мітки",
|
||||
titlePlaceholder: "Заголовок картки",
|
||||
notesPlaceholder: "Нотатки, критерії приймання, посилання",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Шукати картки",
|
||||
allPriorities: "Усі пріоритети",
|
||||
emptyColumn: "Перетягніть роботу сюди",
|
||||
lifecycleUnlinked: "Немає сесії",
|
||||
lifecycleUnlinkedDetail: "Запустіть або пов’яжіть сесію",
|
||||
lifecycleMissing: "Сесію не знайдено",
|
||||
@@ -514,6 +531,13 @@ export const uk: TranslationMap = {
|
||||
lifecycleDoneDetail: "Переміщено на перевірку",
|
||||
lifecycleNeedsReview: "Потребує перевірки",
|
||||
lifecycleNeedsReviewDetail: "Запуск зупинено або він завершився помилкою",
|
||||
eventsLabel: "Події картки",
|
||||
eventCreated: "Створено",
|
||||
eventEdited: "Змінено",
|
||||
eventMoved: "Переміщено",
|
||||
eventMovedTo: "Переміщено до {status}",
|
||||
eventLinked: "Пов’язаний сеанс",
|
||||
eventExecutionUpdated: "Агент оновлено",
|
||||
gameButton: "Мінігра",
|
||||
gameTitle: "Card Chase",
|
||||
gameStart: "Дістаньтеся клітинки запуску.",
|
||||
@@ -1191,7 +1215,7 @@ export const uk: TranslationMap = {
|
||||
queue: {
|
||||
retry: "Повторити",
|
||||
retrySend: "Повторити надсилання",
|
||||
retryQueuedMessage: "Повторити надсилання повідомлення в черзі",
|
||||
retryQueuedMessage: "Повторити повідомлення в черзі",
|
||||
},
|
||||
composer: {
|
||||
placeholder: "Message {name} (Enter to send)",
|
||||
|
||||
52
ui/src/i18n/locales/vi.ts
generated
52
ui/src/i18n/locales/vi.ts
generated
@@ -492,6 +492,32 @@ export const vi: TranslationMap = {
|
||||
},
|
||||
noLinkedSession: "Không có phiên được liên kết",
|
||||
stopSession: "Dừng phiên",
|
||||
editCard: "Chỉnh sửa thẻ",
|
||||
editCardHelp: "Cập nhật siêu dữ liệu hàng đợi và bàn giao phiên.",
|
||||
newCard: "Thẻ mới",
|
||||
newCardHelp: "Đưa công việc vào hàng đợi cho một phiên agent.",
|
||||
deleteCard: "Xóa thẻ",
|
||||
openSession: "Mở phiên",
|
||||
openLinkedSession: "Mở phiên được liên kết",
|
||||
defaultAgent: "Agent mặc định",
|
||||
runEngine: "Chạy {engine}",
|
||||
openEngine: "Mở {engine}",
|
||||
runDefaultAgent: "Chạy agent mặc định",
|
||||
start: "Bắt đầu",
|
||||
live: "trực tiếp",
|
||||
fieldTitle: "Tiêu đề",
|
||||
fieldNotes: "Ghi chú",
|
||||
fieldStatus: "Trạng thái",
|
||||
fieldPriority: "Mức ưu tiên",
|
||||
fieldAgent: "Agent",
|
||||
fieldSession: "Phiên",
|
||||
fieldLabels: "Nhãn",
|
||||
titlePlaceholder: "Tiêu đề thẻ",
|
||||
notesPlaceholder: "Ghi chú, tiêu chí chấp nhận, liên kết",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "Tìm kiếm thẻ",
|
||||
allPriorities: "Tất cả mức ưu tiên",
|
||||
emptyColumn: "Thả công việc vào đây",
|
||||
lifecycleUnlinked: "Không có phiên",
|
||||
lifecycleUnlinkedDetail: "Bắt đầu hoặc liên kết một phiên",
|
||||
lifecycleMissing: "Thiếu phiên",
|
||||
@@ -504,6 +530,32 @@ export const vi: TranslationMap = {
|
||||
lifecycleDoneDetail: "Đã chuyển sang xem xét",
|
||||
lifecycleNeedsReview: "Cần xem xét",
|
||||
lifecycleNeedsReviewDetail: "Lượt chạy đã dừng hoặc thất bại",
|
||||
eventsLabel: "Sự kiện thẻ",
|
||||
eventCreated: "Đã tạo",
|
||||
eventEdited: "Đã chỉnh sửa",
|
||||
eventMoved: "Đã di chuyển",
|
||||
eventMovedTo: "Đã di chuyển đến {status}",
|
||||
eventLinked: "Phiên đã liên kết",
|
||||
eventExecutionUpdated: "Agent đã cập nhật",
|
||||
gameButton: "Trò chơi nhỏ",
|
||||
gameTitle: "Đuổi bắt thẻ",
|
||||
gameStart: "Đến ô khởi chạy.",
|
||||
gameBoundary: "Đã đến ranh giới.",
|
||||
gameBlocked: "Bị chặn.",
|
||||
gameContinue: "Tiếp tục.",
|
||||
gameWin: "Đã vượt qua khởi chạy.",
|
||||
gameMoves: "Lượt đi {count}",
|
||||
gameWins: "Thắng {count}",
|
||||
gameBoard: "Bảng Card Chase",
|
||||
gameControls: "Điều khiển Card Chase",
|
||||
gameAgent: "Tác nhân",
|
||||
gameLaunch: "Khởi chạy",
|
||||
gameBlockedCell: "Bị chặn",
|
||||
gameOpenCell: "Mở",
|
||||
gameMoveUp: "Di chuyển lên",
|
||||
gameMoveLeft: "Di chuyển sang trái",
|
||||
gameMoveDown: "Di chuyển xuống",
|
||||
gameMoveRight: "Di chuyển sang phải",
|
||||
},
|
||||
overview: {
|
||||
access: {
|
||||
|
||||
26
ui/src/i18n/locales/zh-CN.ts
generated
26
ui/src/i18n/locales/zh-CN.ts
generated
@@ -490,6 +490,18 @@ export const zh_CN: TranslationMap = {
|
||||
noLinkedSession: "没有已关联的会话",
|
||||
stopSession: "停止会话",
|
||||
editCard: "编辑卡片",
|
||||
editCardHelp: "更新队列元数据和会话交接。",
|
||||
newCard: "新建卡片",
|
||||
newCardHelp: "为代理会话排队工作。",
|
||||
deleteCard: "删除卡片",
|
||||
openSession: "打开会话",
|
||||
openLinkedSession: "打开关联会话",
|
||||
defaultAgent: "默认代理",
|
||||
runEngine: "运行 {engine}",
|
||||
openEngine: "打开 {engine}",
|
||||
runDefaultAgent: "运行默认代理",
|
||||
start: "开始",
|
||||
live: "实时",
|
||||
fieldTitle: "标题",
|
||||
fieldNotes: "备注",
|
||||
fieldStatus: "状态",
|
||||
@@ -497,7 +509,12 @@ export const zh_CN: TranslationMap = {
|
||||
fieldAgent: "代理",
|
||||
fieldSession: "会话",
|
||||
fieldLabels: "标签",
|
||||
titlePlaceholder: "卡片标题",
|
||||
notesPlaceholder: "备注、验收标准、链接",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "搜索卡片",
|
||||
allPriorities: "所有优先级",
|
||||
emptyColumn: "将工作拖放到此处",
|
||||
lifecycleUnlinked: "无会话",
|
||||
lifecycleUnlinkedDetail: "启动或关联会话",
|
||||
lifecycleMissing: "会话缺失",
|
||||
@@ -510,6 +527,13 @@ export const zh_CN: TranslationMap = {
|
||||
lifecycleDoneDetail: "已移至审核",
|
||||
lifecycleNeedsReview: "需要审核",
|
||||
lifecycleNeedsReviewDetail: "运行已停止或失败",
|
||||
eventsLabel: "卡片事件",
|
||||
eventCreated: "已创建",
|
||||
eventEdited: "已编辑",
|
||||
eventMoved: "已移动",
|
||||
eventMovedTo: "已移至 {status}",
|
||||
eventLinked: "已关联会话",
|
||||
eventExecutionUpdated: "Agent 已更新",
|
||||
gameButton: "迷你游戏",
|
||||
gameTitle: "卡片追逐",
|
||||
gameStart: "到达发布图块。",
|
||||
@@ -1153,7 +1177,7 @@ export const zh_CN: TranslationMap = {
|
||||
queue: {
|
||||
retry: "重试",
|
||||
retrySend: "重试发送",
|
||||
retryQueuedMessage: "重试队列中的消息",
|
||||
retryQueuedMessage: "重试排队消息",
|
||||
},
|
||||
composer: {
|
||||
placeholder: "给 {name} 发消息(Enter 发送)",
|
||||
|
||||
26
ui/src/i18n/locales/zh-TW.ts
generated
26
ui/src/i18n/locales/zh-TW.ts
generated
@@ -490,6 +490,18 @@ export const zh_TW: TranslationMap = {
|
||||
noLinkedSession: "沒有已連結的工作階段",
|
||||
stopSession: "停止工作階段",
|
||||
editCard: "編輯卡片",
|
||||
editCardHelp: "更新佇列中繼資料與工作階段交接。",
|
||||
newCard: "新增卡片",
|
||||
newCardHelp: "為代理程式工作階段排入工作。",
|
||||
deleteCard: "刪除卡片",
|
||||
openSession: "開啟工作階段",
|
||||
openLinkedSession: "開啟連結的工作階段",
|
||||
defaultAgent: "預設代理程式",
|
||||
runEngine: "執行 {engine}",
|
||||
openEngine: "開啟 {engine}",
|
||||
runDefaultAgent: "執行預設代理程式",
|
||||
start: "開始",
|
||||
live: "即時",
|
||||
fieldTitle: "標題",
|
||||
fieldNotes: "備註",
|
||||
fieldStatus: "狀態",
|
||||
@@ -497,7 +509,12 @@ export const zh_TW: TranslationMap = {
|
||||
fieldAgent: "代理",
|
||||
fieldSession: "工作階段",
|
||||
fieldLabels: "標籤",
|
||||
titlePlaceholder: "卡片標題",
|
||||
notesPlaceholder: "備註、驗收標準、連結",
|
||||
labelsPlaceholder: "ui, docs",
|
||||
searchPlaceholder: "搜尋卡片",
|
||||
allPriorities: "所有優先順序",
|
||||
emptyColumn: "將工作拖放到這裡",
|
||||
lifecycleUnlinked: "沒有工作階段",
|
||||
lifecycleUnlinkedDetail: "開始或連結工作階段",
|
||||
lifecycleMissing: "找不到工作階段",
|
||||
@@ -510,6 +527,13 @@ export const zh_TW: TranslationMap = {
|
||||
lifecycleDoneDetail: "已移至審查",
|
||||
lifecycleNeedsReview: "需要審查",
|
||||
lifecycleNeedsReviewDetail: "執行已停止或失敗",
|
||||
eventsLabel: "卡片事件",
|
||||
eventCreated: "已建立",
|
||||
eventEdited: "已編輯",
|
||||
eventMoved: "已移動",
|
||||
eventMovedTo: "已移動至 {status}",
|
||||
eventLinked: "已連結工作階段",
|
||||
eventExecutionUpdated: "代理程式已更新",
|
||||
gameButton: "小遊戲",
|
||||
gameTitle: "卡片追逐",
|
||||
gameStart: "到達啟動方格。",
|
||||
@@ -1154,7 +1178,7 @@ export const zh_TW: TranslationMap = {
|
||||
},
|
||||
queue: {
|
||||
retry: "重試",
|
||||
retrySend: "重試傳送",
|
||||
retrySend: "重新傳送",
|
||||
retryQueuedMessage: "重試佇列中的訊息",
|
||||
},
|
||||
composer: {
|
||||
|
||||
@@ -533,6 +533,37 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.workboard-events {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
margin: 0;
|
||||
padding: 7px 0 0;
|
||||
border-top: 1px solid color-mix(in srgb, var(--border) 62%, transparent);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.workboard-events li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
color: var(--muted);
|
||||
font-size: 0.72rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.workboard-events span {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.workboard-events time {
|
||||
flex: 0 0 auto;
|
||||
color: color-mix(in srgb, var(--muted) 72%, transparent);
|
||||
}
|
||||
|
||||
.workboard-lifecycle {
|
||||
flex: 0 0 auto;
|
||||
border-radius: 6px;
|
||||
|
||||
@@ -2044,6 +2044,10 @@ export function renderApp(state: AppViewState) {
|
||||
enabledByDefault: false,
|
||||
},
|
||||
);
|
||||
const operatorCanWrite = hasOperatorWriteAccess(
|
||||
(state.hello as { auth?: { role?: string; scopes?: string[] } } | null)?.auth ??
|
||||
null,
|
||||
);
|
||||
return m.renderSessions({
|
||||
loading: state.sessionsLoading,
|
||||
result: state.sessionsResult,
|
||||
@@ -2064,7 +2068,7 @@ export function renderApp(state: AppViewState) {
|
||||
selectedKeys: state.sessionsSelectedKeys,
|
||||
workboardSessionKeys: new Set(
|
||||
workboardState.cards
|
||||
.map((card) => card.sessionKey)
|
||||
.flatMap((card) => [card.sessionKey, card.execution?.sessionKey])
|
||||
.filter((key): key is string => typeof key === "string" && key.length > 0),
|
||||
),
|
||||
workboardBusySessionKey: [...workboardState.capturingSessionKeys][0] ?? null,
|
||||
@@ -2168,17 +2172,18 @@ export function renderApp(state: AppViewState) {
|
||||
switchChatSession(state, sessionKey);
|
||||
state.setTab("chat" as import("./navigation.ts").Tab);
|
||||
},
|
||||
onAddToWorkboard: workboardEnabled
|
||||
? async (session) => {
|
||||
await captureSessionToWorkboard({
|
||||
host: state,
|
||||
client: state.client,
|
||||
session,
|
||||
requestUpdate: requestHostUpdate,
|
||||
});
|
||||
state.setTab("workboard" as import("./navigation.ts").Tab);
|
||||
}
|
||||
: undefined,
|
||||
onAddToWorkboard:
|
||||
workboardEnabled && operatorCanWrite
|
||||
? async (session) => {
|
||||
await captureSessionToWorkboard({
|
||||
host: state,
|
||||
client: state.client,
|
||||
session,
|
||||
requestUpdate: requestHostUpdate,
|
||||
});
|
||||
state.setTab("workboard" as import("./navigation.ts").Tab);
|
||||
}
|
||||
: undefined,
|
||||
onToggleCheckpointDetails: (sessionKey) =>
|
||||
toggleSessionCompactionCheckpoints(state, sessionKey),
|
||||
onBranchFromCheckpoint: async (sessionKey, checkpointId) => {
|
||||
|
||||
@@ -204,7 +204,20 @@ describe("workboard controller", () => {
|
||||
it("does not duplicate existing captured sessions", async () => {
|
||||
const host = {};
|
||||
const state = getWorkboardState(host);
|
||||
const existing = { ...sampleCard, sessionKey: sampleSession.key };
|
||||
const existing = {
|
||||
...sampleCard,
|
||||
execution: {
|
||||
id: "exec-1",
|
||||
kind: "agent-session",
|
||||
engine: "codex",
|
||||
mode: "autonomous",
|
||||
status: "running",
|
||||
model: "openai/gpt-5.5",
|
||||
sessionKey: sampleSession.key,
|
||||
startedAt: 1,
|
||||
updatedAt: 1,
|
||||
},
|
||||
} satisfies WorkboardCard;
|
||||
state.loaded = true;
|
||||
state.cards = [existing];
|
||||
const client = createClient({});
|
||||
@@ -223,6 +236,8 @@ describe("workboard controller", () => {
|
||||
const host = {};
|
||||
const state = getWorkboardState(host);
|
||||
state.capturingSessionKeys.add(sampleSession.key);
|
||||
const existing = { ...sampleCard, sessionKey: sampleSession.key };
|
||||
state.cards = [existing];
|
||||
const client = createClient({});
|
||||
|
||||
const card = await captureSessionToWorkboard({
|
||||
@@ -231,7 +246,7 @@ describe("workboard controller", () => {
|
||||
session: sampleSession,
|
||||
});
|
||||
|
||||
expect(card).toBeNull();
|
||||
expect(card).toBe(existing);
|
||||
expect(client.request).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -537,6 +552,12 @@ describe("workboard controller", () => {
|
||||
state: "running",
|
||||
targetStatus: "running",
|
||||
});
|
||||
expect(
|
||||
getWorkboardLifecycle(linked, [{ ...sampleSession, hasActiveRun: false, status: "running" }]),
|
||||
).toMatchObject({
|
||||
state: "running",
|
||||
targetStatus: "running",
|
||||
});
|
||||
expect(
|
||||
getWorkboardLifecycle(linked, [{ ...sampleSession, hasActiveRun: false, status: "done" }]),
|
||||
).toMatchObject({
|
||||
|
||||
@@ -20,6 +20,13 @@ export const WORKBOARD_EXECUTION_STATUSES = [
|
||||
"blocked",
|
||||
"done",
|
||||
] as const;
|
||||
export const WORKBOARD_EVENT_KINDS = [
|
||||
"created",
|
||||
"edited",
|
||||
"moved",
|
||||
"linked",
|
||||
"execution_updated",
|
||||
] as const;
|
||||
|
||||
export const WORKBOARD_ENGINE_MODELS = {
|
||||
codex: "openai/gpt-5.5",
|
||||
@@ -31,6 +38,7 @@ export type WorkboardPriority = (typeof WORKBOARD_PRIORITIES)[number];
|
||||
export type WorkboardExecutionEngine = (typeof WORKBOARD_EXECUTION_ENGINES)[number];
|
||||
export type WorkboardExecutionMode = (typeof WORKBOARD_EXECUTION_MODES)[number];
|
||||
export type WorkboardExecutionStatus = (typeof WORKBOARD_EXECUTION_STATUSES)[number];
|
||||
export type WorkboardEventKind = (typeof WORKBOARD_EVENT_KINDS)[number];
|
||||
|
||||
export type WorkboardExecution = {
|
||||
id: string;
|
||||
@@ -45,6 +53,16 @@ export type WorkboardExecution = {
|
||||
updatedAt: number;
|
||||
};
|
||||
|
||||
export type WorkboardEvent = {
|
||||
id: string;
|
||||
kind: WorkboardEventKind;
|
||||
at: number;
|
||||
fromStatus?: WorkboardStatus;
|
||||
toStatus?: WorkboardStatus;
|
||||
sessionKey?: string;
|
||||
runId?: string;
|
||||
};
|
||||
|
||||
export type WorkboardCard = {
|
||||
id: string;
|
||||
title: string;
|
||||
@@ -63,6 +81,7 @@ export type WorkboardCard = {
|
||||
updatedAt: number;
|
||||
startedAt?: number;
|
||||
completedAt?: number;
|
||||
events?: WorkboardEvent[];
|
||||
};
|
||||
|
||||
export type WorkboardLifecycleState =
|
||||
@@ -209,6 +228,41 @@ function normalizeExecution(value: unknown): WorkboardExecution | undefined {
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeEvent(value: unknown): WorkboardEvent | null {
|
||||
if (!isRecord(value)) {
|
||||
return null;
|
||||
}
|
||||
const id = typeof value.id === "string" && value.id.trim() ? value.id.trim() : "";
|
||||
const kind = WORKBOARD_EVENT_KINDS.includes(value.kind as WorkboardEventKind)
|
||||
? (value.kind as WorkboardEventKind)
|
||||
: null;
|
||||
const at = typeof value.at === "number" && Number.isFinite(value.at) ? value.at : 0;
|
||||
if (!id || !kind || !at) {
|
||||
return null;
|
||||
}
|
||||
const fromStatus = WORKBOARD_STATUSES.includes(value.fromStatus as WorkboardStatus)
|
||||
? (value.fromStatus as WorkboardStatus)
|
||||
: undefined;
|
||||
const toStatus = WORKBOARD_STATUSES.includes(value.toStatus as WorkboardStatus)
|
||||
? (value.toStatus as WorkboardStatus)
|
||||
: undefined;
|
||||
return {
|
||||
id,
|
||||
kind,
|
||||
at,
|
||||
...(fromStatus ? { fromStatus } : {}),
|
||||
...(toStatus ? { toStatus } : {}),
|
||||
...(typeof value.sessionKey === "string" ? { sessionKey: value.sessionKey } : {}),
|
||||
...(typeof value.runId === "string" ? { runId: value.runId } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeEvents(value: unknown): WorkboardEvent[] {
|
||||
return Array.isArray(value)
|
||||
? value.map(normalizeEvent).filter((event): event is WorkboardEvent => event !== null)
|
||||
: [];
|
||||
}
|
||||
|
||||
function normalizeCard(value: unknown): WorkboardCard | null {
|
||||
if (!isRecord(value)) {
|
||||
return null;
|
||||
@@ -225,6 +279,7 @@ function normalizeCard(value: unknown): WorkboardCard | null {
|
||||
return null;
|
||||
}
|
||||
const execution = normalizeExecution(value.execution);
|
||||
const events = normalizeEvents(value.events);
|
||||
return {
|
||||
id,
|
||||
title,
|
||||
@@ -245,6 +300,7 @@ function normalizeCard(value: unknown): WorkboardCard | null {
|
||||
...(execution ? { execution } : {}),
|
||||
...(typeof value.startedAt === "number" ? { startedAt: value.startedAt } : {}),
|
||||
...(typeof value.completedAt === "number" ? { completedAt: value.completedAt } : {}),
|
||||
...(events.length ? { events } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -422,6 +478,7 @@ function executionStatusForLifecycle(
|
||||
case "unlinked":
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function shouldSyncExecutionStatus(
|
||||
@@ -584,7 +641,7 @@ export async function captureSessionToWorkboard(params: {
|
||||
return null;
|
||||
}
|
||||
if (state.capturingSessionKeys.has(params.session.key)) {
|
||||
return state.cards.find((card) => card.sessionKey === params.session.key) ?? null;
|
||||
return state.cards.find((card) => workboardCardSessionKey(card) === params.session.key) ?? null;
|
||||
}
|
||||
state.error = null;
|
||||
state.capturingSessionKeys.add(params.session.key);
|
||||
@@ -601,7 +658,9 @@ export async function captureSessionToWorkboard(params: {
|
||||
if (!state.loaded) {
|
||||
return null;
|
||||
}
|
||||
const existing = state.cards.find((card) => card.sessionKey === params.session.key);
|
||||
const existing = state.cards.find(
|
||||
(card) => workboardCardSessionKey(card) === params.session.key,
|
||||
);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
@@ -160,6 +160,83 @@ describe("renderWorkboard", () => {
|
||||
expect(container.querySelector(".workboard-card")?.getAttribute("role")).toBeNull();
|
||||
});
|
||||
|
||||
it("hides write controls for read-only operators", () => {
|
||||
const host = {};
|
||||
const state = getWorkboardState(host);
|
||||
state.loaded = true;
|
||||
state.cards = [
|
||||
{
|
||||
id: "card-1",
|
||||
title: "Inspect only",
|
||||
status: "todo",
|
||||
priority: "normal",
|
||||
labels: [],
|
||||
position: 1000,
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
},
|
||||
];
|
||||
const container = document.createElement("div");
|
||||
|
||||
render(
|
||||
renderWorkboard({
|
||||
host,
|
||||
client: null,
|
||||
connected: true,
|
||||
canWrite: false,
|
||||
pluginEnabled: true,
|
||||
agentsList: null,
|
||||
sessions: [],
|
||||
onOpenSession: () => undefined,
|
||||
}),
|
||||
container,
|
||||
);
|
||||
|
||||
expect(container.querySelector<HTMLButtonElement>('button[title="Edit card"]')).toBeNull();
|
||||
expect(container.querySelector<HTMLButtonElement>('button[title="Delete card"]')).toBeNull();
|
||||
expect(container.querySelectorAll<HTMLButtonElement>(".workboard-card__start")).toHaveLength(0);
|
||||
expect(
|
||||
container.querySelector<HTMLButtonElement>(".workboard-toolbar__actions .btn.primary"),
|
||||
).toBeNull();
|
||||
expect(container.querySelector(".workboard-card")?.getAttribute("draggable")).toBe("false");
|
||||
});
|
||||
|
||||
it("offers start controls when a linked session no longer exists", () => {
|
||||
const host = {};
|
||||
const state = getWorkboardState(host);
|
||||
state.loaded = true;
|
||||
state.cards = [
|
||||
{
|
||||
id: "card-1",
|
||||
title: "Restart this",
|
||||
status: "blocked",
|
||||
priority: "normal",
|
||||
labels: [],
|
||||
position: 1000,
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
sessionKey: "agent:main:missing:1",
|
||||
},
|
||||
];
|
||||
const container = document.createElement("div");
|
||||
|
||||
render(
|
||||
renderWorkboard({
|
||||
host,
|
||||
client: null,
|
||||
connected: true,
|
||||
pluginEnabled: true,
|
||||
agentsList: null,
|
||||
sessions: [],
|
||||
onOpenSession: () => undefined,
|
||||
}),
|
||||
container,
|
||||
);
|
||||
|
||||
expect(container.textContent).toContain("Session missing");
|
||||
expect(container.querySelectorAll<HTMLButtonElement>(".workboard-card__start")).toHaveLength(5);
|
||||
});
|
||||
|
||||
it("opens a modal for new cards", () => {
|
||||
const host = {};
|
||||
getWorkboardState(host).loaded = true;
|
||||
@@ -231,6 +308,44 @@ describe("renderWorkboard", () => {
|
||||
expect(container.querySelector(".workboard-game__stats")?.textContent).toContain("Moves 1");
|
||||
});
|
||||
|
||||
it("renders card event history", () => {
|
||||
const host = {};
|
||||
const state = getWorkboardState(host);
|
||||
state.loaded = true;
|
||||
state.cards = [
|
||||
{
|
||||
id: "card-1",
|
||||
title: "Tracked task",
|
||||
status: "review",
|
||||
priority: "normal",
|
||||
labels: [],
|
||||
position: 1000,
|
||||
createdAt: 1,
|
||||
updatedAt: 2,
|
||||
events: [
|
||||
{ id: "event-1", kind: "created", at: 1, toStatus: "todo" },
|
||||
{ id: "event-2", kind: "moved", at: 2, fromStatus: "todo", toStatus: "review" },
|
||||
],
|
||||
},
|
||||
];
|
||||
const container = document.createElement("div");
|
||||
|
||||
render(
|
||||
renderWorkboard({
|
||||
host,
|
||||
client: null,
|
||||
connected: true,
|
||||
pluginEnabled: true,
|
||||
agentsList: null,
|
||||
sessions: [],
|
||||
onOpenSession: () => undefined,
|
||||
}),
|
||||
container,
|
||||
);
|
||||
|
||||
expect(container.querySelector(".workboard-events")?.textContent).toContain("Moved to Review");
|
||||
});
|
||||
|
||||
it("opens an edit modal and submits card updates", async () => {
|
||||
const host = {};
|
||||
const state = getWorkboardState(host);
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
type WorkboardExecutionEngine,
|
||||
type WorkboardExecutionMode,
|
||||
type WorkboardCard,
|
||||
type WorkboardEvent,
|
||||
type WorkboardLifecycle,
|
||||
type WorkboardPriority,
|
||||
type WorkboardStatus,
|
||||
@@ -54,6 +55,47 @@ function formatTime(value: number | undefined): string {
|
||||
});
|
||||
}
|
||||
|
||||
function canMutate(props: WorkboardProps): boolean {
|
||||
return props.canWrite !== false;
|
||||
}
|
||||
|
||||
function formatEventLabel(event: WorkboardEvent): string {
|
||||
switch (event.kind) {
|
||||
case "created":
|
||||
return t("workboard.eventCreated");
|
||||
case "edited":
|
||||
return t("workboard.eventEdited");
|
||||
case "moved":
|
||||
return event.toStatus
|
||||
? t("workboard.eventMovedTo", { status: formatStatusLabel(event.toStatus) })
|
||||
: t("workboard.eventMoved");
|
||||
case "linked":
|
||||
return t("workboard.eventLinked");
|
||||
case "execution_updated":
|
||||
return t("workboard.eventExecutionUpdated");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function renderEvents(card: WorkboardCard) {
|
||||
const events = (card.events ?? []).toReversed().slice(0, 4);
|
||||
if (events.length === 0) {
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<ol class="workboard-events" aria-label=${t("workboard.eventsLabel")}>
|
||||
${events.map(
|
||||
(event) => html`
|
||||
<li>
|
||||
<span>${formatEventLabel(event)}</span>
|
||||
<time>${formatTime(event.at)}</time>
|
||||
</li>
|
||||
`,
|
||||
)}
|
||||
</ol>
|
||||
`;
|
||||
}
|
||||
|
||||
function matchesFilter(
|
||||
card: WorkboardCard,
|
||||
options: { query: string; priority: "all" | WorkboardPriority },
|
||||
@@ -347,12 +389,10 @@ function renderCardModal(props: WorkboardProps) {
|
||||
>
|
||||
<div class="workboard-modal__header">
|
||||
<div>
|
||||
<h2 id="workboard-card-modal-title">${editing ? "Edit card" : "New card"}</h2>
|
||||
<p>
|
||||
${editing
|
||||
? "Update queue metadata and session handoff."
|
||||
: "Queue work for an agent session."}
|
||||
</p>
|
||||
<h2 id="workboard-card-modal-title">
|
||||
${editing ? t("workboard.editCard") : t("workboard.newCard")}
|
||||
</h2>
|
||||
<p>${editing ? t("workboard.editCardHelp") : t("workboard.newCardHelp")}</p>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn--icon workboard-card__icon"
|
||||
@@ -371,7 +411,7 @@ function renderCardModal(props: WorkboardProps) {
|
||||
<span>${t("workboard.fieldTitle")}</span>
|
||||
<input
|
||||
class="input workboard-draft__title"
|
||||
placeholder="Card title"
|
||||
placeholder=${t("workboard.titlePlaceholder")}
|
||||
.value=${state.draftTitle}
|
||||
@input=${(event: InputEvent) => {
|
||||
state.draftTitle = (event.currentTarget as HTMLInputElement).value;
|
||||
@@ -383,7 +423,7 @@ function renderCardModal(props: WorkboardProps) {
|
||||
<span>${t("workboard.fieldNotes")}</span>
|
||||
<textarea
|
||||
class="input workboard-draft__notes"
|
||||
placeholder="Notes, acceptance criteria, links"
|
||||
placeholder=${t("workboard.notesPlaceholder")}
|
||||
.value=${state.draftNotes}
|
||||
@input=${(event: InputEvent) => {
|
||||
state.draftNotes = (event.currentTarget as HTMLTextAreaElement).value;
|
||||
@@ -435,7 +475,7 @@ function renderCardModal(props: WorkboardProps) {
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
<option value="">Default agent</option>
|
||||
<option value="">${t("workboard.defaultAgent")}</option>
|
||||
${agents.map(
|
||||
(agent) =>
|
||||
html`<option value=${agent.id}>
|
||||
@@ -568,8 +608,10 @@ function renderStartExecutionButton(
|
||||
const state = getWorkboardState(props.host);
|
||||
const busy = state.busyCardId === card.id;
|
||||
const title = engine
|
||||
? `${mode === "autonomous" ? "Run" : "Open"} ${engine}`
|
||||
: "Run default agent";
|
||||
? mode === "autonomous"
|
||||
? t("workboard.runEngine", { engine })
|
||||
: t("workboard.openEngine", { engine })
|
||||
: t("workboard.runDefaultAgent");
|
||||
return html`
|
||||
<button
|
||||
class="btn btn--xs workboard-card__start workboard-card__start--${mode} ${engine
|
||||
@@ -591,7 +633,7 @@ function renderStartExecutionButton(
|
||||
}
|
||||
}}
|
||||
>
|
||||
${mode === "autonomous" ? icons.play : icons.penLine} ${engine ?? "Start"}
|
||||
${mode === "autonomous" ? icons.play : icons.penLine} ${engine ?? t("workboard.start")}
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
@@ -613,9 +655,11 @@ function renderCard(props: WorkboardProps, card: WorkboardCard) {
|
||||
const session = findWorkboardSession(card, props.sessions);
|
||||
const busy = state.busyCardId === card.id;
|
||||
const syncing = state.syncingCardIds.has(card.id);
|
||||
const live = session?.hasActiveRun === true;
|
||||
const live = session?.hasActiveRun === true || session?.status === "running";
|
||||
const linkedSessionKey = card.sessionKey ?? card.execution?.sessionKey;
|
||||
const linked = Boolean(linkedSessionKey);
|
||||
const writable = canMutate(props);
|
||||
const showStartControls = writable && (!linked || !session);
|
||||
return html`
|
||||
<article
|
||||
class="workboard-card priority-${card.priority} ${busy ? "workboard-card--busy" : ""} ${linked
|
||||
@@ -623,8 +667,8 @@ function renderCard(props: WorkboardProps, card: WorkboardCard) {
|
||||
: ""}"
|
||||
role=${linked ? "button" : nothing}
|
||||
tabindex=${linked ? 0 : nothing}
|
||||
title=${linked ? "Open linked session" : nothing}
|
||||
draggable="true"
|
||||
title=${linked ? t("workboard.openLinkedSession") : nothing}
|
||||
draggable=${writable ? "true" : "false"}
|
||||
@click=${(event: MouseEvent) => {
|
||||
if (!isCardActionTarget(event)) {
|
||||
openCardSession(props, card);
|
||||
@@ -639,6 +683,10 @@ function renderCard(props: WorkboardProps, card: WorkboardCard) {
|
||||
}
|
||||
}}
|
||||
@dragstart=${(event: DragEvent) => {
|
||||
if (!writable) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
state.draggedCardId = card.id;
|
||||
event.dataTransfer?.setData("text/plain", card.id);
|
||||
event.dataTransfer?.setDragImage(event.currentTarget as Element, 16, 16);
|
||||
@@ -651,7 +699,7 @@ function renderCard(props: WorkboardProps, card: WorkboardCard) {
|
||||
>
|
||||
<div class="workboard-card__top">
|
||||
<span class="workboard-card__priority">${card.priority}</span>
|
||||
${live ? html`<span class="workboard-live">live</span>` : nothing}
|
||||
${live ? html`<span class="workboard-live">${t("workboard.live")}</span>` : nothing}
|
||||
${syncing ? html`<span class="workboard-live">${t("common.saving")}</span>` : nothing}
|
||||
</div>
|
||||
<h3>${card.title}</h3>
|
||||
@@ -662,30 +710,37 @@ function renderCard(props: WorkboardProps, card: WorkboardCard) {
|
||||
</div>`
|
||||
: nothing}
|
||||
<div class="workboard-card__meta">
|
||||
${card.agentId ? html`<span>${card.agentId}</span>` : html`<span>default agent</span>`}
|
||||
${card.agentId
|
||||
? html`<span>${card.agentId}</span>`
|
||||
: html`<span>${t("workboard.defaultAgent")}</span>`}
|
||||
<span>${formatTime(card.updatedAt)}</span>
|
||||
</div>
|
||||
${renderEvents(card)}
|
||||
<div class="workboard-card__actions">
|
||||
<button
|
||||
class="btn btn--icon workboard-card__icon"
|
||||
title=${t("workboard.editCard")}
|
||||
@click=${() => {
|
||||
openEditModal(state, card);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
${icons.edit}
|
||||
</button>
|
||||
${writable
|
||||
? html`
|
||||
<button
|
||||
class="btn btn--icon workboard-card__icon"
|
||||
title=${t("workboard.editCard")}
|
||||
@click=${() => {
|
||||
openEditModal(state, card);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
${icons.edit}
|
||||
</button>
|
||||
`
|
||||
: nothing}
|
||||
${linked
|
||||
? html`
|
||||
<button
|
||||
class="btn btn--icon workboard-card__icon"
|
||||
title="Open session"
|
||||
title=${t("workboard.openSession")}
|
||||
@click=${() => props.onOpenSession(linkedSessionKey!)}
|
||||
>
|
||||
${icons.messageSquare}
|
||||
</button>
|
||||
${live
|
||||
${writable && live
|
||||
? html`
|
||||
<button
|
||||
class="btn btn--icon workboard-card__icon"
|
||||
@@ -704,21 +759,26 @@ function renderCard(props: WorkboardProps, card: WorkboardCard) {
|
||||
`
|
||||
: nothing}
|
||||
`
|
||||
: renderStartExecutionControls(props, card)}
|
||||
<button
|
||||
class="btn btn--icon workboard-card__icon workboard-card__delete"
|
||||
title="Delete card"
|
||||
?disabled=${busy}
|
||||
@click=${() =>
|
||||
deleteWorkboardCard({
|
||||
host: props.host,
|
||||
client: props.client,
|
||||
cardId: card.id,
|
||||
requestUpdate: props.onRequestUpdate,
|
||||
})}
|
||||
>
|
||||
${icons.trash}
|
||||
</button>
|
||||
: nothing}
|
||||
${showStartControls ? renderStartExecutionControls(props, card) : nothing}
|
||||
${writable
|
||||
? html`
|
||||
<button
|
||||
class="btn btn--icon workboard-card__icon workboard-card__delete"
|
||||
title=${t("workboard.deleteCard")}
|
||||
?disabled=${busy}
|
||||
@click=${() =>
|
||||
deleteWorkboardCard({
|
||||
host: props.host,
|
||||
client: props.client,
|
||||
cardId: card.id,
|
||||
requestUpdate: props.onRequestUpdate,
|
||||
})}
|
||||
>
|
||||
${icons.trash}
|
||||
</button>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
</article>
|
||||
`;
|
||||
@@ -726,16 +786,20 @@ function renderCard(props: WorkboardProps, card: WorkboardCard) {
|
||||
|
||||
function renderColumn(props: WorkboardProps, status: WorkboardStatus, cards: WorkboardCard[]) {
|
||||
const state = getWorkboardState(props.host);
|
||||
const writable = canMutate(props);
|
||||
return html`
|
||||
<section
|
||||
class="workboard-column ${state.draggedCardId ? "workboard-column--drop" : ""}"
|
||||
@dragover=${(event: DragEvent) => {
|
||||
if (state.draggedCardId) {
|
||||
if (writable && state.draggedCardId) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}}
|
||||
@drop=${(event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
if (!writable) {
|
||||
return;
|
||||
}
|
||||
const cardId = event.dataTransfer?.getData("text/plain") || state.draggedCardId;
|
||||
if (!cardId) {
|
||||
return;
|
||||
@@ -757,7 +821,7 @@ function renderColumn(props: WorkboardProps, status: WorkboardStatus, cards: Wor
|
||||
<div class="workboard-column__cards">
|
||||
${cards.length
|
||||
? cards.map((card) => renderCard(props, card))
|
||||
: html`<div class="workboard-empty">Drop work here</div>`}
|
||||
: html`<div class="workboard-empty">${t("workboard.emptyColumn")}</div>`}
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
@@ -794,6 +858,7 @@ export function renderWorkboard(props: WorkboardProps) {
|
||||
const filtered = state.cards.filter((card) =>
|
||||
matchesFilter(card, { query: state.query, priority: state.priorityFilter }),
|
||||
);
|
||||
const writable = canMutate(props);
|
||||
const byStatus = new Map<WorkboardStatus, WorkboardCard[]>();
|
||||
for (const status of state.statuses) {
|
||||
byStatus.set(status, []);
|
||||
@@ -809,7 +874,7 @@ export function renderWorkboard(props: WorkboardProps) {
|
||||
<input
|
||||
class="input"
|
||||
type="search"
|
||||
placeholder="Search cards"
|
||||
placeholder=${t("workboard.searchPlaceholder")}
|
||||
.value=${state.query}
|
||||
@input=${(event: InputEvent) => {
|
||||
state.query = (event.currentTarget as HTMLInputElement).value;
|
||||
@@ -825,7 +890,7 @@ export function renderWorkboard(props: WorkboardProps) {
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
<option value="all">All priorities</option>
|
||||
<option value="all">${t("workboard.allPriorities")}</option>
|
||||
${WORKBOARD_PRIORITIES.map(
|
||||
(priority) => html`<option value=${priority}>${priority}</option>`,
|
||||
)}
|
||||
@@ -854,15 +919,19 @@ export function renderWorkboard(props: WorkboardProps) {
|
||||
>
|
||||
${icons.play} ${t("workboard.gameButton")}
|
||||
</button>
|
||||
<button
|
||||
class="btn primary"
|
||||
@click=${() => {
|
||||
openCreateModal(state);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
${icons.plus} New card
|
||||
</button>
|
||||
${writable
|
||||
? html`
|
||||
<button
|
||||
class="btn primary"
|
||||
@click=${() => {
|
||||
openCreateModal(state);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
${icons.plus} ${t("workboard.newCard")}
|
||||
</button>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
</div>
|
||||
${state.error ? html`<div class="callout danger">${state.error}</div>` : nothing}
|
||||
|
||||
Reference in New Issue
Block a user