Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions apps/presentation/dashboard/smoke/projection-localization-smoke.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
agentStatusSentence,
projectionSentence,
runEvidenceCopy,
} from "../src/features/personal-workspace/projection-localization.js";

type Values = Record<string, string | number>;
Expand All @@ -14,19 +13,11 @@ const english = {
"projection.agentStopped": "Stopped by you; history, Todos, and evidence are preserved",
"projection.agentWaitingExternal": "Waiting for an external condition",
"projection.confirmAgentDecision": "Confirm the permission or decision the Agent needs next",
"projection.events24h": "{count} events in the last 24 hours",
"projection.firstReadOnlyAdapterCheck": "Run the first read-only adapter check and save progress",
"projection.goalVerified": "Goal state, Todos, and registration information verified",
"projection.latestRun": "Latest run",
"projection.latestValidation": "Latest validation",
"projection.nextUpdatePending": "Waiting for LoopX to update the next step",
"projection.publicSafeProjection": "Public-safe status projection",
"projection.refreshState": "Refresh LoopX status and confirm the current progress is still valid",
"projection.runEvidenceAvailable": "Run evidence is available",
"projection.runRecorded": "The latest LoopX run is recorded",
"projection.statusRefreshNeeded": "LoopX status needs to be refreshed",
"projection.todoStatusUpdated": "Todo status updated; confirming the next step",
"projection.validationRecorded": "The latest validation is recorded",
} as const;

