mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
### Changes 🏗️ This PR adds folder organization capabilities to the library, allowing users to organize their agents into folders: - Added new `LibraryFolder` model and database schema - Created folder management API endpoints for CRUD operations - Implemented folder tree structure with proper parent-child relationships - Added drag-and-drop functionality for moving agents between folders - Created folder creation dialog with emoji picker for folder icons - Added folder editing and deletion capabilities - Implemented folder navigation in the library UI - Added validation to prevent circular references and excessive nesting - Created animation for favoriting agents - Updated library agent list to show folder structure - Added folder filtering to agent list queries <img width="1512" height="950" alt="Screenshot 2026-02-13 at 9 08 45 PM" src="https://github.com/user-attachments/assets/78778e03-4349-4d50-ad71-d83028ca004a" /> ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Create a new folder with custom name, icon, and color - [x] Move agents into folders via drag and drop - [x] Move agents into folders via context menu - [x] Navigate between folders - [x] Edit folder properties (name, icon, color) - [x] Delete folders and verify agents return to root - [x] Verify favorite animation works when adding to favorites - [x] Test folder navigation with search functionality - [x] Verify folder tree structure is maintained #### For configuration changes: - [x] `.env.default` is updated or already compatible with my changes - [x] `docker-compose.yml` is updated or already compatible with my changes - [x] I have included a list of my configuration changes in the PR description (under **Changes**) <!-- greptile_comment --> <h2>Greptile Overview</h2> <details><summary><h3>Greptile Summary</h3></summary> This PR implements a comprehensive folder organization system for library agents, enabling hierarchical structure up to 5 levels deep. **Backend Changes:** - Added `LibraryFolder` model with self-referential hierarchy (`parentId` → `Parent`/`Children`) - Implemented CRUD operations with validation for circular references and depth limits (MAX_FOLDER_DEPTH=5) - Added `folderId` foreign key to `LibraryAgent` table - Created folder management endpoints: list, get, create, update, move, delete, and bulk agent moves - Proper soft-delete cascade handling for folders and their contained agents **Frontend Changes:** - Created folder creation/edit/delete dialogs with emoji picker integration - Implemented folder navigation UI with breadcrumbs and folder tree structure - Added drag-and-drop support for moving agents between folders - Created context menu for agent actions (move to folder, remove from folder) - Added favorite animation system with `FavoriteAnimationProvider` - Integrated folder filtering into agent list queries **Key Features:** - Folders support custom names, emoji icons, and hex colors - Unique constraint per parent folder per user prevents duplicate names - Validation prevents circular folder hierarchies and excessive nesting - Agents can be moved between folders via drag-drop or context menu - Deleting a folder soft-deletes all descendant folders and contained agents </details> <details><summary><h3>Confidence Score: 4/5</h3></summary> - This PR is safe to merge with minor considerations for performance optimization - The implementation is well-structured with proper validation, error handling, and database constraints. The folder hierarchy logic correctly prevents circular references and enforces depth limits. However, there are some performance concerns with N+1 queries in depth calculation and circular reference checking that could be optimized for deeply nested hierarchies. The foreign key constraint (ON DELETE RESTRICT) conflicts with the hard-delete code path but shouldn't cause issues since soft-deletes are the default. The client-side duplicate validation is redundant but not harmful. - Pay close attention to migration file (foreign key constraint) and db.py (performance of recursive queries) </details> <details><summary><h3>Sequence Diagram</h3></summary> ```mermaid sequenceDiagram participant User participant Frontend participant API participant DB User->>Frontend: Create folder with name/icon/color Frontend->>API: POST /v2/folders API->>DB: Validate parent exists & depth limit API->>DB: Check unique constraint (userId, parentId, name) DB-->>API: Folder created API-->>Frontend: LibraryFolder response Frontend-->>User: Show success toast User->>Frontend: Drag agent to folder Frontend->>API: POST /v2/folders/agents/bulk-move API->>DB: Verify folder exists API->>DB: Update LibraryAgent.folderId DB-->>API: Agents updated API-->>Frontend: Updated agents Frontend-->>User: Refresh agent list User->>Frontend: Navigate into folder Frontend->>API: GET /v2/library/agents?folder_id=X API->>DB: Query agents WHERE folderId=X DB-->>API: Filtered agents API-->>Frontend: Agent list Frontend-->>User: Display folder contents User->>Frontend: Delete folder Frontend->>API: DELETE /v2/folders/{id} API->>DB: Get descendant folders recursively API->>DB: Soft-delete folders + agents in transaction DB-->>API: Deletion complete API-->>Frontend: 204 No Content Frontend-->>User: Show success toast ``` </details> <sub>Last reviewed commit: a6c2f64</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->
189 lines
6.3 KiB
JSON
189 lines
6.3 KiB
JSON
{
|
|
"name": "frontend",
|
|
"version": "0.3.4",
|
|
"private": true,
|
|
"engines": {
|
|
"node": "22.x"
|
|
},
|
|
"scripts": {
|
|
"dev": "pnpm run generate:api:force && next dev --turbo",
|
|
"build": "cross-env NODE_OPTIONS=--max-old-space-size=16384 next build",
|
|
"start": "next start",
|
|
"start:standalone": "cd .next/standalone && node server.js",
|
|
"lint": "next lint && prettier --check .",
|
|
"format": "next lint --fix; prettier --write .",
|
|
"types": "tsc --noEmit",
|
|
"test": "NEXT_PUBLIC_PW_TEST=true next build --turbo && playwright test",
|
|
"test-ui": "NEXT_PUBLIC_PW_TEST=true next build --turbo && playwright test --ui",
|
|
"test:unit": "vitest run",
|
|
"test:unit:watch": "vitest",
|
|
"test:no-build": "playwright test",
|
|
"gentests": "playwright codegen http://localhost:3000",
|
|
"storybook": "storybook dev -p 6006",
|
|
"build-storybook": "storybook build",
|
|
"test-storybook": "test-storybook",
|
|
"test-storybook:ci": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"pnpm run build-storybook -- --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && pnpm run test-storybook\"",
|
|
"generate:api": "npx --yes tsx ./scripts/generate-api-queries.ts && orval --config ./orval.config.ts",
|
|
"generate:api:force": "npx --yes tsx ./scripts/generate-api-queries.ts --force && orval --config ./orval.config.ts"
|
|
},
|
|
"browserslist": [
|
|
"defaults"
|
|
],
|
|
"dependencies": {
|
|
"@ai-sdk/react": "3.0.61",
|
|
"@faker-js/faker": "10.0.0",
|
|
"@ferrucc-io/emoji-picker": "0.0.48",
|
|
"@hookform/resolvers": "5.2.2",
|
|
"@next/third-parties": "15.4.6",
|
|
"@phosphor-icons/react": "2.1.10",
|
|
"@posthog/react": "1.7.0",
|
|
"@radix-ui/react-accordion": "1.2.12",
|
|
"@radix-ui/react-alert-dialog": "1.1.15",
|
|
"@radix-ui/react-avatar": "1.1.10",
|
|
"@radix-ui/react-checkbox": "1.3.3",
|
|
"@radix-ui/react-collapsible": "1.1.12",
|
|
"@radix-ui/react-context-menu": "2.2.16",
|
|
"@radix-ui/react-dialog": "1.1.15",
|
|
"@radix-ui/react-dropdown-menu": "2.1.16",
|
|
"@radix-ui/react-icons": "1.3.2",
|
|
"@radix-ui/react-label": "2.1.7",
|
|
"@radix-ui/react-popover": "1.1.15",
|
|
"@radix-ui/react-radio-group": "1.3.8",
|
|
"@radix-ui/react-scroll-area": "1.2.10",
|
|
"@radix-ui/react-select": "2.2.6",
|
|
"@radix-ui/react-separator": "1.1.7",
|
|
"@radix-ui/react-slider": "1.3.6",
|
|
"@radix-ui/react-slot": "1.2.3",
|
|
"@radix-ui/react-switch": "1.2.6",
|
|
"@radix-ui/react-tabs": "1.1.13",
|
|
"@radix-ui/react-toast": "1.2.15",
|
|
"@radix-ui/react-tooltip": "1.2.8",
|
|
"@rjsf/core": "6.1.2",
|
|
"@rjsf/utils": "6.1.2",
|
|
"@rjsf/validator-ajv8": "6.1.2",
|
|
"@sentry/nextjs": "10.27.0",
|
|
"@streamdown/cjk": "1.0.1",
|
|
"@streamdown/math": "1.0.1",
|
|
"@streamdown/mermaid": "1.0.1",
|
|
"@supabase/ssr": "0.7.0",
|
|
"@supabase/supabase-js": "2.78.0",
|
|
"@tanstack/react-query": "5.90.6",
|
|
"@tanstack/react-table": "8.21.3",
|
|
"@types/jaro-winkler": "0.2.4",
|
|
"@vercel/analytics": "1.5.0",
|
|
"@vercel/speed-insights": "1.2.0",
|
|
"@xyflow/react": "12.9.2",
|
|
"ai": "6.0.59",
|
|
"boring-avatars": "1.11.2",
|
|
"class-variance-authority": "0.7.1",
|
|
"clsx": "2.1.1",
|
|
"cmdk": "1.1.1",
|
|
"cookie": "1.0.2",
|
|
"date-fns": "4.1.0",
|
|
"dexie": "4.2.1",
|
|
"dotenv": "17.2.3",
|
|
"elliptic": "6.6.1",
|
|
"embla-carousel-react": "8.6.0",
|
|
"flatbush": "4.5.0",
|
|
"framer-motion": "12.23.24",
|
|
"geist": "1.5.1",
|
|
"highlight.js": "11.11.1",
|
|
"jaro-winkler": "0.2.8",
|
|
"katex": "0.16.25",
|
|
"launchdarkly-react-client-sdk": "3.9.0",
|
|
"lodash": "4.17.21",
|
|
"lucide-react": "0.552.0",
|
|
"next": "15.4.10",
|
|
"next-themes": "0.4.6",
|
|
"nuqs": "2.7.2",
|
|
"party-js": "2.2.0",
|
|
"posthog-js": "1.334.1",
|
|
"react": "18.3.1",
|
|
"react-currency-input-field": "4.0.3",
|
|
"react-day-picker": "9.11.1",
|
|
"react-dom": "18.3.1",
|
|
"react-hook-form": "7.66.0",
|
|
"react-icons": "5.5.0",
|
|
"react-markdown": "9.0.3",
|
|
"react-modal": "3.16.3",
|
|
"react-shepherd": "6.1.9",
|
|
"react-window": "2.2.0",
|
|
"recharts": "3.3.0",
|
|
"rehype-autolink-headings": "7.1.0",
|
|
"rehype-highlight": "7.0.2",
|
|
"rehype-katex": "7.0.1",
|
|
"rehype-slug": "6.0.0",
|
|
"remark-gfm": "4.0.1",
|
|
"remark-math": "6.0.0",
|
|
"shepherd.js": "14.5.1",
|
|
"shiki": "^3.21.0",
|
|
"sonner": "2.0.7",
|
|
"streamdown": "2.1.0",
|
|
"tailwind-merge": "2.6.0",
|
|
"tailwind-scrollbar": "3.1.0",
|
|
"tailwindcss-animate": "1.0.7",
|
|
"use-stick-to-bottom": "1.1.2",
|
|
"uuid": "11.1.0",
|
|
"vaul": "1.1.2",
|
|
"zod": "3.25.76",
|
|
"zustand": "5.0.8"
|
|
},
|
|
"devDependencies": {
|
|
"@chromatic-com/storybook": "4.1.2",
|
|
"@opentelemetry/instrumentation": "0.209.0",
|
|
"@playwright/test": "1.56.1",
|
|
"@storybook/addon-a11y": "9.1.5",
|
|
"@storybook/addon-docs": "9.1.5",
|
|
"@storybook/addon-links": "9.1.5",
|
|
"@storybook/addon-onboarding": "9.1.5",
|
|
"@storybook/nextjs": "9.1.5",
|
|
"@tanstack/eslint-plugin-query": "5.91.2",
|
|
"@tanstack/react-query-devtools": "5.90.2",
|
|
"@testing-library/dom": "10.4.1",
|
|
"@testing-library/react": "16.3.2",
|
|
"@types/canvas-confetti": "1.9.0",
|
|
"@types/lodash": "4.17.20",
|
|
"@types/negotiator": "0.6.4",
|
|
"@types/node": "24.10.0",
|
|
"@types/react": "18.3.17",
|
|
"@types/react-dom": "18.3.5",
|
|
"@types/react-modal": "3.16.3",
|
|
"@types/react-window": "2.0.0",
|
|
"@vitejs/plugin-react": "5.1.2",
|
|
"axe-playwright": "2.2.2",
|
|
"chromatic": "13.3.3",
|
|
"concurrently": "9.2.1",
|
|
"cross-env": "10.1.0",
|
|
"eslint": "8.57.1",
|
|
"eslint-config-next": "15.5.7",
|
|
"eslint-plugin-storybook": "9.1.5",
|
|
"happy-dom": "20.3.4",
|
|
"import-in-the-middle": "2.0.2",
|
|
"msw": "2.11.6",
|
|
"msw-storybook-addon": "2.0.6",
|
|
"orval": "7.13.0",
|
|
"pbkdf2": "3.1.5",
|
|
"postcss": "8.5.6",
|
|
"prettier": "3.6.2",
|
|
"prettier-plugin-tailwindcss": "0.7.1",
|
|
"require-in-the-middle": "8.0.1",
|
|
"storybook": "9.1.5",
|
|
"tailwindcss": "3.4.17",
|
|
"typescript": "5.9.3",
|
|
"vite-tsconfig-paths": "6.0.4",
|
|
"vitest": "4.0.17"
|
|
},
|
|
"msw": {
|
|
"workerDirectory": [
|
|
"public"
|
|
]
|
|
},
|
|
"pnpm": {
|
|
"overrides": {
|
|
"@opentelemetry/instrumentation": "0.209.0",
|
|
"lodash-es": "4.17.23"
|
|
}
|
|
},
|
|
"packageManager": "pnpm@10.20.0+sha512.cf9998222162dd85864d0a8102e7892e7ba4ceadebbf5a31f9c2fce48dfce317a9c53b9f6464d1ef9042cba2e02ae02a9f7c143a2b438cd93c91840f0192b9dd"
|
|
}
|