feat: frontend archive UI#4229
Conversation
…frontend-archive-ui
…anagement into mode-scoped bundles
…s and specific table columns
…des in the testset management system
…luators UI components
…ort to archived Testset and Workflow tables
…lity in TestsetsTable
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…tor cache supporting archived workflows and persistent metadata entries.
…and consolidate paginated store logic with shared helpers
…w toggle to application management header
…e with custom row merging
…paginated store with shared helpers and factory functions
…hecks for routing and deletion
…frontend-archive-ui
…AI/agenta into feat/frontend-archive-ui
Previously the archived apps page briefly displayed the "no archived apps" empty state before swapping to the loaded table. Render the table (with skeleton rows) while the archived count query is in flight so the empty state only appears once we know the list is actually empty.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdds frontend archived-entity views for Apps, Evaluators, and Testsets: a shared ArchivedEntityLayout, mode-aware tables/columns, archived paginated stores that fetch with includeArchived and filter/sort by deleted_at client-side, detail fetchers updated to accept includeArchived, archive/unarchive lifecycle wiring on molecules, route re-exports, and updated UI copy/tests. ChangesArchived Entities Feature Implementation
Sequence DiagramssequenceDiagram
participant User
participant Page as Archived Page
participant Table as Table/Columns
participant Store as Paginated Store
participant API as Backend API
User->>Page: Navigate to /archived
activate Page
Page->>Store: getTestsetTableState("archived")
activate Store
Store->>API: Fetch items with include_archived=true
activate API
API-->>Store: Return items with deleted_at
deactivate API
Store->>Store: Filter rows by deleted_at, sort desc
Store->>Store: Slice by cursor offset
Store-->>Page: Return paginated archived rows
deactivate Store
Page->>Table: Render with mode="archived"
activate Table
Table->>Table: Show archived-only columns (deletedAt, deletedBy)
Table->>Table: Show Restore action
Table-->>Page: Render table
deactivate Table
Page-->>User: Display archived entities
deactivate Page
sequenceDiagram
participant User
participant Table as Table
participant Molecule as Lifecycle Molecule
participant API as Backend API
participant Store as Paginated Store
User->>Table: Click Restore on a row
activate Table
Table->>Molecule: lifecycle.unarchive(entityId, {projectId})
activate Molecule
Molecule->>API: POST /.../unarchive
activate API
API-->>Molecule: Success
deactivate API
Molecule->>Store: Invalidate archived & active stores / clear caches
Molecule-->>Table: Return success
deactivate Molecule
Table-->>User: Show success message
Table->>Store: Refresh archived list
activate Store
Store->>API: Fetch updated archived list
API-->>Store: Return updated list
Store-->>Table: Updated paginated data (row removed)
deactivate Store
Table-->>User: Update table (row removed)
deactivate Table
sequenceDiagram
participant User
participant ActivePage as Active Page
participant Modal as Archive Modal
participant Molecule as Lifecycle Molecule
participant API as Backend API
participant Stores as Active + Archived Stores
User->>ActivePage: Click Archive action on row
activate ActivePage
ActivePage->>Modal: Open archive confirmation modal
activate Modal
Modal-->>User: Show "Archive {name}?" dialog
User->>Modal: Confirm "Archive"
Modal->>Molecule: lifecycle.archive(workflowId, {projectId})
activate Molecule
Molecule->>API: POST /.../archive
activate API
API-->>Molecule: Success
deactivate API
Molecule->>Stores: Invalidate active & archived paginated stores and counts
Molecule-->>Modal: Return success
deactivate Molecule
Modal-->>User: Show "Archived" success message
Modal->>ActivePage: onArchived callback
deactivate Modal
ActivePage->>ActivePage: Refetch active list
ActivePage-->>User: Remove archived row from active view
deactivate ActivePage
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes ✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
web/oss/src/components/Evaluators/index.tsx (1)
216-262:⚠️ Potential issue | 🟠 Major | ⚡ Quick winInvalidate the evaluator table after archive/unarchive.
These handlers call
workflowMolecule.lifecycle.archive/unarchive(), but this screen is driven bygetEvaluatorsTableState(mode).paginatedStore. WithoutinvalidateEvaluatorsListCache()/refetchAll()after success, the row can remain in the active or archived table until a manual reload.Suggested fix
const handleRestore = useCallback(async (record: EvaluatorTableRow) => { try { const {projectId} = getProjectValues() if (!projectId || !record.workflowId) return await workflowMolecule.lifecycle.unarchive(record.workflowId, {projectId}) + refetchAll() message.success("Evaluator restored") } catch (error) { message.error(extractApiErrorMessage(error)) } -}, []) +}, [refetchAll]) const handleConfirmDelete = useCallback(async () => { if (!deleteTargetIds.length) return try { setIsDeleting(true) const {projectId} = getProjectValues() if (!projectId) return @@ await Promise.all( deleteTargetIds.map((id) => workflowMolecule.lifecycle.archive(id, {projectId})), ) + refetchAll() message.success(web/oss/src/components/pages/app-management/modals/DeleteAppModal/index.tsx (1)
44-46:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSurface archive failures to the user.
The failure path only logs to the console, so a rejected archive request leaves the modal open with no visible explanation. Please show an error toast here as well.
Minimal fix
} catch (error) { console.error("Failed to archive app:", error) + message.error("Failed to archive app") } finally {web/oss/src/components/pages/prompts/PromptsPage.tsx (1)
419-425:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon't continue template retry after a failed archive.
catch(console.error)consumes the cleanup failure, and Line 425 can create a new app anyway. That leaves the timed-out app unarchived and makes duplicate prompts possible.Suggested fix
- await workflowMolecule.lifecycle - .archive(statusData.appId, {projectId}) - .catch(console.error) + try { + await workflowMolecule.lifecycle.archive(statusData.appId, {projectId}) + } catch (error) { + console.error(error) + setStatusData((prev) => ({...prev, status: "error", details: error})) + return + } refetchWorkflows()
🧹 Nitpick comments (5)
web/packages/agenta-entities/src/workflow/core/types.ts (1)
22-26: ⚡ Quick winRequire an actual identifier in
workflowRefs.
WorkflowReferencecurrently allows{}, soqueryWorkflows({ workflowRefs: [{}] })type-checks even though the backend has nothing to resolve. Tightening this new public type to require at leastidorslugwill prevent invalid requests from escaping the client.♻️ Proposed type tightening
-export interface WorkflowReference { - id?: string - slug?: string - version?: string -} +type WorkflowReferenceBase = { + version?: string +} + +export type WorkflowReference = + | (WorkflowReferenceBase & {id: string; slug?: string}) + | (WorkflowReferenceBase & {id?: string; slug: string})web/oss/src/services/testsets/api/index.ts (1)
271-281: ⚡ Quick winUse shared API utilities for new endpoint helpers.
For newly added API helper paths, route through
@agenta/shared/api(axios,getAgentaApiUrl) to keep OSS/EE behavior aligned and avoid duplicate API plumbing patterns.As per coding guidelines, "Use
@agenta/shared/apifor API utilities like axios, getAgentaApiUrl, getEnv, configureAxios".web/oss/src/components/Evaluators/index.tsx (1)
333-343: ⚡ Quick winDebounce the search term before writing it into table state.
setSearchTerm()runs on every keypress, andsearchDeps={[searchTerm]}will make the table react to each one. Please debounce the input before updating the atom.As per coding guidelines, "Use
@agenta/shared/hooksfor shared React hooks like useDebounceInput" and "Debounce search inputs and filters; throttle scroll and resize handlers."web/oss/src/components/TestsetsTable/assets/createTestsetsColumns.tsx (1)
1-1: ⚡ Quick winAvoid the deep
@agenta/entities/shared/userimport.Please pull
UserAuthorLabelfrom the package’s public export surface here instead of reaching into an internal path. That keeps this table from depending on@agenta/entitiesfolder structure.As per coding guidelines, "Use
@agenta/entitiesclean named exports for entity state management (molecules), bridges, and UI components".web/oss/tests/playwright/acceptance/testsset/testset-management.ts (1)
445-447: 🏗️ Heavy liftAdd a round-trip archive → restore acceptance case.
This now exercises the renamed archive action, but the new restore path is still untested. A regression in the archived table wiring or unarchive invalidation would slip through this suite.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: c2f15224-8560-41a2-8284-85aa4c1537ce
📒 Files selected for processing (60)
docs/design/archive-workflows/archived-entities-view-design.mdweb/ee/src/pages/w/[workspace_id]/p/[project_id]/apps/archived/index.tsxweb/ee/src/pages/w/[workspace_id]/p/[project_id]/evaluators/archived/index.tsxweb/ee/src/pages/w/[workspace_id]/p/[project_id]/testsets/archived/index.tsxweb/oss/src/components/ArchivedEntityLayout/index.tsxweb/oss/src/components/ArchivedEntityLayout/types.tsweb/oss/src/components/Evaluators/ArchivedEvaluatorsPage.tsxweb/oss/src/components/Evaluators/Table/EvaluatorsTable.tsxweb/oss/src/components/Evaluators/Table/assets/evaluatorColumns.tsxweb/oss/src/components/Evaluators/assets/cells/TableDropdownMenu/index.tsxweb/oss/src/components/Evaluators/components/DeleteEvaluatorsModal/assets/DeleteEvaluatorsModalContent/index.tsxweb/oss/src/components/Evaluators/components/DeleteEvaluatorsModal/index.tsxweb/oss/src/components/Evaluators/index.tsxweb/oss/src/components/Evaluators/store/evaluatorsPaginatedStore.tsweb/oss/src/components/TestcasesTableNew/hooks/api.tsweb/oss/src/components/TestsetsTable/TestsetsTable.tsxweb/oss/src/components/TestsetsTable/assets/createTestsetsColumns.tsxweb/oss/src/components/TestsetsTable/components/TestsetsFiltersContent.tsxweb/oss/src/components/TestsetsTable/components/TestsetsFiltersSummary.tsxweb/oss/src/components/TestsetsTable/components/TestsetsHeaderFilters.tsxweb/oss/src/components/TestsetsTable/hooks/useTestsetsColumns.tsxweb/oss/src/components/pages/app-management/ArchivedAppsPage.tsxweb/oss/src/components/pages/app-management/components/ApplicationManagementSection.tsxweb/oss/src/components/pages/app-management/components/appWorkflowColumns.tsxweb/oss/src/components/pages/app-management/index.tsxweb/oss/src/components/pages/app-management/modals/DeleteAppModal/index.tsxweb/oss/src/components/pages/app-management/modals/DeleteAppModal/store/deleteAppModalStore.tsweb/oss/src/components/pages/app-management/store/appWorkflowStore.tsweb/oss/src/components/pages/app-management/store/index.tsweb/oss/src/components/pages/prompts/PromptsPage.tsxweb/oss/src/components/pages/prompts/components/PromptsTableSection.tsxweb/oss/src/components/pages/prompts/hooks/usePromptsColumns.tsxweb/oss/src/components/pages/prompts/store.tsweb/oss/src/components/pages/testset/ArchivedTestsetsPage.tsxweb/oss/src/components/pages/testset/modals/DeleteTestset.tsxweb/oss/src/pages/w/[workspace_id]/p/[project_id]/apps/archived/index.tsxweb/oss/src/pages/w/[workspace_id]/p/[project_id]/evaluators/archived/index.tsxweb/oss/src/pages/w/[workspace_id]/p/[project_id]/testsets/archived/index.tsxweb/oss/src/services/testsets/api/index.tsweb/oss/src/state/app/atoms/fetcher.tsweb/oss/src/state/app/selectors/app.tsweb/oss/src/state/appState/parse.tsweb/oss/src/state/entities/shared/createPaginatedEntityStore.tsweb/oss/src/state/entities/shared/index.tsweb/oss/src/state/entities/shared/utils.tsweb/oss/src/state/entities/testset/index.tsweb/oss/src/state/entities/testset/paginatedStore.tsweb/oss/src/state/entities/testset/store.tsweb/oss/src/state/entities/testset/testsetController.tsweb/oss/tests/playwright/acceptance/evaluators/tests.tsweb/oss/tests/playwright/acceptance/testsset/testset-management.tsweb/packages/agenta-entities/src/shared/user/UserAuthorLabel.tsxweb/packages/agenta-entities/src/testset/api/index.tsweb/packages/agenta-entities/src/testset/api/mutations.tsweb/packages/agenta-entities/src/testset/index.tsweb/packages/agenta-entities/src/testset/state/testsetMolecule.tsweb/packages/agenta-entities/src/workflow/api/api.tsweb/packages/agenta-entities/src/workflow/core/types.tsweb/packages/agenta-entities/src/workflow/state/evaluatorUtils.tsweb/packages/agenta-entities/src/workflow/state/molecule.ts
💤 Files with no reviewable changes (1)
- web/packages/agenta-entities/src/shared/user/UserAuthorLabel.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: ae80848f-cfea-42fd-8cdb-be926b01a46f
📒 Files selected for processing (3)
web/oss/src/components/ArchivedEntityLayout/index.tsxweb/oss/src/components/Evaluators/index.tsxweb/oss/src/components/Evaluators/store/evaluatorsPaginatedStore.ts
✅ Files skipped from review due to trivial changes (1)
- web/oss/src/components/ArchivedEntityLayout/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- web/oss/src/components/Evaluators/index.tsx
What's new
Implemented an archived view for workflows, to restore the archived workflows.
Implemented archived UI for:
Chnages
archiveandunarchiveactions to molecule levelinclude_archiveon the existing queryWorkflow for fetching the archive dataarchiveto render some view conditionallyDelete->Archivefor better understanding about the action