const chinese = {
Expand Down Expand Up @@ -97,16 +88,4 @@ equal(
"English stopped status",
);

const latestRun = runEvidenceCopy({ eventCount: 0, hasArtifact: true, hasLatestValidation: false }, en);
equal(latestRun.label, "Latest run", "English latest-run label");
equal(latestRun.metadata, "Run evidence is available", "English run-evidence metadata");

const latestValidation = runEvidenceCopy({ eventCount: 3, hasArtifact: false, hasLatestValidation: true }, en);
equal(latestValidation.label, "Latest validation", "English latest-validation label");
equal(latestValidation.metadata, "3 events in the last 24 hours", "English event-count metadata");

const chineseRun = runEvidenceCopy({ eventCount: 0, hasArtifact: false, hasLatestValidation: false }, zhCN);
equal(chineseRun.label, "最近运行", "Chinese latest-run label");
equal(chineseRun.metadata, "公开安全状态投影", "Chinese public-safe metadata");

console.log("projection localization smoke passed");
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ const en = {
"drawer.unconfigured": "Not configured",
"drawer.workspaceCandidates": "Available workspaces",
"files.emptySummary": "Public-safe output",
"files.empty": "No files, outputs, or verified reports yet.",
"files.empty": "No delivered files or verified reports yet. Run and validation status remain in Tasks.",
"files.checkingTeam": "Checking this Goal conversation for verified team results…",
"files.teamLoadFailed": "Could not check team results from this Goal conversation.",
"files.loadingReports": "Loading verified milestone reports…",
"files.reportDelta": "+{added} added · {changed} changed",
"files.reportAdded": "added",
Expand Down Expand Up @@ -763,19 +765,11 @@ const en = {
"projection.agentStopped": "Stopped by you; history, Todos, and evidence are preserved",
"projection.agentWaitingExternal": "Waiting for an external condition",
"projection.confirmAgentDecision": "Confirm the permission or decision the Agent needs next",
"projection.events24h": "{count} events in the last 24 hours",
"projection.firstReadOnlyAdapterCheck": "Run the first read-only adapter check and save progress",
"projection.goalVerified": "Goal state, Todos, and registration information verified",
"projection.latestRun": "Latest run",
"projection.latestValidation": "Latest validation",
"projection.nextUpdatePending": "Waiting for LoopX to update the next step",
"projection.publicSafeProjection": "Public-safe status projection",
"projection.refreshState": "Refresh LoopX status and confirm the current progress is still valid",
"projection.runEvidenceAvailable": "Run evidence is available",
"projection.runRecorded": "The latest LoopX run is recorded",
"projection.statusRefreshNeeded": "LoopX status needs to be refreshed",
"projection.todoStatusUpdated": "Todo status updated; confirming the next step",
"projection.validationRecorded": "The latest validation is recorded",
"runs.completed": "Completed",
"runs.failed": "Needs review",
"runs.interrupted": "Interrupted",
Expand Down Expand Up @@ -1477,7 +1471,9 @@ const zhCN: Record<WorkspaceMessageKey, string> = {
"drawer.unconfigured": "未配置",
"drawer.workspaceCandidates": "可选择的工作区",
"files.emptySummary": "公开安全产出",
"files.empty": "还没有文件、产出或已验证的阶段周报。",
"files.empty": "还没有已交付文件或已验证报告。运行和验证状态请在任务中查看。",
"files.checkingTeam": "正在检查当前 Goal 会话的已验证团队成果…",
"files.teamLoadFailed": "无法核验当前 Goal 会话的团队成果。",
"files.loadingReports": "正在加载已验证的阶段周报…",
"files.reportDelta": "+{added} 新增 · {changed} 变化",
"files.reportAdded": "新增",
Expand Down Expand Up @@ -1851,19 +1847,11 @@ const zhCN: Record<WorkspaceMessageKey, string> = {
"projection.agentStopped": "已由你停止;历史、Todo 和证据仍保留",
"projection.agentWaitingExternal": "正在等待外部条件",
"projection.confirmAgentDecision": "请确认 Agent 下一步需要的权限或决策",
"projection.events24h": "24 小时内 {count} 个事件",
"projection.firstReadOnlyAdapterCheck": "执行首次只读适配检查并保存进度",
"projection.goalVerified": "Goal 状态、Todo 与注册信息已验证",
"projection.latestRun": "最近运行",
"projection.latestValidation": "最近验证",
"projection.nextUpdatePending": "等待 LoopX 更新下一步",
"projection.publicSafeProjection": "公开安全状态投影",
"projection.refreshState": "刷新 LoopX 状态,确认当前进度仍然有效",
"projection.runEvidenceAvailable": "存在可查看的运行证据",
"projection.runRecorded": "最近一次 LoopX 运行已经记录",
"projection.statusRefreshNeeded": "LoopX 状态需要刷新",
"projection.todoStatusUpdated": "Todo 状态已经更新,正在确认下一步",
"projection.validationRecorded": "最近验证已经记录",
"runs.completed": "已完成",
"runs.failed": "需检查",
"runs.interrupted": "已中断",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
fetchGoalContexts,
fetchGoalChannelTargets,
fetchLarkConnections,
fetchLoopXMode,
listTypedActions,
previewTypedAction,
setupGoalChannel,
Expand Down Expand Up @@ -181,40 +182,71 @@ function ManagerHomeBoard({
}

function GoalOutputsView({
active,
items,
onSelect,
reportState,
teamSessionId,
}: {
active: boolean;
items: Array<Extract<WorkspaceTimelineItem, { kind: "output" }>>;
onSelect: (selection: WorkspaceDrawerSelection) => void;
reportState?: WorkspaceModel["periodicReports"];
teamSessionId?: string;
}) {
const { locale, t } = useWorkspaceI18n();
const [teamSnapshot, setTeamSnapshot] = useState<LoopXModeSnapshot | null>(null);
const [teamError, setTeamError] = useState(false);
const [teamRefresh, setTeamRefresh] = useState(0);
useEffect(() => {
if (!active || !teamSessionId) {
setTeamSnapshot(null);
setTeamError(false);
return;
}
let current = true;
setTeamSnapshot(null);
setTeamError(false);
void fetchLoopXMode(teamSessionId).then((snapshot) => {
if (current) setTeamSnapshot(snapshot);
}).catch(() => {
if (current) setTeamError(true);
});
return () => { current = false; };
}, [active, teamSessionId, teamRefresh]);
const teamConfigured = Boolean(teamSnapshot?.session_id === teamSessionId
&& teamSnapshot?.settings.agent_id && teamSnapshot?.settings.execution_config);
return (
<section className="personal-object-list personal-files-list" data-testid="personal-goal-outputs">
<header><strong>{t("files.title")}</strong><span>{items.length}</span></header>
{reportState?.loading ? (
<p className="personal-object-list-state" role="status"><RefreshCw className="is-spinning" size={14} />{t("files.loadingReports")}</p>
) : null}
{reportState?.error ? (
<p className="personal-object-list-state is-error" role="alert"><AlertCircle size={14} />{t("files.reportLoadFailed")}: {reportState.error}</p>
) : null}
{!reportState?.loading && !reportState?.error && items.length === 0 ? (
<p className="personal-object-list-state"><FileText size={14} />{t("files.empty")}</p>
) : null}
{items.map((item) => (
<button data-output-kind={item.output.kind} key={item.id} onClick={() => onSelect({ item: item.output, kind: "output" })} type="button">
<span className="personal-file-icon"><FileText size={16} /></span>
<strong>{item.output.title}</strong>
{item.output.report ? <em>{t("files.reportDelta", { added: item.output.report.addedCount, changed: item.output.report.changedCount })}</em> : null}
<p>{item.output.summary ?? item.output.safePreview ?? item.output.kind ?? t("files.emptySummary")}</p>
<small title={item.output.createdAt}>{[
item.output.kind === "report" ? t("files.verifiedReport") : null,
activityTimeLabel(item.output.createdAt, locale, t),
].filter(Boolean).join(" · ")}</small>
</button>
))}
</section>
<>
<section className="personal-object-list personal-files-list" data-testid="personal-goal-outputs">
<header><strong>{t("files.title")}</strong>{!teamConfigured ? <span>{items.length}</span> : null}</header>
{reportState?.loading ? (
<p className="personal-object-list-state" role="status"><RefreshCw className="is-spinning" size={14} />{t("files.loadingReports")}</p>
) : null}
{reportState?.error ? (
<p className="personal-object-list-state is-error" role="alert"><AlertCircle size={14} />{t("files.reportLoadFailed")}: {reportState.error}</p>
) : null}
{!reportState?.loading && !reportState?.error && items.length === 0 && !teamConfigured
&& (!teamSessionId || Boolean(teamSnapshot)) ? (
<p className="personal-object-list-state"><FileText size={14} />{t("files.empty")}</p>
) : null}
{items.map((item) => (
<button data-output-kind={item.output.kind} key={item.id} onClick={() => onSelect({ item: item.output, kind: "output" })} type="button">
<span className="personal-file-icon"><FileText size={16} /></span>
<strong>{item.output.title}</strong>
{item.output.report ? <em>{t("files.reportDelta", { added: item.output.report.addedCount, changed: item.output.report.changedCount })}</em> : null}
<p>{item.output.summary ?? item.output.safePreview ?? item.output.kind ?? t("files.emptySummary")}</p>
<small title={item.output.createdAt}>{[
item.output.kind === "report" ? t("files.verifiedReport") : null,
activityTimeLabel(item.output.createdAt, locale, t),
].filter(Boolean).join(" · ")}</small>
</button>
))}
</section>
{active && teamSessionId && !teamSnapshot && !teamError ? <p className="personal-object-list-state" role="status">{t("files.checkingTeam")}</p> : null}
{active && teamSessionId && teamError ? <p className="personal-object-list-state is-error" role="alert">{t("files.teamLoadFailed")} <button type="button" onClick={() => setTeamRefresh(value => value + 1)}>{t("startup.retry")}</button></p> : null}
{active && teamConfigured && teamSessionId ? <GoalTeamResults sessionId={teamSessionId} zh={locale === "zh-CN"} refreshKey={JSON.stringify(teamSnapshot?.deliveries ?? [])} /> : null}
</>
);
}

Expand Down Expand Up @@ -1991,9 +2023,11 @@ export function PersonalWorkspacePage({
userTodos={model.userTodos}
/>),
files: (<GoalOutputsView
active={selectedGoalTab === "files"}
items={items.filter((item): item is Extract<WorkspaceTimelineItem, { kind: "output" }> => item.kind === "output")}
onSelect={setSelection}
reportState={model.periodicReports}
teamSessionId={!readOnly && selectedAgentId === "codex" ? conversationSessionId : undefined}
/>),
chat: (<>
{selectedGoal && activeSessionRun?.goalId === selectedGoal.goalId ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,11 @@ export type ProjectionMessageKey =
| "projection.agentStopped"
| "projection.agentWaitingExternal"
| "projection.confirmAgentDecision"
| "projection.events24h"
| "projection.firstReadOnlyAdapterCheck"
| "projection.goalVerified"
| "projection.latestRun"
| "projection.latestValidation"
| "projection.nextUpdatePending"
| "projection.publicSafeProjection"
| "projection.refreshState"
| "projection.runEvidenceAvailable"
| "projection.runRecorded"
| "projection.statusRefreshNeeded"
| "projection.todoStatusUpdated"
| "projection.validationRecorded";
| "projection.todoStatusUpdated";

export type ProjectionTranslate = (
key: ProjectionMessageKey,
Expand Down Expand Up @@ -70,25 +62,3 @@ export function agentStatusSentence(status: ProjectionAgentStatus, t: Projection
};
return t(keyByStatus[status]);
}

export function runEvidenceCopy(
{
eventCount,
hasArtifact,
hasLatestValidation,
}: {
eventCount: number;
hasArtifact: boolean;
hasLatestValidation: boolean;
},
t: ProjectionTranslate,
) {
return {
label: t(hasLatestValidation ? "projection.latestValidation" : "projection.latestRun"),
metadata: eventCount > 0
? t("projection.events24h", { count: eventCount })
: hasArtifact
? t("projection.runEvidenceAvailable")
: t("projection.publicSafeProjection"),
};
}
Loading
Loading