[feat] Redesign the Skills page on /m as the shared list, with a card view for ListTable - #6890
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 SummarySummary by CodeRabbit
WalkthroughThe pull request adds skill author metadata, shared list and grid rendering, batched skill APIs, mobile registry workflows, upload-based creation, editable skill drawers, agent association, and inline skill publishing. ChangesSkills registry and editor redesign
Priority: ➖ Normal Estimated code review effort: 5 (Critical) | ~90 minutes Merge Risk: 🟡 Moderate · up to The change should not merge yet: type checking can fail, agent updates may appear successful before completing, and some skill filtering and editing interactions produce incorrect results. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
86e86fe to
aa2a27d
Compare
eba3ac2 to
160c0a2
Compare
Railway Preview Environment
Updated at 2026-09-17T13:26:45.237Z |
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (1)
web/packages/agenta-skills-ui/src/useSkillCreateEntry.ts (1)
5-10: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueKeep only concise comments for non-obvious constraints.
web/AGENTS.mdmakes this a hard rule: comments must be at most one short line, must not restate the code, and longer comments are allowed only for genuinely surprising constraints.
- Reduce
useSkillCreateEntry.tsto one short line documenting only that Write clears the upload before opening a blank editor.- Remove the comments in
SkillImportDrawer.tsxat lines 214-215, 238, 261, 279-280, and 369-370. They describe visible layout or styling rather than a non-obvious constraint.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Advanced
Run ID: 7f9e977f-2da7-48ec-8a93-e3bd4e231e9e
📒 Files selected for processing (48)
api/oss/src/core/skills/dtos.pyapi/oss/src/core/skills/service.pyweb/mobile/src/features/skills/SkillActionsMenu.tsxweb/mobile/src/features/skills/SkillArchivedTag.tsxweb/mobile/src/features/skills/SkillCardBody.tsxweb/mobile/src/features/skills/SkillFilterMenu.tsxweb/mobile/src/features/skills/SkillListScreen.tsxweb/mobile/src/features/skills/SkillListTable.tsxweb/mobile/src/features/skills/SkillRowCells.tsxweb/mobile/src/features/skills/SkillSourceUpdateAction.tsxweb/mobile/src/features/skills/SkillUpdateCell.tsxweb/mobile/src/features/skills/skillListView.tsweb/mobile/src/features/skills/states/SkillsEmpty.tsxweb/mobile/src/features/skills/states/SkillsError.tsxweb/mobile/src/features/skills/states/SkillsNoMatch.tsxweb/mobile/src/features/skills/useSkillActions.tsweb/mobile/src/features/skills/useSkillUpdates.tsweb/oss/src/components/pages/skills/SkillsPage.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/AgentTemplateControl.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/ConfigItemDrawer.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/SkillFormView.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/ConfigItemList.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/itemDescriptors.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/itemKinds.tsxweb/packages/agenta-entity-ui/src/agent/AgentPicker.tsxweb/packages/agenta-entity-ui/src/agent/index.tsweb/packages/agenta-skills-ui/src/NewSkillMenuButton.tsxweb/packages/agenta-skills-ui/src/SkillAgentPicker.tsxweb/packages/agenta-skills-ui/src/SkillCard.tsxweb/packages/agenta-skills-ui/src/SkillCreateDrawer.tsxweb/packages/agenta-skills-ui/src/SkillDetailDrawer.tsxweb/packages/agenta-skills-ui/src/SkillImportDrawer.tsxweb/packages/agenta-skills-ui/src/SkillPickerDrawer.tsxweb/packages/agenta-skills-ui/src/SkillPickerHost.tsxweb/packages/agenta-skills-ui/src/SkillUploadPanel.tsxweb/packages/agenta-skills-ui/src/SourceRefreshButton.tsxweb/packages/agenta-skills-ui/src/index.tsweb/packages/agenta-skills-ui/src/useSkillCreateEntry.tsweb/packages/agenta-skills/src/api/index.tsweb/packages/agenta-skills/src/core/schema.tsweb/packages/agenta-ui/src/components/ui/checkbox.tsxweb/packages/agenta-ui/src/drawer/EnhancedDrawer.tsxweb/packages/agenta-ui/src/list-table/ListTable.tsxweb/packages/agenta-ui/src/list-table/ListTableViewToggle.tsxweb/packages/agenta-ui/src/list-table/index.tsweb/packages/agenta-ui/src/list-table/types.tsweb/storybook/stories/ListTable.stories.tsxweb/storybook/stories/skills-ui/SkillUploadPanel.stories.tsx
💤 Files with no reviewable changes (3)
- web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/ConfigItemList.tsx
- web/storybook/stories/skills-ui/SkillUploadPanel.stories.tsx
- web/packages/agenta-skills-ui/src/SkillUploadPanel.tsx
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Advanced
Run ID: 430a014c-49c4-46d5-8493-e3c1553ac013
📒 Files selected for processing (10)
web/mobile/src/features/skills/SkillFilterMenu.tsxweb/mobile/src/features/skills/SkillListTable.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/AgentTemplateControl.tsxweb/packages/agenta-entity-ui/src/agent/AgentPicker.tsxweb/packages/agenta-skills-ui/src/SkillAgentPicker.tsxweb/packages/agenta-skills-ui/src/SkillCreateDrawer.tsxweb/packages/agenta-skills-ui/src/SkillDetailDrawer.tsxweb/packages/agenta-skills-ui/src/SourceRefreshButton.tsxweb/packages/agenta-skills-ui/src/useSkillCreateEntry.tsweb/packages/agenta-ui/src/list-table/types.ts
🚧 Files skipped from review as they are similar to previous changes (9)
- web/mobile/src/features/skills/SkillListTable.tsx
- web/packages/agenta-skills-ui/src/useSkillCreateEntry.ts
- web/packages/agenta-skills-ui/src/SkillAgentPicker.tsx
- web/packages/agenta-entity-ui/src/agent/AgentPicker.tsx
- web/packages/agenta-skills-ui/src/SkillDetailDrawer.tsx
- web/packages/agenta-skills-ui/src/SkillCreateDrawer.tsx
- web/mobile/src/features/skills/SkillFilterMenu.tsx
- web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/AgentTemplateControl.tsx
- web/packages/agenta-skills-ui/src/SourceRefreshButton.tsx
Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.
| export type ListTableViewProps<Row> = | ||
| | { | ||
| /** | ||
| * Same groups, same headings, same open and collapse — cards instead of rows. | ||
| * `"list"` by default, so a consumer that never asks for cards never sees them. | ||
| */ | ||
| view?: "list" | ||
| renderCard?: (row: Row) => ReactNode | ||
| } | ||
| | { | ||
| view: "grid" | ||
| /** | ||
| * A card's CONTENTS. The frame owns the tile — border, radius, padding, hover, the | ||
| * open affordance — the way it owns a row's, so a consumer draws what is inside it | ||
| * and nothing else. | ||
| */ | ||
| renderCard: (row: Row) => ReactNode | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
sed -n '35,90p' web/packages/agenta-ui/src/list-table/types.ts
sed -n '105,145p' web/mobile/src/features/skills/SkillListTable.tsx
rg -n 'interface SkillListTableProps|type SkillListTableProps|<SkillListTable|view:' web/mobile/src/features/skills/SkillListTable.tsx web/mobile/src/features/skills/SkillListScreen.tsx web/storybook/stories/ListTable.stories.tsxRepository: Agenta-AI/agenta
Length of output: 4040
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- SkillListTable imports and signature ---'
sed -n '1,95p' web/mobile/src/features/skills/SkillListTable.tsx
printf '%s\n' '--- ListTable declarations/usages ---'
rg -n --glob '*.ts' --glob '*.tsx' 'export (const|function) ListTable|function ListTable|const ListTable|ListTableProps' web/packages/agenta-ui/src/list-table web/mobile/src/features/skills/SkillListTable.tsx
printf '%s\n' '--- component implementation ---'
sed -n '1,120p' web/packages/agenta-ui/src/list-table/ListTable.tsxRepository: Agenta-AI/agenta
Length of output: 10385
🏁 Script executed:
set -eu
rg -n --glob '*.ts' --glob '*.tsx' 'ListTableProps|export .*ListTable|function ListTable|const ListTable' web/packages/agenta-ui/src web/mobile/src/features/skills/SkillListTable.tsxRepository: Agenta-AI/agenta
Length of output: 1746
Allow a runtime ListTableView when renderCard is present.
SkillListTable passes view: ListTableView directly to ListTable and always supplies renderCard. ListTable accepts ListTableProps<Row> without another overload or narrowing. The current union accepts only view?: "list" or view: "grid", so TypeScript rejects this props object because it satisfies neither branch.
export type ListTableViewProps<Row> =
| {
view?: "list"
renderCard?: (row: Row) => ReactNode
}
| {
- view: "grid"
+ view: ListTableView
renderCard: (row: Row) => ReactNode
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export type ListTableViewProps<Row> = | |
| | { | |
| /** | |
| * Same groups, same headings, same open and collapse — cards instead of rows. | |
| * `"list"` by default, so a consumer that never asks for cards never sees them. | |
| */ | |
| view?: "list" | |
| renderCard?: (row: Row) => ReactNode | |
| } | |
| | { | |
| view: "grid" | |
| /** | |
| * A card's CONTENTS. The frame owns the tile — border, radius, padding, hover, the | |
| * open affordance — the way it owns a row's, so a consumer draws what is inside it | |
| * and nothing else. | |
| */ | |
| renderCard: (row: Row) => ReactNode | |
| } | |
| export type ListTableViewProps<Row> = | |
| | { | |
| /** | |
| * Same groups, same headings, same open and collapse — cards instead of rows. | |
| * `"list"` by default, so a consumer that never asks for cards never sees them. | |
| */ | |
| view?: "list" | |
| renderCard?: (row: Row) => ReactNode | |
| } | |
| | { | |
| view: ListTableView | |
| /** | |
| * A card's CONTENTS. The frame owns the tile — border, radius, padding, hover, the | |
| * open affordance — the way it owns a row's, so a consumer draws what is inside it | |
| * and nothing else. | |
| */ | |
| renderCard: (row: Row) => ReactNode | |
| } |
9bf060c to
bdb1fa9
Compare
cd90fbc to
b885e53
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Advanced
Run ID: 17b5ff87-f8c0-4447-9b8a-7af0f1c0d8e7
📒 Files selected for processing (51)
api/oss/src/core/skills/dtos.pyapi/oss/src/core/skills/service.pyweb/mobile/src/features/skills/SkillActionsMenu.tsxweb/mobile/src/features/skills/SkillArchivedTag.tsxweb/mobile/src/features/skills/SkillCardBody.tsxweb/mobile/src/features/skills/SkillFilterMenu.tsxweb/mobile/src/features/skills/SkillListScreen.tsxweb/mobile/src/features/skills/SkillListTable.tsxweb/mobile/src/features/skills/SkillRowCells.tsxweb/mobile/src/features/skills/SkillSourceUpdateAction.tsxweb/mobile/src/features/skills/SkillUpdateCell.tsxweb/mobile/src/features/skills/skillListView.tsweb/mobile/src/features/skills/states/SkillsEmpty.tsxweb/mobile/src/features/skills/states/SkillsError.tsxweb/mobile/src/features/skills/states/SkillsNoMatch.tsxweb/mobile/src/features/skills/useSkillActions.tsweb/mobile/src/features/skills/useSkillUpdates.tsweb/oss/src/components/pages/skills/SkillsPage.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/AgentTemplateControl.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/ConfigItemDrawer.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/SkillFormView.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/ConfigItemList.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/itemDescriptors.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/itemKinds.tsxweb/packages/agenta-entity-ui/src/agent/AgentPicker.tsxweb/packages/agenta-entity-ui/src/agent/index.tsweb/packages/agenta-skills-ui/src/NewSkillMenuButton.tsxweb/packages/agenta-skills-ui/src/SkillAgentPicker.tsxweb/packages/agenta-skills-ui/src/SkillCard.tsxweb/packages/agenta-skills-ui/src/SkillCreateDrawer.tsxweb/packages/agenta-skills-ui/src/SkillDetailDrawer.tsxweb/packages/agenta-skills-ui/src/SkillImportDrawer.tsxweb/packages/agenta-skills-ui/src/SkillPickerDrawer.tsxweb/packages/agenta-skills-ui/src/SkillPickerHost.tsxweb/packages/agenta-skills-ui/src/SkillUploadPanel.tsxweb/packages/agenta-skills-ui/src/SourceRefreshButton.tsxweb/packages/agenta-skills-ui/src/index.tsweb/packages/agenta-skills-ui/src/useSkillCreateEntry.tsweb/packages/agenta-skills/src/api/index.tsweb/packages/agenta-skills/src/core/schema.tsweb/packages/agenta-ui/src/agent-icon/index.tsweb/packages/agenta-ui/src/agent-icon/skillMark.tsweb/packages/agenta-ui/src/components/ui/checkbox.tsxweb/packages/agenta-ui/src/drawer/EnhancedDrawer.tsxweb/packages/agenta-ui/src/list-table/ListTable.tsxweb/packages/agenta-ui/src/list-table/ListTableViewToggle.tsxweb/packages/agenta-ui/src/list-table/index.tsweb/packages/agenta-ui/src/list-table/types.tsweb/storybook/stories/ListTable.stories.tsxweb/storybook/stories/skills-ui/SkillPickerDrawer.stories.tsxweb/storybook/stories/skills-ui/SkillUploadPanel.stories.tsx
💤 Files with no reviewable changes (3)
- web/storybook/stories/skills-ui/SkillUploadPanel.stories.tsx
- web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/ConfigItemList.tsx
- web/packages/agenta-skills-ui/src/SkillUploadPanel.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- web/packages/agenta-skills/src/core/schema.ts
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.
| const headValue = useMemo(() => toFormValue(head?.skill), [head]) | ||
| const dirty = useMemo( | ||
| () => editBaseId !== null && JSON.stringify(draft) !== JSON.stringify(headValue), | ||
| [draft, editBaseId, headValue], | ||
| ) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Compare the draft to the head by value, not by serialized shape.
headValue always carries description: "" and files: [], because toFormValue fills both defaults. SkillFormView removes a key instead of storing an empty value: set deletes the field when the new value is "" (see SkillFormView.tsx lines 266-279), and setFiles deletes files when the list becomes empty.
So a user who types in Description and then clears it again produces draft without a description key. JSON.stringify(draft) !== JSON.stringify(headValue) is then true although the content is unchanged. Two consequences follow: the drawer asks "Discard changes?" on close, and Save stays enabled and commits a revision identical to the head.
Normalize both sides before comparing.
Proposed fix
- const headValue = useMemo(() => toFormValue(head?.skill), [head])
- const dirty = useMemo(
- () => editBaseId !== null && JSON.stringify(draft) !== JSON.stringify(headValue),
- [draft, editBaseId, headValue],
- )
+ const headValue = useMemo(() => toFormValue(head?.skill), [head])
+ // The form drops a key rather than storing an empty value, so compare the normalized
+ // shapes — otherwise "typed then cleared" reads as an edit.
+ const dirty = useMemo(
+ () =>
+ editBaseId !== null &&
+ JSON.stringify(toFormValue(draft)) !== JSON.stringify(headValue),
+ [draft, editBaseId, headValue],
+ )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const headValue = useMemo(() => toFormValue(head?.skill), [head]) | |
| const dirty = useMemo( | |
| () => editBaseId !== null && JSON.stringify(draft) !== JSON.stringify(headValue), | |
| [draft, editBaseId, headValue], | |
| ) | |
| const headValue = useMemo(() => toFormValue(head?.skill), [head]) | |
| // The form drops a key rather than storing an empty value, so compare the normalized | |
| // shapes — otherwise "typed then cleared" reads as an edit. | |
| const dirty = useMemo( | |
| () => | |
| editBaseId !== null && | |
| JSON.stringify(toFormValue(draft)) !== JSON.stringify(headValue), | |
| [draft, editBaseId, headValue], | |
| ) |
| setBusy(true) | ||
| try { | ||
| await write() | ||
| setChanged(true) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Wait for the actual agent write before marking the drawer as changed.
SkillPickerHost.handleAdd and handleRemove do not return the promises from onAdd and onRemove. If either callback is asynchronous, Line 114 marks success and releases busy before the write finishes. A rejected write then bypasses this try/finally flow.
Return both parent callback results from SkillPickerHost.
d5fe4f0 to
d475953
Compare
The shared list frame gains a grid view over the same groups, headings and collapse: renderCard draws a card's contents and the frame owns the tile — border, radius, open affordance, a card-shaped skeleton — the way it owns a row's. Columns are container-driven (auto-fill on cardMinWidth), so one list fits a phone, a pane and a page without breakpoints. groupActions puts a per-group action at a heading's right edge, a sibling of the collapse button rather than a button inside it. ListTableViewToggle is the icon-only list/cards switch at the toolbar's 32px rung. List view is unchanged for every existing consumer.
The registry is the shared ListTable — the frame the agents and automations lists use — with this app's columns, and the first list on /m to offer the frame's card view: the same groups drawn as tiles, switched from the toolbar. Search sits in a ListTableToolbar beside the shared FilterMenu carrying Source, Status, Used by and Group by. A registry item becomes a row in one place, from the same sections the desktop registry reads, so a row and a card describe a skill the same way. Each row carries a kebab — Open, Check for updates (imported only), Archive / Restore — and a repository heading carries the one action that belongs to the group: a read-only check, then Update N skills. Every state is designed: skeleton in both views, empty, no-match, and a failed fetch with a retry.
…olumn keeps one width An Update button beside the kebab widened its own row's actions track and pushed that row's cells off the others'. The row now shows an icon at the kebab's size (and a check once applied); the card keeps the word.
…kill's own initials Ink on a tint derived from the origin's colour, through the same helper the agent icon chip uses, so a skill's mark beside an agent's reads as the same kind of thing. The letters are the name's initials — "sd" for shoot-demo-video — so a column of marks tells skills apart.
A list that groups skills by their source has nothing left to say in the source column; the author is the next thing a reader asks.
Grouped by source the heading already says where a skill came from, so the provenance column — and a card's footer — read the creator instead, resolved through the same owners roster the agents list uses.
The design's hover is a lighter border and a soft shadow. A shadow is nearly invisible on a dark surface, so dark mode adds the fill lift a row gets and a deeper shadow.
…actually have; the import skeleton's box is square
…chived switch, and Group by leads with None
…ter, in place of a one-row kebab
…; the drawer's popovers portal into its panel so their lists scroll under the sheet's lock
…er, in a popover on the kebab
… share one agent-skills commit
…skill back off it; the picker's rows are no longer inert
…d says so when the head fails to load
…nd a batch import drops what landed from its retry set
…nvalid upstream skills
…e agent picker's list is a listbox
… action only shows under a source heading
… subagent rows; the header, its count and Add all go
…t the left and Done at the right
…arch, closes the picker and opens the editor; Done waits for a change; SkillAvatar takes a className
… for the registry avatar and an agent config's skill rows
89f74a8 to
2c272ab
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
web/packages/agenta-skills-ui/src/SkillDetailDrawer.tsx (1)
219-223: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winThe draft still compares by serialized shape, not by value.
headValuealways carriesdescription: ""andfiles: [].SkillFormViewdeletes a key instead of storing an empty value. A user who types in Description and then clears it produces adraftwithout adescriptionkey.dirtythen stays true although the content equals the head. The drawer asks "Discard changes?" on close, and Save commits a revision identical to the head.Normalize both sides before comparing.
Proposed fix
const headValue = useMemo(() => toFormValue(head?.skill), [head]) + // The form drops a key rather than storing an empty value, so compare normalized shapes — + // otherwise "typed then cleared" reads as an edit. const dirty = useMemo( - () => editBaseId !== null && JSON.stringify(draft) !== JSON.stringify(headValue), + () => + editBaseId !== null && + JSON.stringify(toFormValue(draft)) !== JSON.stringify(headValue), [draft, editBaseId, headValue], )
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Advanced
Run ID: 17a4f205-b607-462a-9005-e17611cb9a98
📒 Files selected for processing (51)
api/oss/src/core/skills/dtos.pyapi/oss/src/core/skills/service.pyweb/mobile/src/features/skills/SkillActionsMenu.tsxweb/mobile/src/features/skills/SkillArchivedTag.tsxweb/mobile/src/features/skills/SkillCardBody.tsxweb/mobile/src/features/skills/SkillFilterMenu.tsxweb/mobile/src/features/skills/SkillListScreen.tsxweb/mobile/src/features/skills/SkillListTable.tsxweb/mobile/src/features/skills/SkillRowCells.tsxweb/mobile/src/features/skills/SkillSourceUpdateAction.tsxweb/mobile/src/features/skills/SkillUpdateCell.tsxweb/mobile/src/features/skills/skillListView.tsweb/mobile/src/features/skills/states/SkillsEmpty.tsxweb/mobile/src/features/skills/states/SkillsError.tsxweb/mobile/src/features/skills/states/SkillsNoMatch.tsxweb/mobile/src/features/skills/useSkillActions.tsweb/mobile/src/features/skills/useSkillUpdates.tsweb/oss/src/components/pages/skills/SkillsPage.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/AgentTemplateControl.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/ConfigItemDrawer.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/SkillFormView.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/ConfigItemList.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/itemDescriptors.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/itemKinds.tsxweb/packages/agenta-entity-ui/src/agent/AgentPicker.tsxweb/packages/agenta-entity-ui/src/agent/index.tsweb/packages/agenta-skills-ui/src/NewSkillMenuButton.tsxweb/packages/agenta-skills-ui/src/SkillAgentPicker.tsxweb/packages/agenta-skills-ui/src/SkillCard.tsxweb/packages/agenta-skills-ui/src/SkillCreateDrawer.tsxweb/packages/agenta-skills-ui/src/SkillDetailDrawer.tsxweb/packages/agenta-skills-ui/src/SkillImportDrawer.tsxweb/packages/agenta-skills-ui/src/SkillPickerDrawer.tsxweb/packages/agenta-skills-ui/src/SkillPickerHost.tsxweb/packages/agenta-skills-ui/src/SkillUploadPanel.tsxweb/packages/agenta-skills-ui/src/SourceRefreshButton.tsxweb/packages/agenta-skills-ui/src/index.tsweb/packages/agenta-skills-ui/src/useSkillCreateEntry.tsweb/packages/agenta-skills/src/api/index.tsweb/packages/agenta-skills/src/core/schema.tsweb/packages/agenta-ui/src/agent-icon/index.tsweb/packages/agenta-ui/src/agent-icon/skillMark.tsweb/packages/agenta-ui/src/components/ui/checkbox.tsxweb/packages/agenta-ui/src/drawer/EnhancedDrawer.tsxweb/packages/agenta-ui/src/list-table/ListTable.tsxweb/packages/agenta-ui/src/list-table/ListTableViewToggle.tsxweb/packages/agenta-ui/src/list-table/index.tsweb/packages/agenta-ui/src/list-table/types.tsweb/storybook/stories/ListTable.stories.tsxweb/storybook/stories/skills-ui/SkillPickerDrawer.stories.tsxweb/storybook/stories/skills-ui/SkillUploadPanel.stories.tsx
💤 Files with no reviewable changes (3)
- web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/ConfigItemList.tsx
- web/storybook/stories/skills-ui/SkillUploadPanel.stories.tsx
- web/packages/agenta-skills-ui/src/SkillUploadPanel.tsx
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.
| export const ALL_SOURCES = "all" | ||
| export const PROJECT_SOURCE = "project" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Namespace repository filter values.
ALL_SOURCES and PROJECT_SOURCE share the raw string namespace with repository labels. A repository named all selects all rows. A repository named project selects project-owned rows.
Prefix repository values or use a discriminated source value before matching and persistence.
Context
The Skills page on
/mwas a one-off: the desktop's card gallery under a search box and an "Archived skills" link, unlike the Agents and Automations lists next to it. There was no way to filter, group, or act on a skill from the list, and every other list on/malready shares one table frame.Changes
ListTablelearns a card view (@agenta/ui/list-table).view="grid"draws the same groups, headings and collapse as cards;renderCarddraws a card's contents and the frame owns the tile (border, radius, hover, open affordance, a card-shaped skeleton). Columns are container-driven (cardMinWidth, auto-fill), so one list fits a phone, a pane and a page.groupActionsputs a per-group action on a heading's right edge.ListTableViewToggleis the list/cards switch. List view is unchanged for every existing consumer.Skills on
/mbecomes the shared list. Title row withNew skill, aListTableToolbarwith search, the sharedFilterMenu(Source, Status, Used by, Group by) and the view toggle. Rows: skill mark with the name's initials (tinted like an agent chip), name and description, Created by or Source (depending on grouping), Used by, Last updated, and a kebab (Open, Check for updates, Archive/Restore). A repository heading carries "Check updates", then "Update N skills". Skeleton, empty, no-match and error states are designed.The detail drawer is editable from the start. No Edit step; Discard/Save sit in the footer, inert until the draft differs from the head. The header carries the name, provenance behind an info tooltip, a faded "Used by N agents" whose popover lists the agents as links, and a kebab whose popover offers Add to agent (the home page's agent picker as a flyout, ticking agents in place) and Archive (an alert scoped to the drawer). The pick-agents step is gone.
New skillreads likeNew agent. Three rows with a tinted tile, a name and a hint: Write from scratch, Upload, Import from a repo. Upload opens the file picker at once; one skill lands in the editor prefilled, several become a pick list that imports them together. The old full-drawer dropzone (SkillUploadPanel) is gone. Empty required fields redden only after Create or Save is pressed.Import from a repo. The URL field stays on top once scanned, the found skills sit under it as a labelled section with square checkboxes, the scan shows a skeleton, and a failed scan reads as an alert carrying the server's own sentence instead of the raw client error.
Inline skills in an agent's config. "Publish to registry" moves from the row into the skill drawer's footer, and publishes the draft as edited.
Shared helpers.
checkSkillUpdates/applySkillUpdatesin@agenta/skillsbatch the per-skill calls once for the desktop refresh button and the/mhook.useSkillCreateEntryin@agenta/skills-uiholds the create drawer's open/upload state for its three hosts.AgentPickerPanelis the agent picker's panel on its own, for a host with its own popover.Small API addition. Registry skills now carry
created_by_id, so a list grouped by source can name the author instead of repeating the heading.Tests
/mat desktop and 375px, light and dark: both views, filters and reset, group collapse, archive and restore, check and apply an upstream update, row and card open the drawer, agent links navigate, upload of one and of several skills, repo scan success and failure, publish from the inline drawer footer, the home page picker after the panel extraction.ListTable(list, grid, loading, empty); theSkillUploadPanelstory is removed with the component.ListTable.tsx; this PR's diff is only its own commits.What to QA
/mSkills: switch list and cards, reload. The view survives; the filters reset.Demo
Outstanding: this is a draft; a capture from the running app follows before review.