feat(apps): trigger method, role wording, avatars, calmer card colors - #7
Merged
Conversation
## 类型 → 触发方式 The picker now offers 聊天 / 定时任务 / 邮件 / 自定义 and answers "what triggers this employee". 订阅 folds into 定时任务 in the label only — the stored value is still `Subscription`, because `isStreamApp` reads it in eight places to decide whether to show feed management. `Plugin` moves to the platform picker, where it actually belongs. Legacy `Tool`/`Plugin` values still render (they appear as an extra option when an app already has one) instead of showing an empty select. ## Agent.md → 角色设定 The editor's title is now just 角色设定 — no filename, no colored tag. The help text was rewritten for people who don't know what a prompt is. The revert-to- prompt action is gone: with every new app born with an Agent.md there is nothing to revert to, and the button only ever led to a dead end. The 提示词 dropdown is gone from the edit dialog too. The role is the single source of truth, so there is no template to pick from; `prompt_id` is still sent (null) as the rollback anchor. Its `/api/prompts` fetch went with it — one fewer request on first paint. ## Avatars New field with eight built-in avatars plus upload. Built-ins are SVG rather than images: the whole UI is lucide, so the same glyph family looks native, scales cleanly and carries no licensing baggage. They live in `public/` so every deployment has them and an offline install doesn't render blanks. Colour ownership: if the user picked an avatar (built-in or uploaded) it renders untouched — their choice, not ours to theme. Only the unset case falls back to initial + brand colour, so it follows a tenant's primary colour. `AppAvatar` is shared by list, card, detail and dialog so the rule isn't reimplemented four times and slowly drifting. Uploads get a UUID filename first. The OSS object key is `<category>/<yyyymm>/<filename>` with no server-side dedupe (verified: two presigns for the same name return the same key), and avatars are exactly where names collide — avatar.png, logo.png. A collision doesn't error, it silently swaps one employee's face for another's. ## Card colours Trigger and platform tags are neutral now. They used to be purple/green/yellow/ blue/emerald/orange, one hue per value, and the hues meant nothing — 聊天 purple, Web purple too. Colour is left to the things that are actually saying something: review-status badges, the destructive action, and the avatar. Both colour maps were deleted rather than filled with one repeated value. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Needs ragent-service#66 (the
avatar_urlfield and thePluginplatform value).类型 → 触发方式
The picker now offers 聊天 / 定时任务 / 邮件 / 自定义 and answers "what triggers this employee". 订阅 folds into 定时任务 in the label only — the stored value stays
Subscription, becauseisStreamAppreads it in eight places to decide whether to show feed management.Pluginmoves to the platform picker where it belongs.Legacy
Tool/Pluginvalues still render: when an app already has one it appears as an extra option, so the select never shows up blank.Agent.md → 角色设定
The editor title is now just 角色设定 — no filename, no colored tag. The help text was rewritten for people who don't know what a prompt is. Revert-to-prompt is gone: now that every new app is born with an Agent.md there is nothing to revert to, so the button only ever led to a dead end.
The 提示词 dropdown is gone from the edit dialog as well. The role is the single source of truth, so there is no template to pick from.
prompt_idis still submitted (null) as the rollback anchor; the now-unused/api/promptsfetch went with it — one fewer request on first paint.Avatars
Eight built-in avatars plus upload, shown in the edit dialog and rendered in list, card and detail views.
Built-ins are SVG rather than images: the whole UI is lucide, so the same glyph family looks native, scales cleanly at any size and carries no licensing baggage. They live in
public/so every deployment has them and an offline install doesn't render blanks.Colour ownership — if the user picked an avatar (built-in or uploaded) it renders untouched; that was their choice, not ours to theme. Only the unset case falls back to initial + brand colour, so it follows whatever primary colour a tenant configures.
AppAvataris shared by all four call sites so the rule isn't reimplemented four times and slowly drifting.Uploads get a UUID filename first. The OSS object key is
<category>/<yyyymm>/<filename>with no server-side dedupe — verified by calling presign twice with the same name and getting the same key back. Avatars are exactly where names collide (avatar.png, logo.png, 头像.png), and a collision doesn't error: it silently swaps one employee's face for another's, and the person who uploaded first never finds out.Card colours
Trigger and platform tags are neutral now. They used to be purple / green / yellow / blue / emerald / orange, one hue per value, and the hues meant nothing — 聊天 was purple and Web was purple too, so a reader has to check whether the colour is saying something before discovering it isn't.
Colour is left to the things that actually say something: review-status badges (draft / pending / rejected), the destructive action, and the avatar. Both colour maps were deleted rather than filled with one repeated value — a map whose every value is identical isn't a map.
Tests
216 passing (+8).
tscunchanged at the existing baseline apart from the new test files' pre-existingTS5097class.The avatar tests pin the two directions that fail silently: every entry in
BUILTIN_AVATARShas a file on disk and every file on disk is registered (an unregistered one can never be picked). One asserts the SVGs carry their own colours and don't usecurrentColor— loaded via<img>they can't reach page CSS variables, so a stripped colour isn't an error, just an invisible tile. Both were mutation verified.Verified in the browser
Not just unit tests: picked a built-in avatar → saved → confirmed the value in the database → confirmed the card re-rendered with it. Uploaded a real PNG and confirmed the object key got a UUID, the file came back with
content-type: image/png, and the image rendered.🤖 Generated with Claude Code