Add tree organization system with categories, tags, and folders
Features: - Categories: Global and team-specific tree categorization (admin-managed) - Tags: Flexible tree tagging with autocomplete (author + admin) - User folders: Personal tree collections with subfolder support - Hierarchical structure (max 3 levels deep) - Right-click context menu for folder management - Cascade delete for subfolders - Filter trees by category, tags, and folder in library view Backend: - New models: Category, Tag, UserFolder with relationships - New API endpoints for categories, tags, and folders - Tree organization migrations (005, 006) Frontend: - FolderSidebar with hierarchical folder tree - FolderEditModal for create/edit with color picker - AddToFolderMenu for quick tree organization - TagInput with autocomplete and TagBadges display - Updated TreeMetadataForm and TreeLibraryPage Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
45
frontend/src/types/category.ts
Normal file
45
frontend/src/types/category.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// Category types for tree organization
|
||||
|
||||
export interface Category {
|
||||
id: string
|
||||
name: string
|
||||
slug: string
|
||||
description: string | null
|
||||
team_id: string | null
|
||||
display_order: number
|
||||
is_active: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
tree_count: number
|
||||
}
|
||||
|
||||
export interface CategoryListItem {
|
||||
id: string
|
||||
name: string
|
||||
slug: string
|
||||
description: string | null
|
||||
team_id: string | null
|
||||
display_order: number
|
||||
is_active: boolean
|
||||
tree_count: number
|
||||
}
|
||||
|
||||
export interface CategoryCreate {
|
||||
name: string
|
||||
description?: string | null
|
||||
team_id?: string | null
|
||||
}
|
||||
|
||||
export interface CategoryUpdate {
|
||||
name?: string
|
||||
description?: string | null
|
||||
display_order?: number
|
||||
is_active?: boolean
|
||||
}
|
||||
|
||||
// Embedded category info for tree responses
|
||||
export interface CategoryInfo {
|
||||
id: string
|
||||
name: string
|
||||
slug: string
|
||||
}
|
||||
52
frontend/src/types/folder.ts
Normal file
52
frontend/src/types/folder.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
// Folder types for user tree organization
|
||||
|
||||
export interface Folder {
|
||||
id: string
|
||||
name: string
|
||||
color: string
|
||||
icon: string
|
||||
parent_id: string | null
|
||||
display_order: number
|
||||
tree_count: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface FolderListItem {
|
||||
id: string
|
||||
name: string
|
||||
color: string
|
||||
icon: string
|
||||
parent_id: string | null
|
||||
display_order: number
|
||||
tree_count: number
|
||||
}
|
||||
|
||||
export interface FolderCreate {
|
||||
name: string
|
||||
color?: string
|
||||
icon?: string
|
||||
parent_id?: string | null
|
||||
}
|
||||
|
||||
export interface FolderUpdate {
|
||||
name?: string
|
||||
color?: string
|
||||
icon?: string
|
||||
display_order?: number
|
||||
parent_id?: string | null
|
||||
}
|
||||
|
||||
export interface FolderReorderRequest {
|
||||
folder_ids: string[]
|
||||
}
|
||||
|
||||
export interface FolderTreeRequest {
|
||||
tree_id: string
|
||||
}
|
||||
|
||||
// For hierarchical display of folders
|
||||
export interface FolderTreeItem extends FolderListItem {
|
||||
children: FolderTreeItem[]
|
||||
isExpanded?: boolean
|
||||
}
|
||||
@@ -3,6 +3,9 @@ export * from './auth'
|
||||
export * from './tree'
|
||||
export * from './session'
|
||||
export * from './invite'
|
||||
export * from './tag'
|
||||
export * from './category'
|
||||
export * from './folder'
|
||||
|
||||
// API response wrapper types
|
||||
export interface PaginatedResponse<T> {
|
||||
|
||||
27
frontend/src/types/tag.ts
Normal file
27
frontend/src/types/tag.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// Tag types for tree organization
|
||||
|
||||
export interface Tag {
|
||||
id: string
|
||||
name: string
|
||||
slug: string
|
||||
team_id: string | null
|
||||
usage_count: number
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface TagListItem {
|
||||
id: string
|
||||
name: string
|
||||
slug: string
|
||||
team_id: string | null
|
||||
usage_count: number
|
||||
}
|
||||
|
||||
export interface TagCreate {
|
||||
name: string
|
||||
team_id?: string | null
|
||||
}
|
||||
|
||||
export interface TagAssignment {
|
||||
tags: string[]
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { CategoryInfo } from './category'
|
||||
|
||||
// Tree node types
|
||||
export type NodeType = 'decision' | 'action' | 'solution'
|
||||
|
||||
@@ -60,10 +62,15 @@ export interface Tree {
|
||||
name: string
|
||||
description: string | null
|
||||
category: string | null
|
||||
category_id: string | null
|
||||
category_info: CategoryInfo | null
|
||||
tags: string[]
|
||||
tree_structure: TreeStructure
|
||||
author_id: string | null
|
||||
team_id: string | null
|
||||
is_active: boolean
|
||||
is_public: boolean
|
||||
is_default: boolean
|
||||
version: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
@@ -75,7 +82,13 @@ export interface TreeListItem {
|
||||
name: string
|
||||
description: string | null
|
||||
category: string | null
|
||||
category_id: string | null
|
||||
category_info: CategoryInfo | null
|
||||
tags: string[]
|
||||
author_id: string | null
|
||||
is_active: boolean
|
||||
is_public: boolean
|
||||
is_default: boolean
|
||||
version: number
|
||||
usage_count: number
|
||||
created_at: string
|
||||
@@ -86,13 +99,33 @@ export interface TreeCreate {
|
||||
name: string
|
||||
description?: string
|
||||
category?: string
|
||||
category_id?: string | null
|
||||
tags?: string[]
|
||||
tree_structure: TreeStructure
|
||||
is_public?: boolean
|
||||
is_default?: boolean
|
||||
}
|
||||
|
||||
export interface TreeUpdate {
|
||||
name?: string
|
||||
description?: string
|
||||
category?: string
|
||||
category_id?: string | null
|
||||
tags?: string[]
|
||||
tree_structure?: TreeStructure
|
||||
is_active?: boolean
|
||||
is_public?: boolean
|
||||
}
|
||||
|
||||
// Filter params for tree listing
|
||||
export interface TreeFilters {
|
||||
category?: string
|
||||
category_id?: string
|
||||
tags?: string
|
||||
folder_id?: string
|
||||
is_active?: boolean
|
||||
author_id?: string
|
||||
is_public?: boolean
|
||||
skip?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ export interface User {
|
||||
email: string
|
||||
name: string
|
||||
role: UserRole
|
||||
is_team_admin: boolean
|
||||
team_id: string | null
|
||||
created_at: string
|
||||
last_login: string | null
|
||||
|
||||
Reference in New Issue
Block a user