diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c6f609c..5d8e567b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ ### Fixed +- #297:创建数字员工默认先展示 Agent 与基础信息;Agent 草案、头像、权限、能力、记忆、运行模式和预算改为按需展开,保留安全默认值、原有字段校验与 hire 请求 payload。 + - 组织树员工行的右键菜单与省略号菜单首位新增「编辑」入口:点击后打开 #292 的员工编辑抽屉,并按被右键/省略号唤起的那一行现取该员工档案回填表单,保存也对该行提交,不再绑定或抢占主面板当前选中的对话;岗位卡片头部的「编辑」按钮改用同一入口。企业根行菜单不变(仍为项目设置等)。附渲染层测试:行菜单两种触发均出编辑项、企业行菜单不出,以及 App 级端到端断言右键某行后抽屉预填该行档案、改名保存以正确 id 走档案更新桥且选中保持不变。 - #301:创建数字员工抽屉移除左上角无响应的标题关闭按钮(×):创建执行中取消本就被设计拒绝(#43),而该按钮在提交、审批与成功三个阶段静默吞掉点击,与同屏置灰的「执行中不可取消」提示相矛盾。按报告要求直接删除;可编辑面板保留底部「取消」,遮罩与 Esc 行为不变,员工编辑抽屉的关闭按钮不受影响。 diff --git a/apps/desktop/renderer/src/app.css b/apps/desktop/renderer/src/app.css index b7c3291d..fffad33c 100644 --- a/apps/desktop/renderer/src/app.css +++ b/apps/desktop/renderer/src/app.css @@ -2014,15 +2014,31 @@ } -/* #57 agent 引擎品牌 icon(Qoder 应用标 / Claude starburst):14px 档、圆角 3px, - 与引擎文字标签内联对齐。 */ +/* #57 agent 引擎品牌 icon:统一 18px 布局盒子;不同素材的画布留白不一, + 用轻微 optical scale 让实际可见的品牌面积保持同一档位。 */ .owb-engine-icon { - width: 14px; - height: 14px; - border-radius: 3px; - margin-right: 4px; - vertical-align: -2px; + width: 18px; + height: 18px; + border-radius: 5px; + margin-right: 5px; + vertical-align: -4px; flex: none; + transform: scale(var(--owb-engine-icon-optical-scale, 1)); +} + +.owb-engine-icon--qoder { + --owb-engine-icon-optical-scale: 1.2; +} + +.owb-engine-icon--workbuddy { + --owb-engine-icon-optical-scale: .92; +} + +/* design-system 的树元数据默认把所有图像压到 12px;品牌标识需要与 + 岗位头像同一视觉档位,避免在深色树中显得像一枚无关紧要的点。 */ +.ui-org-tree__metadata .owb-engine-icon { + width: 18px; + height: 18px; } /* #35 S3 文档模块面:岗位选择器与 DocsPanel 纵向排布,间距走档位变量。 */ @@ -2933,9 +2949,92 @@ overflow-wrap: break-word; } -.owb-hire-agent-picker .ant-select { +.owb-hire-choice-select { + position: relative; min-width: 0; +} + +.owb-hire-choice-select__trigger { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + width: 100%; + min-width: 0; + min-height: 36px; + padding: 0 10px; + border: 1px solid var(--ui-border); + border-radius: 8px; + background: var(--ui-surface); + color: var(--ui-foreground); + font: inherit; + text-align: left; + cursor: pointer; +} + +.owb-hire-choice-select__trigger:hover, +.owb-hire-choice-select__trigger[aria-expanded="true"] { + border-color: color-mix(in srgb, var(--ui-primary) 62%, var(--ui-border)); +} + +.owb-hire-choice-select__trigger:focus-visible { + outline: 2px solid var(--ui-focus); + outline-offset: 2px; +} + +.owb-hire-choice-select__trigger > span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.owb-hire-choice-select__trigger > svg { + flex: 0 0 auto; + color: var(--ui-foreground-muted); + transition: transform 120ms ease; +} + +.owb-hire-choice-select__trigger[aria-expanded="true"] > svg { + transform: rotate(180deg); +} + +.owb-hire-choice-select__menu { + position: absolute; + z-index: 1100; + top: calc(100% + 4px); + right: 0; + left: 0; + display: grid; + gap: 2px; + min-width: 100%; + padding: 4px; + border: 1px solid var(--ui-border); + border-radius: 8px; + background: var(--ui-surface-raised); + box-shadow: var(--ui-shadow-md); +} + +.owb-hire-choice-select__menu > button { width: 100%; + padding: 8px 9px; + border: 0; + border-radius: 6px; + background: transparent; + color: var(--ui-foreground); + font: inherit; + text-align: left; + cursor: pointer; +} + +.owb-hire-choice-select__menu > button:hover, +.owb-hire-choice-select__menu > button.is-selected { + background: color-mix(in srgb, var(--ui-primary) 14%, var(--ui-surface)); + color: var(--ui-primary); +} + +.owb-hire-choice-select__menu > button:focus-visible { + outline: 2px solid var(--ui-focus); + outline-offset: -2px; } .owb-hire-agent-binding { @@ -2964,6 +3063,31 @@ background: var(--ui-surface-inset); } +.owb-hire-assist { + overflow: hidden; + border: 1px solid var(--ui-border); + border-radius: 10px; + background: color-mix(in srgb, var(--ui-surface-inset) 52%, transparent); +} + +.owb-hire-assist > summary { + display: flex; + align-items: center; + gap: 7px; + min-height: 42px; + padding: 0 13px; + color: var(--ui-foreground); + font-size: 12px; + font-weight: 650; + cursor: pointer; + list-style: none; +} + +.owb-hire-assist > summary::-webkit-details-marker { display: none; } +.owb-hire-assist > summary > svg { color: var(--ui-primary); } +.owb-hire-assist > summary > span { margin-left: auto; color: var(--ui-foreground-muted); font-size: 10px; font-weight: 400; } +.owb-hire-assist > .owb-hire-conversation { border: 0; border-top: 1px solid var(--ui-border); border-radius: 0; } + .owb-hire-conversation__meta, .owb-hire-prompt__footer, .owb-hire-draft-card__heading, @@ -3115,6 +3239,13 @@ font-size: 10px; } +.owb-hire-basic-description { + margin: 5px 0 0; + color: var(--ui-foreground-muted); + font-size: 11px; + line-height: 1.45; +} + .owb-hire-basic-grid, .owb-hire-two-col { display: grid; diff --git a/apps/desktop/renderer/src/assets/workbuddy.png b/apps/desktop/renderer/src/assets/workbuddy.png deleted file mode 100644 index 6b23faae..00000000 Binary files a/apps/desktop/renderer/src/assets/workbuddy.png and /dev/null differ diff --git a/apps/desktop/renderer/src/assets/workbuddy.svg b/apps/desktop/renderer/src/assets/workbuddy.svg new file mode 100644 index 00000000..2fb0e5a9 --- /dev/null +++ b/apps/desktop/renderer/src/assets/workbuddy.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/desktop/renderer/src/org/HireDrawer.tsx b/apps/desktop/renderer/src/org/HireDrawer.tsx index bb78d125..a40db3b2 100644 --- a/apps/desktop/renderer/src/org/HireDrawer.tsx +++ b/apps/desktop/renderer/src/org/HireDrawer.tsx @@ -8,7 +8,7 @@ * POST /hire gate. */ import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react"; -import { Button as AntButton, Checkbox, Drawer, Input, Select, Steps, message } from "antd"; +import { Button as AntButton, Checkbox, Drawer, Input, Steps, message } from "antd"; import { CheckCircle2, ChevronDown, LoaderCircle, RotateCcw, Sparkles, XCircle } from "lucide-react"; import { Input as OwbInput } from "@fullstack-ai-infra/ui"; import { useT, type OwbT } from "@roleweave/ui"; @@ -97,6 +97,46 @@ function defaultPrompt(t: OwbT): string { return t("hire.agentPromptTemplate"); } +function HireChoiceSelect({ ariaLabel, value, options, onChange, t }: { + ariaLabel: string; + value: string; + options: Array<{ value: string; label: string }>; + onChange: (value: string) => void; + t: OwbT; +}) { + const [open, setOpen] = useState(false); + const selected = options.find((option) => option.value === value); + const selectedLabel = selected?.label ?? value; + return ( +
+ + {open ?
+ {options.map((option) => )} +
: null} +
+ ); +} + export function HireDrawer({ open, workspacePath, positions, presetReportTo, engine, conversationEngine, engineAvailability, conversationHostId, conversationHostName, budgetPoolTokens = PLATFORM_BUDGET_POOL, budgetAllocatedTokens = 0, onClose, onHired }: HireDrawerProps) { const t = useT(); const [flow, dispatch] = useReducer(reduceHireFlow, undefined, () => initialHireFlow()); @@ -116,6 +156,7 @@ export function HireDrawer({ open, workspacePath, positions, presetReportTo, eng const [messages, setMessages] = useState([]); const [conversationBusy, setConversationBusy] = useState(false); const [conversationError, setConversationError] = useState(null); + const [designAssistOpen, setDesignAssistOpen] = useState(false); const [advancedOpen, setAdvancedOpen] = useState(false); const [permissions, setPermissions] = useState({ tools: ["Read", "Grep", "Glob"], rules: [{ scope: "position", resource: "./knowledge/**", actions: ["read"] }], skills: [], mcpServers: [] }); const [memorySources, setMemorySources] = useState([{ kind: "position_docs", locator: "./knowledge/**" }]); @@ -147,7 +188,7 @@ export function HireDrawer({ open, workspacePath, positions, presetReportTo, eng setName(""); setDescription(""); setAvatar(undefined); setAvatarGenerating(false); setAvatarError(null); setReportTo(presetReportTo); setMode("approval_required"); setTaskTokens("20000"); setTaskIterations("8"); setDayTokens("200000"); setDayIterations("64"); setAgentHost(defaultAgentHost(engineAvailability)); - setPrompt(defaultPrompt(t)); setMessages([]); setConversationBusy(false); setConversationError(null); setAdvancedOpen(false); + setPrompt(defaultPrompt(t)); setMessages([]); setConversationBusy(false); setConversationError(null); setDesignAssistOpen(false); setAdvancedOpen(false); setPermissions({ tools: ["Read", "Grep", "Glob"], rules: [{ scope: "position", resource: "./knowledge/**", actions: ["read"] }], skills: [], mcpServers: [] }); setMemorySources([{ kind: "position_docs", locator: "./knowledge/**" }]); setPhaseCopy(t("hire.phaseSubmit")); }, [clearTimers, engineAvailability, open, presetReportTo, t]); @@ -298,55 +339,59 @@ export function HireDrawer({ open, workspacePath, positions, presetReportTo, eng

{t("hire.agentTitle")}

{t("hire.agentDescription")}

-