From 1568fa40d1b1201ac75f5d9e14caef8bb0e8b304 Mon Sep 17 00:00:00 2001 From: Dan Piths <85949566+danpiths@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:24:40 +0530 Subject: [PATCH] fix: skills repo removes hydration and polishes the whole flow --- framework/configstore/skills.go | 15 - .../components/fileManagerView.tsx | 419 ++--- .../skills-repo/components/filePreview.tsx | 326 +++- .../skills-repo/components/helpers.ts | 85 +- .../components/metadataEditorTableView.tsx | 65 +- .../skills-repo/components/shared.tsx | 392 +++-- .../components/skillCreatorView.tsx | 2 +- .../components/skillDetailsView.tsx | 39 +- .../skills-repo/components/skillListView.tsx | 46 +- .../dialogs/skillVersionDialog.tsx | 2 +- .../dialogs/versionDetailsDialog.tsx | 58 +- .../skills-repo/forms/skillEditForm.tsx | 1374 ++++++++++------- .../skills-repo/forms/skillEditFormFields.tsx | 35 +- ui/app/workspace/skills-repo/page.tsx | 8 +- ui/components/ui/treeView.tsx | 10 +- 15 files changed, 1637 insertions(+), 1239 deletions(-) diff --git a/framework/configstore/skills.go b/framework/configstore/skills.go index 324cf227fb..68a2fc73bf 100644 --- a/framework/configstore/skills.go +++ b/framework/configstore/skills.go @@ -763,7 +763,6 @@ func (s *RDBConfigStore) GetSkillVersion(ctx context.Context, skillID, version s } return nil, err } - hydrateInlineTextContent(v.Files) return &v, nil } @@ -1085,19 +1084,6 @@ func createSkillVersion(tx *gorm.DB, skill *tables.TableSkill, version string) ( } // populateSkillFiles reloads the serving version's files into the transient skill.Files. -// hydrateInlineTextContent fills InlineContent for text files from their DB blob -// so GET responses return the editable content (the `content` field). Content kept -// only in object storage is served via the file endpoint rather than inlined here. -func hydrateInlineTextContent(files []tables.TableSkillFile) { - for i := range files { - file := &files[i] - if file.SourceType == tables.SkillSourceTypeText && file.InlineContent == nil && file.Blob != nil { - content := string(file.Blob.Data) - file.InlineContent = &content - } - } -} - func populateSkillFiles(tx *gorm.DB, skill *tables.TableSkill) error { var version tables.TableSkillVersion if err := tx.Preload("Files"). @@ -1110,7 +1096,6 @@ func populateSkillFiles(tx *gorm.DB, skill *tables.TableSkill) error { } skill.Files = version.Files skill.FileCount = int64(len(version.Files)) - hydrateInlineTextContent(skill.Files) return nil } diff --git a/ui/app/workspace/skills-repo/components/fileManagerView.tsx b/ui/app/workspace/skills-repo/components/fileManagerView.tsx index 1ee31c86ad..836d125a91 100644 --- a/ui/app/workspace/skills-repo/components/fileManagerView.tsx +++ b/ui/app/workspace/skills-repo/components/fileManagerView.tsx @@ -24,6 +24,7 @@ import { } from "@/components/ui/dropdownMenu"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { ScrollBar } from "@/components/ui/scrollArea"; import { Textarea } from "@/components/ui/textarea"; import { Tree, type BaseNodeData, type TreeNode } from "@/components/ui/treeView"; import { getErrorMessage } from "@/lib/store/apis/baseApi"; @@ -36,22 +37,15 @@ import { Check, ChevronDown, ChevronRight, - ChevronsDownUp, - ChevronsUpDown, FileText, Folder, - FolderPlus, Info, Loader2, MoreHorizontal, - MoveRight, - Pencil, Plus, - Trash2, - Upload, X, } from "lucide-react"; -import { useCallback, useEffect, useMemo, useRef, useState, type ChangeEvent } from "react"; +import { useEffect, useMemo, useRef, useState, type ChangeEvent } from "react"; import { formatFileSize } from "./helpers"; import { cn } from "@/lib/utils"; import { toast } from "sonner"; @@ -125,17 +119,17 @@ function FileAddForm({ folderPath, initialSourceType, initialEntry, submitLabel, const [error, setError] = useState(null); const locationLabel = folderPath ? `${folderPath}/` : "root"; - // Adding a new text file only asks for a name; its content is edited in the - // right-hand pane afterwards. (Editing an existing entry keeps the full form.) - const isTextNameOnly = sourceType === "text" && !initialEntry; + // Adding a new file asks for its name in-tree first; source-specific fields + // are edited in the right-hand pane after the file is inserted. + const isNewFileNameOnly = !initialEntry; const nameInputRef = useRef(null); // Grab focus after the menu that opened this draft has returned focus to its trigger. useEffect(() => { - if (!isTextNameOnly) return; + if (!isNewFileNameOnly) return; const id = window.setTimeout(() => nameInputRef.current?.focus(), 0); return () => window.clearTimeout(id); - }, [isTextNameOnly]); + }, [isNewFileNameOnly]); const handleUploadFileChange = (file: File | null) => { setSelectedFile(file); @@ -160,7 +154,7 @@ function FileAddForm({ folderPath, initialSourceType, initialEntry, submitLabel, const pathErr = validateFilePath(fullPath); if (pathErr) return setError(pathErr); - if (!isTextNameOnly) { + if (!isNewFileNameOnly) { const srcErr = validateSourceType(sourceType, { url, dataurl, @@ -201,49 +195,58 @@ function FileAddForm({ folderPath, initialSourceType, initialEntry, submitLabel, onAdd(entry); }; - // Name-only add: a single full-width input. Enter adds, Escape/empty-blur cancels. - if (isTextNameOnly) { + // Name-only add: input with check/cross like folder add. + if (isNewFileNameOnly) { return ( -
- { - setFilename(e.target.value); - setError(null); - }} - onKeyDown={(e) => { - if (e.key === "Enter") { - e.preventDefault(); - handleSubmit(); - } else if (e.key === "Escape") { - e.preventDefault(); - onCancel(); - } - }} - placeholder="filename.ext (press Enter to add, Esc to cancel)" - className="h-8 w-full font-mono text-xs" - aria-label="Filename" - /> +
+
+ { + setFilename(e.target.value); + setError(null); + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + handleSubmit(); + } else if (e.key === "Escape") { + e.preventDefault(); + onCancel(); + } + }} + placeholder="filename.ext" + className="h-7 max-w-xs font-mono text-xs" + aria-label="Filename" + /> + + +
{error && ( -

+

+
)}
); } return ( -
- {!isTextNameOnly && ( +
+ {!isNewFileNameOnly && (
- + {sourceOption.label} - Location: {locationLabel} + Location: {locationLabel}
)} @@ -268,13 +271,13 @@ function FileAddForm({ folderPath, initialSourceType, initialEntry, submitLabel, aria-label="Source URL" /> )} - {sourceType === "text" && !isTextNameOnly && ( + {sourceType === "text" && !isNewFileNameOnly && (