Skip to content

Commit

Permalink
edit folder title works!
Browse files Browse the repository at this point in the history
  • Loading branch information
ciur committed Sep 5, 2024
1 parent db347aa commit 5e37750
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 76 deletions.
2 changes: 2 additions & 0 deletions ui2/src/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import navBarReducer from "@/slices/navBar"
import tagsReducer from "@/features/tags/tagsSlice"
import groupsReducer from "@/features/groups/groupsSlice"
import usersReducer from "@/features/users/usersSlice"
import nodesReducer from "@/features/nodes/nodesSlice"
import {uploaderReducer} from "@/slices/uploader"
import sizesSliceReducer from "@/slices/sizes"
import dragndropReducer from "@/slices/dragndrop"
Expand All @@ -23,6 +24,7 @@ export const store = configureStore({
uploader: uploaderReducer,
sizes: sizesSliceReducer,
dragndrop: dragndropReducer,
nodes: nodesReducer,
[apiSlice.reducerPath]: apiSlice.reducer
},
middleware: getDefaultMiddleware =>
Expand Down
56 changes: 38 additions & 18 deletions ui2/src/components/SinglePanel/EditNodeTitleButton.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,67 @@
import {useDisclosure} from "@mantine/hooks"
import {useContext} from "react"
import {Tooltip, ActionIcon} from "@mantine/core"
import {IconEdit} from "@tabler/icons-react"

import {useSelector, useDispatch} from "react-redux"
import {
selectSelectedNodes,
nodeUpdated,
selectSelectedNodeIds,
clearNodesSelection
} from "@/slices/dualPanel/dualPanel"
import edit_node_title from "@/components/modals/EditNodeTitle"
import {EditNodeTitleModal} from "@/components/modals/EditNodeTitle"

import type {RootState} from "@/app/types"

import type {NodeType, PanelMode} from "@/types"
import type {PanelMode, NodeType} from "@/types"

import PanelContext from "@/contexts/PanelContext"
import {selectNodesByIds} from "@/features/nodes/nodesSlice"

export default function EditNodeTitleButton() {
const [opened, {open, close}] = useDisclosure(false)
const mode: PanelMode = useContext(PanelContext)
const dispatch = useDispatch()
const selectedIds = useSelector((state: RootState) =>
selectSelectedNodeIds(state, mode)
)
const selectedNodes = useSelector((state: RootState) =>
selectSelectedNodes(state, mode)
selectNodesByIds(state, selectedIds || [])
)
const onEditNodeTitle = () => {

const dispatch = useDispatch()
let node: NodeType = selectedNodes[0]

const onClick = () => {
if (selectedNodes.length < 1) {
console.log("Error: no selected nodes")
return
}
node = selectedNodes[0]
open()
}

let node: NodeType = selectedNodes[0]
const onSubmit = () => {
dispatch(clearNodesSelection(mode))
close()
}

edit_node_title(node)
.then((node: NodeType) => {
dispatch(nodeUpdated({node, mode}))
})
.finally(() => dispatch(clearNodesSelection(mode)))
const onCancel = () => {
dispatch(clearNodesSelection(mode))
close()
}

return (
<Tooltip label="Change title" withArrow>
<ActionIcon size={"lg"} variant="default" onClick={onEditNodeTitle}>
<IconEdit stroke={1.4} />
</ActionIcon>
</Tooltip>
<>
<Tooltip label="Change title" withArrow>
<ActionIcon size={"lg"} variant="default" onClick={onClick}>
<IconEdit stroke={1.4} />
</ActionIcon>
</Tooltip>
<EditNodeTitleModal
opened={opened}
node={node}
onSubmit={onSubmit}
onCancel={onCancel}
/>
</>
)
}
5 changes: 3 additions & 2 deletions ui2/src/components/Viewer/EditTitleButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
nodeUpdated,
clearNodesSelection
} from "@/slices/dualPanel/dualPanel"
import edit_node_title from "@/components/modals/EditNodeTitle"
//import edit_node_title from "@/components/modals/EditNodeTitle"

import type {RootState} from "@/app/types"

Expand All @@ -29,12 +29,13 @@ export default function EditTitleButton() {
}

let node: NodeType = selectedNodes[0]

/*
edit_node_title(node)
.then((node: NodeType) => {
dispatch(nodeUpdated({node, mode}))
})
.finally(() => dispatch(clearNodesSelection(mode)))
*/
}

