diff --git a/src/renderer/src/i18n/zh.ts b/src/renderer/src/i18n/zh.ts index 0bdff6af..454f40e2 100644 --- a/src/renderer/src/i18n/zh.ts +++ b/src/renderer/src/i18n/zh.ts @@ -179,7 +179,6 @@ export const zh: Record = { "Hire agent": "招聘智能体", "Hires need your stamp; deliverables route through review before shipping.": "招聘需要你签字确认;交付物先经审核再发布。", "Hires require approval": "招聘需审批", - "Hiring pipeline": "招聘进展", "Home": "首页", "How autonomous should the CEO be?": "CEO 的自主程度?", "Humans only": "仅人类", diff --git a/src/renderer/src/pages/TeamPage.tsx b/src/renderer/src/pages/TeamPage.tsx index cc4c411c..382ef095 100644 --- a/src/renderer/src/pages/TeamPage.tsx +++ b/src/renderer/src/pages/TeamPage.tsx @@ -4,7 +4,6 @@ import { AvatarField } from "../shared/AvatarField"; import { TopbarActions } from "../shared/TopbarActions"; import { Dialog } from "../shared/Dialog"; import { OrgChartTree } from "./team/OrgChartTree"; -import { HiringPipeline } from "./team/HiringPipeline"; import type { AgentRecord, EmployeeRecord, ProviderRecord } from "../../../shared/domain"; import type { PageProps } from "./types"; import { activeOrgId, money } from "./types"; @@ -119,8 +118,6 @@ export function TeamPage({ snapshot, actions }: PageProps) { - a.orgId === orgId)} /> -
{t("Roster")}
task.id === detailTaskId) ?? null : null; return ( -
+
- {view === "board" && ( - setNewTaskOpen(true)} - onOpen={(task) => setDetailTaskId(task.id)} - /> - )} - {view === "list" && ( - setDetailTaskId(task.id)} - /> - )} - {view === "timeline" && } +
+ {view === "board" && ( + setNewTaskOpen(true)} + onOpen={(task) => setDetailTaskId(task.id)} + /> + )} + {view === "list" && ( +
+ setDetailTaskId(task.id)} + /> +
+ )} + {view === "timeline" && ( +
+ +
+ )} +
setNewGoalOpen(false)} /> setNewProjectOpen(false)} /> @@ -230,30 +238,32 @@ function BoardView({ onOpen: (task: TaskRecord) => void; }) { return ( -
+
{COLUMNS.map((column) => { const columnTasks = tasks.filter((task) => task.status === column.id); return ( -
-
+
+
{column.label} {columnTasks.length}
- {columnTasks.map((task) => ( - agent.id === task.assigneeAgentId) ?? null} - project={projects.find((project) => project.id === task.projectId) ?? null} - provider={providerFor(agents.find((agent) => agent.id === task.assigneeAgentId) ?? null, providers)} - latestRun={latestTaskRun(task.id, taskRuns)} - onAdvance={() => onAdvance(task)} - onRun={() => onRun(task)} - onOpen={() => onOpen(task)} - /> - ))} +
+ {columnTasks.map((task) => ( + agent.id === task.assigneeAgentId) ?? null} + project={projects.find((project) => project.id === task.projectId) ?? null} + provider={providerFor(agents.find((agent) => agent.id === task.assigneeAgentId) ?? null, providers)} + latestRun={latestTaskRun(task.id, taskRuns)} + onAdvance={() => onAdvance(task)} + onRun={() => onRun(task)} + onOpen={() => onOpen(task)} + /> + ))} +
); })} diff --git a/src/renderer/src/pages/team/HiringPipeline.tsx b/src/renderer/src/pages/team/HiringPipeline.tsx deleted file mode 100644 index 3bd2ad70..00000000 --- a/src/renderer/src/pages/team/HiringPipeline.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Avatar } from "../../shared/ui"; -import type { AgentRecord, ApprovalRecord } from "../../../../shared/domain"; -import { formatRelative } from "../types"; -import { t } from "../../i18n/i18n"; - -interface PipelineStage { - id: string; - label: string; - color: string; -} - -const STAGES: PipelineStage[] = [ - { id: "pending_approval", label: t("Pending approval"), color: "var(--amber)" }, - { id: "approved", label: t("Approved"), color: "var(--green)" }, - { id: "active", label: t("Active"), color: "var(--accent)" }, - { id: "rejected", label: t("Rejected"), color: "var(--red)" }, -]; - -interface PipelineEntry { - agent: AgentRecord; - stage: string; - approval: ApprovalRecord | null; -} - -function resolveStage(agent: AgentRecord, approvals: ApprovalRecord[]): PipelineEntry { - const hireApproval = approvals.find( - (a) => a.sourceEntityType === "agent" && a.sourceEntityId === agent.id && a.kind === "agent_hire", - ) ?? null; - - if (hireApproval?.state === "pending") return { agent, stage: "pending_approval", approval: hireApproval }; - if (hireApproval?.state === "declined") return { agent, stage: "rejected", approval: hireApproval }; - if (agent.lifecycle === "active") return { agent, stage: "active", approval: hireApproval }; - return { agent, stage: "approved", approval: hireApproval }; -} - -export function HiringPipeline({ agents, approvals }: { agents: AgentRecord[]; approvals: ApprovalRecord[] }) { - const entries = agents.map((a) => resolveStage(a, approvals)); - - return ( -
-
{t("Hiring pipeline")}
-
- {STAGES.map((stage) => { - const stageEntries = entries.filter((e) => e.stage === stage.id); - return ( -
-
- - {stage.label} - {stageEntries.length} -
-
- {stageEntries.map((entry) => ( -
-
- -
-
{entry.agent.name}
-
{entry.agent.role} · {entry.agent.department}
-
-
- {entry.approval && ( -
- {formatRelative(entry.approval.createdAt)} -
- )} -
- ))} -
-
- ); - })} -
-
- ); -} diff --git a/src/renderer/src/shared/OrgSwitcher.tsx b/src/renderer/src/shared/OrgSwitcher.tsx index 3215cd8e..50841867 100644 --- a/src/renderer/src/shared/OrgSwitcher.tsx +++ b/src/renderer/src/shared/OrgSwitcher.tsx @@ -51,7 +51,7 @@ export function OrgSwitcher({ snapshot, activeOrgId, onSelect, onNew, onDelete } }; return ( -
+