11import { useMemo , useState } from "react"
22
3- import { Button , Dropdown , Input , Space , Table , Typography } from "antd"
3+ import { Button , Dropdown , Input , Space , Table , Typography , message } from "antd"
44import { ColumnsType } from "antd/es/table"
55import useSWR from "swr"
66
@@ -17,14 +17,15 @@ import {
1717
1818import { useBreadcrumbsEffect } from "@/oss/lib/hooks/useBreadcrumbs"
1919import { useProjectData } from "@/oss/state/project"
20- import { queryFolders } from "@/oss/services/folders"
20+ import { createFolder , editFolder , queryFolders } from "@/oss/services/folders"
2121import PromptsBreadcrumb from "./components/PromptsBreadcrumb"
2222import { buildFolderTree , FolderTreeNode } from "./assets/utils"
2323import { MoreOutlined } from "@ant-design/icons"
2424import { formatDay } from "@/oss/lib/helpers/dateTimeHelper"
2525import { DataNode } from "antd/es/tree"
2626import MoveFolderModal from "./modals/MoveFolderModal"
2727import DeleteFolderModal from "./modals/DeleteFolderModal"
28+ import NewFolderModal from "./modals/NewFolderModal"
2829
2930const { Title} = Typography
3031
@@ -40,13 +41,18 @@ const PromptsPage = () => {
4041 const [ deleteModalOpen , setDeleteModalOpen ] = useState ( false )
4142 const [ renameValue , setRenameValue ] = useState ( "" )
4243 const [ moveSelection , setMoveSelection ] = useState < string | null > ( null )
44+ const [ moveFolderId , setMoveFolderId ] = useState < string | null > ( null )
4345 const [ newFolderName , setNewFolderName ] = useState ( "" )
46+ const [ isCreatingFolder , setIsCreatingFolder ] = useState ( false )
47+ const [ isMovingFolder , setIsMovingFolder ] = useState ( false )
4448
4549 useBreadcrumbsEffect ( { breadcrumbs : { prompts : { label : "prompts" } } } , [ ] )
4650
47- const { data : foldersData , isLoading} = useSWR ( projectId ? [ "folders" , projectId ] : null , ( ) =>
48- queryFolders ( { folder : { } } ) ,
49- )
51+ const {
52+ data : foldersData ,
53+ isLoading,
54+ mutate,
55+ } = useSWR ( projectId ? [ "folders" , projectId ] : null , ( ) => queryFolders ( { folder : { } } ) )
5056
5157 const { roots, foldersById} = useMemo ( ( ) => {
5258 const folders = foldersData ?. folders ?? [ ]
@@ -64,17 +70,20 @@ const PromptsPage = () => {
6470 key : node . id ! ,
6571 title : node . name ,
6672 children : buildNodes ( node . children || [ ] ) ,
67- disableCheckbox : node . id === currentFolderId ,
68- selectable : node . id !== currentFolderId ,
6973 } ) )
7074
7175 return buildNodes ( roots )
72- } , [ currentFolderId , roots ] )
76+ } , [ roots ] )
7377
74- const moveDestinationName = useMemo (
75- ( ) => ( moveSelection ? ( foldersById [ moveSelection ] ?. name ?? moveSelection ) : null ) ,
76- [ moveSelection , foldersById ] ,
77- )
78+ const moveDestinationName = useMemo ( ( ) => {
79+ if ( ! moveSelection ) return null
80+ return foldersById [ moveSelection ] ?. name ?? moveSelection
81+ } , [ moveSelection , foldersById ] )
82+
83+ const moveFolderName = useMemo ( ( ) => {
84+ if ( ! moveFolderId ) return null
85+ return foldersById [ moveFolderId ] ?. name ?? moveFolderId
86+ } , [ foldersById , moveFolderId ] )
7887
7988 // what we show in the table
8089 const visibleRows : FolderTreeNode [ ] = useMemo ( ( ) => {
@@ -92,6 +101,74 @@ const PromptsPage = () => {
92101 setCurrentFolderId ( folderId )
93102 }
94103
104+ const openNewFolderModal = ( ) => {
105+ setNewFolderName ( "Untitled folder" )
106+ setNewFolderModalOpen ( true )
107+ }
108+
109+ const handleCreateFolder = async ( ) => {
110+ const name = newFolderName . trim ( ) || "Untitled folder"
111+
112+ setIsCreatingFolder ( true )
113+ try {
114+ await createFolder ( {
115+ folder : {
116+ name,
117+ parent_id : currentFolderId ?? null ,
118+ } ,
119+ } )
120+
121+ await mutate ( )
122+ setNewFolderModalOpen ( false )
123+ message . success ( "Folder created" )
124+ } catch ( error ) {
125+ message . error ( "Failed to create folder" )
126+ } finally {
127+ setIsCreatingFolder ( false )
128+ }
129+ }
130+
131+ const handleOpenMoveModal = ( folderId : string | null ) => {
132+ if ( ! folderId ) return
133+
134+ setMoveFolderId ( folderId )
135+ setMoveSelection ( folderId )
136+ setMoveModalOpen ( true )
137+ }
138+
139+ const handleCloseMoveModal = ( ) => {
140+ setMoveModalOpen ( false )
141+ setMoveFolderId ( null )
142+ setMoveSelection ( null )
143+ }
144+
145+ const handleMoveFolder = async ( ) => {
146+ if ( ! moveFolderId || ! moveSelection || moveSelection === moveFolderId ) {
147+ message . warning ( "Select a destination folder" )
148+ return
149+ }
150+
151+ setIsMovingFolder ( true )
152+ try {
153+ await editFolder ( moveFolderId , {
154+ folder : {
155+ id : moveFolderId ,
156+ parent_id : moveSelection ,
157+ } ,
158+ } )
159+
160+ await mutate ( )
161+ setMoveModalOpen ( false )
162+ setMoveFolderId ( null )
163+ setMoveSelection ( null )
164+ message . success ( "Folder moved" )
165+ } catch ( error ) {
166+ message . error ( "Failed to move folder" )
167+ } finally {
168+ setIsMovingFolder ( false )
169+ }
170+ }
171+
95172 const columns : ColumnsType < FolderTreeNode > = [
96173 {
97174 title : "Name" ,
@@ -144,7 +221,7 @@ const PromptsPage = () => {
144221 icon : < FolderDashedIcon size = { 16 } /> ,
145222 onClick : ( e : any ) => {
146223 e . domEvent . stopPropagation ( )
147- setMoveModalOpen ( true )
224+ handleOpenMoveModal ( record . id as string )
148225 } ,
149226 } ,
150227 {
@@ -185,6 +262,8 @@ const PromptsPage = () => {
185262 foldersById = { foldersById }
186263 currentFolderId = { currentFolderId }
187264 onFolderChange = { handleBreadcrumbFolderChange }
265+ onNewFolder = { openNewFolderModal }
266+ onMoveFolder = { handleOpenMoveModal }
188267 />
189268
190269 < div className = "flex flex-col gap-2" >
@@ -225,7 +304,7 @@ const PromptsPage = () => {
225304 label : "New folder" ,
226305 onClick : ( event ) => {
227306 event . domEvent . stopPropagation ( )
228- // onNewFolder?. ()
307+ openNewFolderModal ( )
229308 } ,
230309 } ,
231310 {
@@ -279,20 +358,35 @@ const PromptsPage = () => {
279358 </ div >
280359
281360 < MoveFolderModal
282- foldername = { currentFolder ?. name }
361+ folderName = { moveFolderName }
283362 moveDestinationName = { moveDestinationName }
284- moveModalOpen = { moveModalOpen }
285- setMoveModalOpen = { setMoveModalOpen }
363+ open = { moveModalOpen }
364+ onCancel = { handleCloseMoveModal }
365+ onMove = { handleMoveFolder }
286366 treeData = { treeData }
287367 moveSelection = { moveSelection }
288368 setMoveSelection = { setMoveSelection }
369+ isMoving = { isMovingFolder }
370+ disabledConfirm = { ! moveFolderId || ! moveSelection || moveSelection === moveFolderId }
289371 />
290372
291373 < DeleteFolderModal
292374 deleteModalOpen = { deleteModalOpen }
293375 setDeleteModalOpen = { setDeleteModalOpen }
294376 folderName = { currentFolder ?. name }
295377 />
378+
379+ < NewFolderModal
380+ open = { newFolderModalOpen }
381+ folderName = { newFolderName }
382+ setFolderName = { setNewFolderName }
383+ onCreate = { handleCreateFolder }
384+ onCancel = { ( ) => {
385+ setNewFolderModalOpen ( false )
386+ setNewFolderName ( "" )
387+ } }
388+ confirmLoading = { isCreatingFolder }
389+ />
296390 </ div >
297391 )
298392}
0 commit comments