return (
Expand Down
106 changes: 52 additions & 54 deletions ui2/src/components/modals/EditNodeTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,67 @@
import {ChangeEvent} from "react"
import {useState} from "react"
import {createRoot} from "react-dom/client"
import {MantineProvider, TextInput} from "@mantine/core"
import theme from "@/themes"
import GenericModal from "@/components/modals/Generic"
import {useState, useEffect} from "react"
import {TextInput, Loader, Group, Button, Modal} from "@mantine/core"
import Error from "@/components/modals/Error"
import type {NodeType} from "@/types"
import {MODALS} from "@/cconstants"
import axios, {AxiosError} from "axios"
import {useRenameFolderMutation} from "@/features/nodes/apiSlice"

type Args = {
interface Args {
node: NodeType
onOK: (node: NodeType) => void
onCancel: (msg?: string) => void
opened: boolean
onSubmit: () => void
onCancel: () => void
}

const EditNodeTitleModal = ({node, onOK, onCancel}: Args) => {
export const EditNodeTitleModal = ({
node,
onSubmit,
onCancel,
opened
}: Args) => {
const [renameFolder, {isLoading, isSuccess}] = useRenameFolderMutation()
const [title, setTitle] = useState(node.title)
const [error, setError] = useState("")

useEffect(() => {
// close dialog as soon as we have
// "success" status from the mutation
if (isSuccess) {
onSubmit()
reset()
}
}, [isSuccess])

const handleTitleChanged = (event: ChangeEvent<HTMLInputElement>) => {
let value = event.currentTarget.value

setTitle(value)
}

const handleSubmit = async (signal: AbortSignal) => {
const onLocalSubmit = async () => {
const data = {
title: title,
id: node.id
}
try {
let response = await axios.patch(
`/api/nodes/${node.id}`,
{title},
{signal}
)
let new_node: NodeType = response.data as NodeType
onOK(new_node)
} catch (error: any | AxiosError) {
if (axios.isAxiosError(error)) {
setError(error.message)
return false // i.e. do not close dialog
}
await renameFolder(data)
} catch (error: any) {
// @ts-ignore
setError(err.data.detail)
}
return true // i.e. close dialog
}

const handleCancel = () => {
// just close the dialog
const onLocalCancel = () => {
onCancel()
reset()
}

const reset = () => {
setTitle("")
setError("")
onCancel()
}

return (
<GenericModal
modal_title="Create Folder"
submit_button_title="Create"
onSubmit={handleSubmit}
onCancel={handleCancel}
>
<Modal title={"New Tag"} opened={opened} onClose={onLocalCancel}>
<TextInput
data-autofocus
onChange={handleTitleChanged}
Expand All @@ -66,25 +71,18 @@ const EditNodeTitleModal = ({node, onOK, onCancel}: Args) => {
mt="md"
/>
{error && <Error message={error} />}
</GenericModal>
)
}

function edit_node_title(node: NodeType) {
let modals = document.getElementById(MODALS)

let promise = new Promise<NodeType>(function (onOK, onCancel) {
if (modals) {
let dom_root = createRoot(modals)
dom_root.render(
<MantineProvider theme={theme}>
<EditNodeTitleModal node={node} onOK={onOK} onCancel={onCancel} />
</MantineProvider>
)
}
}) // new Promise...

return promise
<Group justify="space-between" mt="md">
<Button variant="default" onClick={onLocalCancel}>
Cancel
</Button>
<Group>
{isLoading && <Loader size="sm" />}
<Button disabled={isLoading} onClick={onLocalSubmit}>
Submit
</Button>
</Group>
</Group>
</Modal>
)
}

export default edit_node_title
16 changes: 15 additions & 1 deletion ui2/src/features/nodes/apiSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ type CreateFolderType = {
ctype: "folder"
}

type RenameFolderType = {
title: string
id: string
}

export type PaginatedArgs = {
nodeID: string
page_number?: number
Expand Down Expand Up @@ -46,12 +51,21 @@ export const apiSliceWithNodes = apiSlice.injectEndpoints({
body: folder
}),
invalidatesTags: ["Node"]
}),
renameFolder: builder.mutation<NodeType, RenameFolderType>({
query: folder => ({
url: `/nodes/${folder.id}`,
method: "PATCH",
body: folder
}),
invalidatesTags: ["Node"]
})
})
})

export const {
useGetPaginatedNodesQuery,
useGetFolderQuery,
useAddNewFolderMutation
useAddNewFolderMutation,
useRenameFolderMutation
} = apiSliceWithNodes
43 changes: 42 additions & 1 deletion ui2/src/features/nodes/nodesSlice.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,45 @@
import {
createSelector,
createEntityAdapter,
createSlice,
PayloadAction
} from "@reduxjs/toolkit"
import {RootState} from "@/app/types"
import {apiSliceWithNodes} from "./apiSlice"
import type {NodeType, Paginated} from "@/types"

export const selectFolderResult = (folderID: string) =>
const nodeAdapter = createEntityAdapter<NodeType>()
const initialState = nodeAdapter.getInitialState()

const nodesSlice = createSlice({
name: "nodes",
initialState,
reducers: {},
extraReducers(builder) {
builder.addMatcher(
apiSliceWithNodes.endpoints.getPaginatedNodes.matchFulfilled,
(state, action: PayloadAction<Paginated<NodeType>>) => {
const payload = action.payload
nodeAdapter.upsertMany(state, payload.items)
}
)
}
})

export default nodesSlice.reducer

export const selectFoldersResult = (folderID: string) =>
apiSliceWithNodes.endpoints.getFolder.select(folderID)

export const selectItemIds = (_: RootState, itemIds: string[]) => itemIds

export const {selectEntities: selectNodeEntities} = nodeAdapter.getSelectors(
(state: RootState) => state.nodes
)

export const selectNodesByIds = createSelector(
[selectNodeEntities, selectItemIds],
(entities, ids) => {
return Object.values(entities).filter(i => ids.includes(i.id))
}
)

0 comments on commit 5e37750

Please sign in to comment.