gui: sidebar tree UX fixes — has_children, preserve expanded, double-click, DnD visual
- Backend: add HasChildren field to NodeDTO; ListWorkspaceTree/ListChildren populate it by querying CountChildren for container types - Node repository: add CountChildren(parentID, types...) method - TreeNode: toggle shown only when has_children (not isContainer); double-click on row = expand/collapse; icon click = expand/collapse; drop-valid class via DOM classList for DnD highlight; auto-expand collapsed container on 500ms hover during drag; auto-scroll near edge during drag - App.svelte: selectNode no longer resets workspaceTree/expanded; new reloadTreePreservingExpanded() helper re-fetches children for all expanded nodes after DnD move / delete; deleteWorkspaceNode preserves expanded state
This commit is contained in:
+11
-10
@@ -104,16 +104,17 @@ func (a *App) autoSyncLoop() {
|
||||
// ============================================================
|
||||
|
||||
type NodeDTO struct {
|
||||
ID string `json:"id"`
|
||||
ParentID *string `json:"parent_id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
TemplateID string `json:"template_id"`
|
||||
FsPath string `json:"fs_path"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Archived bool `json:"archived"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
ID string `json:"id"`
|
||||
ParentID *string `json:"parent_id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
TemplateID string `json:"template_id"`
|
||||
FsPath string `json:"fs_path"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Archived bool `json:"archived"`
|
||||
HasChildren bool `json:"has_children"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
type TemplateDTO struct {
|
||||
|
||||
@@ -19,7 +19,15 @@ func (a *App) ListWorkspaceTree() ([]NodeDTO, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return filterContainers(toNodeDTOs(list)), nil
|
||||
dtos := filterContainers(toNodeDTOs(list))
|
||||
for i := range dtos {
|
||||
n, err := a.nodes.CountChildren(dtos[i].ID, "case", "client", "project", "folder", "document", "recipe")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dtos[i].HasChildren = n > 0
|
||||
}
|
||||
return dtos, nil
|
||||
}
|
||||
|
||||
func (a *App) ListWorkspaceChildren(parentID string) ([]NodeDTO, error) {
|
||||
@@ -27,7 +35,15 @@ func (a *App) ListWorkspaceChildren(parentID string) ([]NodeDTO, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return filterContainers(toNodeDTOs(list)), nil
|
||||
dtos := filterContainers(toNodeDTOs(list))
|
||||
for i := range dtos {
|
||||
n, err := a.nodes.CountChildren(dtos[i].ID, "case", "client", "project", "folder", "document", "recipe")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dtos[i].HasChildren = n > 0
|
||||
}
|
||||
return dtos, nil
|
||||
}
|
||||
|
||||
func filterContainers(dtos []NodeDTO) []NodeDTO {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -16,8 +16,8 @@
|
||||
background: #13131f;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/main-Dt9BLCiY.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-CHi9sCXv.css">
|
||||
<script type="module" crossorigin src="/assets/main-y7k2Kn7r.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-CJu7OoK7.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
Reference in New Issue
Block a user