From 6991dd57111690b7fea3a31c88b9c4fc8b95a4a2 Mon Sep 17 00:00:00 2001 From: Diana Nanyanzi Date: Fri, 6 Dec 2024 21:58:25 +0300 Subject: [PATCH 1/8] feat: implement three panel design layout --- i18n/en.pot | 28 ++-- src/App.tsx | 6 +- src/components/keys/keysTable.tsx | 2 +- src/components/namespaces/LinksList.tsx | 2 +- src/components/panel/CreateButton.tsx | 25 ++++ src/components/panel/DataStoreControl.tsx | 30 ++++ src/components/panel/EmptyPanelEditor.tsx | 25 ++++ src/components/panel/KeysSidePanel.tsx | 109 ++++++++++++++ src/components/panel/Main.tsx | 17 +++ src/components/panel/NamespacesSidePanel.tsx | 103 ++++++++++++++ src/components/panel/Panel.module.css | 141 +++++++++++++++++++ src/components/panel/PanelEdit.tsx | 136 ++++++++++++++++++ src/components/panel/PanelEditor.tsx | 21 +++ src/components/panel/PanelEmptyArea.tsx | 29 ++++ src/components/panel/PanelError.tsx | 68 +++++++++ src/components/panel/PanelErrorPage.tsx | 13 ++ src/components/panel/PanelHeader.tsx | 10 ++ src/components/panel/PanelLink.tsx | 55 ++++++++ src/components/panel/PanelLinksList.tsx | 62 ++++++++ src/components/panel/PanelRouter.tsx | 48 +++++++ src/components/panel/SearchField.tsx | 14 ++ src/components/panel/SidebarPanel.tsx | 39 +++++ src/components/panel/ThreePanelLayout.tsx | 19 +++ src/components/sidebar/sidebar.tsx | 2 +- 24 files changed, 985 insertions(+), 19 deletions(-) create mode 100644 src/components/panel/CreateButton.tsx create mode 100644 src/components/panel/DataStoreControl.tsx create mode 100644 src/components/panel/EmptyPanelEditor.tsx create mode 100644 src/components/panel/KeysSidePanel.tsx create mode 100644 src/components/panel/Main.tsx create mode 100644 src/components/panel/NamespacesSidePanel.tsx create mode 100644 src/components/panel/Panel.module.css create mode 100644 src/components/panel/PanelEdit.tsx create mode 100644 src/components/panel/PanelEditor.tsx create mode 100644 src/components/panel/PanelEmptyArea.tsx create mode 100644 src/components/panel/PanelError.tsx create mode 100644 src/components/panel/PanelErrorPage.tsx create mode 100644 src/components/panel/PanelHeader.tsx create mode 100644 src/components/panel/PanelLink.tsx create mode 100644 src/components/panel/PanelLinksList.tsx create mode 100644 src/components/panel/PanelRouter.tsx create mode 100644 src/components/panel/SearchField.tsx create mode 100644 src/components/panel/SidebarPanel.tsx create mode 100644 src/components/panel/ThreePanelLayout.tsx diff --git a/i18n/en.pot b/i18n/en.pot index f3cc6aa..45add9d 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-12-05T03:27:06.316Z\n" -"PO-Revision-Date: 2024-12-05T03:27:06.317Z\n" +"POT-Creation-Date: 2024-12-06T19:16:44.628Z\n" +"PO-Revision-Date: 2024-12-06T19:16:44.628Z\n" msgid "View keys" msgstr "View keys" @@ -14,6 +14,9 @@ msgstr "View keys" msgid "Click a namespace to view its keys" msgstr "Click a namespace to view its keys" +msgid "An error occurred" +msgstr "An error occurred" + msgid "Add New Key" msgstr "Add New Key" @@ -56,9 +59,6 @@ msgstr "New key" msgid "Delete" msgstr "Delete" -msgid "Failed to fetch key values!" -msgstr "Failed to fetch key values!" - msgid "Key successfully updated" msgstr "Key successfully updated" @@ -89,20 +89,20 @@ msgstr "Namespaces" msgid "This will delete all the keys in this namespace" msgstr "This will delete all the keys in this namespace" +msgid "New" +msgstr "New" + msgid "DataStore" msgstr "DataStore" msgid "User DataStore" msgstr "User DataStore" -msgid "Search" -msgstr "Search" - -msgid "An error has occurred" -msgstr "An error has occurred" +msgid "Select a namespace and key to edit its values" +msgstr "Select a namespace and key to edit its values" -msgid "Back" -msgstr "Back" +msgid "Error" +msgstr "Error" -msgid "Back to DataStore" -msgstr "Back to DataStore" +msgid "Search" +msgstr "Search" diff --git a/src/App.tsx b/src/App.tsx index bdfee63..b993b01 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,14 @@ import React, { FC } from 'react' import { RouterProvider } from 'react-router-dom' import AppWrapper from './components/AppWrapper' -import { router } from './routes/Router' +import { threePanelRouter } from './components/panel/PanelRouter' +// import { router } from './routes/Router' const App: FC = () => { return ( - + {/* */} + ) } diff --git a/src/components/keys/keysTable.tsx b/src/components/keys/keysTable.tsx index 17b8b81..f0d049b 100644 --- a/src/components/keys/keysTable.tsx +++ b/src/components/keys/keysTable.tsx @@ -49,7 +49,7 @@ const KeysTable = () => { useEffect(() => { refetch({ id: namespace }) - }, [namespace]) + }, [namespace, refetch]) const handleDeleteAction = async (key) => { await engine.mutate( diff --git a/src/components/namespaces/LinksList.tsx b/src/components/namespaces/LinksList.tsx index c866f20..8133c26 100644 --- a/src/components/namespaces/LinksList.tsx +++ b/src/components/namespaces/LinksList.tsx @@ -50,7 +50,7 @@ function LinksList({ data, error, loading, refetchList }) { useEffect(() => { refetchList() - }, [store, namespace, key]) + }, [store, namespace, key, refetchList]) return (
diff --git a/src/components/panel/CreateButton.tsx b/src/components/panel/CreateButton.tsx new file mode 100644 index 0000000..9a0f307 --- /dev/null +++ b/src/components/panel/CreateButton.tsx @@ -0,0 +1,25 @@ +import { Button } from '@dhis2/ui' +import { IconAdd16 } from '@dhis2/ui-icons' +import React from 'react' +import i18n from '../../locales' +import classes from './Panel.module.css' + +const CreateButton = () => { + return ( +
+ +
+ ) +} + +export default CreateButton diff --git a/src/components/panel/DataStoreControl.tsx b/src/components/panel/DataStoreControl.tsx new file mode 100644 index 0000000..83c7e51 --- /dev/null +++ b/src/components/panel/DataStoreControl.tsx @@ -0,0 +1,30 @@ +import { SegmentedControl } from '@dhis2/ui' +import React from 'react' +import i18n from '../../locales' + +type DataStoreControlProps = { + option: string + handleChange: (payload, event) => void +} + +export default function DataStoreControl({ + option, + handleChange, +}: DataStoreControlProps) { + return ( + + ) +} diff --git a/src/components/panel/EmptyPanelEditor.tsx b/src/components/panel/EmptyPanelEditor.tsx new file mode 100644 index 0000000..5bccba5 --- /dev/null +++ b/src/components/panel/EmptyPanelEditor.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import i18n from '../../locales' +import PanelEditor from './PanelEditor' +import { PanelHeader } from './PanelHeader' + +export default function EmptyPanelEditor({ + placeholder, +}: { + placeholder?: string +}) { + const defaultMessage = i18n.t( + 'Select a namespace and key to edit its values' + ) + return ( +
+ + Editor + + console.log('')} + /> +
+ ) +} diff --git a/src/components/panel/KeysSidePanel.tsx b/src/components/panel/KeysSidePanel.tsx new file mode 100644 index 0000000..57f58a9 --- /dev/null +++ b/src/components/panel/KeysSidePanel.tsx @@ -0,0 +1,109 @@ +import { useDataQuery } from '@dhis2/app-service-data' +import React, { useEffect } from 'react' +import { useParams } from 'react-router-dom' +import { PanelHeader } from './PanelHeader' +import SidebarPanel from './SidebarPanel' + +interface QueryResults { + results: [] +} + +const dataStoreQuery = { + results: { + resource: 'dataStore', + id: ({ id }) => id, + }, +} + +const userDataStoreQuery = { + results: { + resource: 'userDataStore', + id: ({ id }) => id, + }, +} + +const KeysSidePanel = () => { + // const navigate = useNavigate() + const { store, namespace } = useParams() + // const [option, setOption] = useState(store || '') + + const RenderDataStoreKeys = () => { + const { + error: dataStoreQueryError, + loading: dataStoreQueryLoading, + data: dataStoreQueryData, + refetch: refetchDataStore, + } = useDataQuery(dataStoreQuery, { + variables: { + id: namespace, + }, + }) + + useEffect(() => { + refetchDataStore() + }, [store]) + + return ( + + ) + } + + const RenderUserDataStoreKeys = () => { + const { + error: userDataStoreQueryError, + loading: userDataStoreQueryLoading, + data: userDataStoreQueryData, + refetch: refetchUserDataStore, + } = useDataQuery(userDataStoreQuery, { + variables: { + id: namespace, + }, + }) + + useEffect(() => { + refetchUserDataStore() + }, [store]) + + return ( + + ) + } + + return ( + <> + {namespace && ( + <> + + <> + {' '} + {namespace} + + + + {store && ( + <> + {store === 'userDataStore' && ( + + )} + {store === 'dataStore' && } + + )} + + )} + + ) +} + +export default KeysSidePanel diff --git a/src/components/panel/Main.tsx b/src/components/panel/Main.tsx new file mode 100644 index 0000000..bfad11d --- /dev/null +++ b/src/components/panel/Main.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import { Outlet } from 'react-router-dom' +import KeysSidePanel from './KeysSidePanel' +import classes from './Panel.module.css' + +export default function Main() { + return ( + <> +
+ +
+
+ +
+ + ) +} diff --git a/src/components/panel/NamespacesSidePanel.tsx b/src/components/panel/NamespacesSidePanel.tsx new file mode 100644 index 0000000..d76ec6e --- /dev/null +++ b/src/components/panel/NamespacesSidePanel.tsx @@ -0,0 +1,103 @@ +import { useDataQuery } from '@dhis2/app-service-data' +import React, { useEffect, useState } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import DataStoreControl from './DataStoreControl' +import { PanelHeader } from './PanelHeader' +import SidebarPanel from './SidebarPanel' + +interface QueryResults { + results: [] +} + +const dataStoreQuery = { + results: { + resource: 'dataStore', + }, +} + +const userDataStoreQuery = { + results: { + resource: 'userDataStore', + }, +} + +const NamespacesSidePanel = () => { + const navigate = useNavigate() + const { store } = useParams() + const [option, setOption] = useState(store || '') + + const RenderUserDataStorePanel = () => { + const { + error: userDataStoreQueryError, + loading: userDataStoreQueryLoading, + data: userDataStoreQueryData, + refetch: refetchUserDataStore, + } = useDataQuery(userDataStoreQuery) + + useEffect(() => { + refetchUserDataStore() + }, [store]) + + return ( + + ) + } + + const RenderDataStorePanel = () => { + const { + error: dataStoreQueryError, + loading: dataStoreQueryLoading, + data: dataStoreQueryData, + refetch: refetchDataStore, + } = useDataQuery(dataStoreQuery) + + useEffect(() => { + refetchDataStore() + }, [store]) + + return ( + + ) + } + + const handleDataStoreSelect = ({ value }) => { + setOption(value) + navigate(`/${value}`) + } + + useEffect(() => { + const storeOptions = ['dataStore', 'userDataStore'] + if (!storeOptions.includes(store)) { + navigate('/dataStore') + } else { + setOption(store) + } + }, [store]) + + return ( + <> + + + + {store === 'userDataStore' && } + {store === 'dataStore' && } + + ) +} + +export default NamespacesSidePanel diff --git a/src/components/panel/Panel.module.css b/src/components/panel/Panel.module.css new file mode 100644 index 0000000..8d8971d --- /dev/null +++ b/src/components/panel/Panel.module.css @@ -0,0 +1,141 @@ +.container { + /* width: 100%; */ + /* height: 100vh; */ + box-sizing: border-box; + /* height: 100%; */ + /* display: flex; */ + /* flex-direction: row; */ + /* font-size: 1rem; */ + display: grid; + grid-template-columns: 400px auto; + border-bottom: 1px solid var(--colors-grey100); +} + +.panelHeader { + height: 5vh; + padding: 0.3em; + border-bottom: 1px solid var(--colors-grey300); +} + +.sidebar { + border-right: 1px solid var(--colors-grey300); + /* margin-top: 0.5em */ + /* padding: 0.5em; */ + /* width: 30%; */ + /* margin: 0.1em; */ +} + +.sidebarContent { + padding: 0.5em; + margin-top: 0.5em; + /* margin: 0; */ + /* padding: 0.3em; */ + /* width: 20%; */ +} + +.createButton { + width: 100%; +} + +.createButton button { + margin: 0.5em 0 0.3em 0; + width: 100%; + border: none; +} + +.top { + /* margin-top: 0.5em; */ +} + +.bottom { + /* margin-bottom: 0.5em; */ +} + +.sidebarList h4 { + /* padding: 0; */ + /* margin: 0.5em; */ +} + +.sidebarList ul { + margin: 0; + padding: 0; + list-style-type: none; +} + +.select { + /* height: 70px; */ + /* padding: 0; */ + /* margin: 0; */ +} + +/* main area */ + +.main { + display: grid; + grid-template-columns: 400px auto; +} + +/* --- keys */ + +.keysTable { + /* margin-top: 10px; */ + /* padding: 0.2em; */ +} + +/* nav link */ + +/* sourced and adapted from https://github.com/dhis2/design-specs/blob/b65e6518dcc7c16733379cd80688e67a422fc742/src/components/sidenav.css#L73 (-> 104) */ +.navLink { + width: 100%; + /* display: grid; */ + /* grid-template-rows: 1fr 2fr 1fr; */ + /* background-color: aliceblue; */ + /* border: 1px solid red; */ + /* height: 50px; */ + min-height: 36px; + border-radius: 10px; +} + +.navLink button { + /* border: 0; */ +} + +.navLink a { + /* display: block; */ + /* min-height: 36px; */ + padding: 5px; + /* background: var(--colors-grey100); */ + text-decoration: none; + color: var(--colors-grey900); + font-size: 15px; + display: grid; + grid-template-columns: 25px auto 30px; + border-radius: 10px; + /* display: flex; */ + /* align-items: center; */ +} + +.navLink a button { + border: none; + background-color: transparent; +} +.navLink:hover, +.navLink a:hover { + background: var(--colors-grey100); +} +.navLink:focus, +.navLink a:focus { + outline: 2px solid white; + background: var(--colors-teal050); + outline-offset: -2px; +} + +.navLink a.active, +.navLink :global(.active) { + /* font-weight: 500; */ + background: var(--colors-teal050); + /* box-shadow: inset 6px 0px 0px 0px var(--colors-grey500); */ +} +.navLink.active:hover { + background: var(--colors-teal050); +} diff --git a/src/components/panel/PanelEdit.tsx b/src/components/panel/PanelEdit.tsx new file mode 100644 index 0000000..b7883c9 --- /dev/null +++ b/src/components/panel/PanelEdit.tsx @@ -0,0 +1,136 @@ +import { useDataMutation, useDataQuery } from '@dhis2/app-runtime' +import { Button } from '@dhis2-ui/button' +import React, { useEffect, useState } from 'react' +import { useParams } from 'react-router-dom' +import useCustomAlert from '../../hooks/useCustomAlert' +import i18n from '../../locales' +import Error from '../Error' +import PanelEditor from './PanelEditor' +import { PanelHeader } from './PanelHeader' + +const modifyKeyMutation = ({ store }) => ({ + type: 'update' as const, + resource: `${store}`, + id: ({ key, namespace }: { key: string; namespace: string }) => + `${namespace}/${key}`, + data: ({ value }) => JSON.parse(value), +}) + +const keyValuesQuery = ({ store }: { store: string }) => ({ + results: { + resource: `${store}`, + id: ({ key, namespace }: { key: string; namespace: string }) => + `${namespace}/${key}`, + }, +}) + +// const useKeyValuesQuery = ({ store, key, namespace }) => { +// if (key && namespace) { +// return useDataQuery(keyValuesQuery({ store }), { +// variables: { +// key, +// namespace, +// }, +// }) +// } else { +// return { +// data: null, +// loading: false, +// error: null, +// refetch: () => Promise.resolve(), +// } +// } +// } + +const PanelEdit = () => { + const { key, namespace, store } = useParams() + const { showSuccess, showError } = useCustomAlert() + + const { + data, + loading: queryLoading, + error, + refetch, + } = useDataQuery(keyValuesQuery({ store }), { + variables: { + key, + namespace, + }, + }) + + const [value, setValue] = useState( + 'Select a namespace and key to edit its values' + ) + + const [updateKey, { loading }] = useDataMutation( + // @ts-expect-error("") + modifyKeyMutation({ store }), + { + onComplete: () => { + const message = i18n.t('Key successfully updated') + showSuccess(message) + }, + onError: () => { + const message = i18n.t('There was an error updating the key') + showError(message) + }, + } + ) + + const handleEditorChange = (value) => { + setValue(value) + } + + useEffect(() => { + setValue(JSON.stringify(data?.results, null, 4)) + }, [data]) + + useEffect(() => { + refetch({ key, namespace }) + }, [key, namespace, store, refetch]) + + if (error) { + return + } + + const loadingText = `${i18n.t('Loading')}...` + + return ( + <> + +
+ {key && key} + + +
+
+ + + ) +} + +export default PanelEdit diff --git a/src/components/panel/PanelEditor.tsx b/src/components/panel/PanelEditor.tsx new file mode 100644 index 0000000..5fbefa0 --- /dev/null +++ b/src/components/panel/PanelEditor.tsx @@ -0,0 +1,21 @@ +import { json } from '@codemirror/lang-json' +import CodeMirror, { ViewUpdate } from '@uiw/react-codemirror' +import React from 'react' + +type PanelEditorProps = { + handleChange?: (value: string, viewUpdate: ViewUpdate) => void + value: string +} + +const PanelEditor = ({ value, handleChange }: PanelEditorProps) => { + return ( + + ) +} + +export default PanelEditor diff --git a/src/components/panel/PanelEmptyArea.tsx b/src/components/panel/PanelEmptyArea.tsx new file mode 100644 index 0000000..f297431 --- /dev/null +++ b/src/components/panel/PanelEmptyArea.tsx @@ -0,0 +1,29 @@ +import { NoticeBox } from '@dhis2/ui' +import React from 'react' +import { useParams } from 'react-router-dom' +import i18n from '../../locales' +import EmptyPanelEditor from './EmptyPanelEditor' +import classes from './Panel.module.css' +import { PanelHeader } from './PanelHeader' + +const PanelEmptyArea = () => { + const { store, namespace } = useParams() + return ( + <> +
+ + Keys Panel + + {store && !namespace && ( +
+ + {i18n.t('Click a namespace to view its keys')} + +
+ )} +
+ + + ) +} +export default PanelEmptyArea diff --git a/src/components/panel/PanelError.tsx b/src/components/panel/PanelError.tsx new file mode 100644 index 0000000..b9b0c8d --- /dev/null +++ b/src/components/panel/PanelError.tsx @@ -0,0 +1,68 @@ +import { NoticeBox } from '@dhis2/ui' +import React from 'react' +import { Link, isRouteErrorResponse, useRouteError } from 'react-router-dom' +import i18n from '../../locales' +import classes from './Panel.module.css' +import { PanelHeader } from './PanelHeader' + +interface Error { + status?: number + statusText?: string + internal?: boolean + data?: string + message?: string +} + +export type ErrorResponse = { + httpStatus?: string + httpStatusCode?: number + status?: string + message?: string + errorCode?: string +} + +type PassedErrorProps = { + err?: ErrorResponse +} + +export default function PanelError({ err }: PassedErrorProps) { + const error: Error = useRouteError() + + return ( +
+ + Error + +
+ + {isRouteErrorResponse(error) ? ( + <> +

+ + {error.status} {error.statusText}{' '} + + - {error.data} +

+ + ) : ( +

+ + {error.status} {error.statusText}{' '} + + {error?.message && - {error.message}} +

+ )} + {err && ( +

+ + {err.httpStatusCode} {err.httpStatus}{' '} + + {err?.message && - {err.message}} +

+ )} + Back to datastore +
+
+
+ ) +} diff --git a/src/components/panel/PanelErrorPage.tsx b/src/components/panel/PanelErrorPage.tsx new file mode 100644 index 0000000..d97bf08 --- /dev/null +++ b/src/components/panel/PanelErrorPage.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import i18n from '../../locales' +import EmptyPanelEditor from './EmptyPanelEditor' +import PanelError from './PanelError' + +export default function PanelErrorPage() { + return ( + <> + + + + ) +} diff --git a/src/components/panel/PanelHeader.tsx b/src/components/panel/PanelHeader.tsx new file mode 100644 index 0000000..afa8c22 --- /dev/null +++ b/src/components/panel/PanelHeader.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import classes from './Panel.module.css' + +type PanelHeaderProps = { + children?: React.ReactElement +} + +export function PanelHeader({ children }: PanelHeaderProps) { + return
{children}
+} diff --git a/src/components/panel/PanelLink.tsx b/src/components/panel/PanelLink.tsx new file mode 100644 index 0000000..d662aa7 --- /dev/null +++ b/src/components/panel/PanelLink.tsx @@ -0,0 +1,55 @@ +import { Button } from '@dhis2/ui' +import { + IconFile16, + IconMore16, + IconFolder16, + IconFolderOpen16, +} from '@dhis2/ui-icons' +import React from 'react' +import { NavLink } from 'react-router-dom' +import classes from './Panel.module.css' + +type SidebarPanelLinkProps = { + label: string + to: string + type: string +} + +const SidebarPanelLink = ({ to, label, type }: SidebarPanelLinkProps) => { + const renderIcon = ({ isActive }) => + type === 'namespace' ? ( + isActive ? ( + + ) : ( + + ) + ) : ( + + ) + return ( +
  • + { + return isActive ? 'active' : '' + }} + > + {({ isActive }) => ( + <> + {renderIcon({ isActive })} + {label} +
  • + ) +} + +export default SidebarPanelLink diff --git a/src/components/panel/PanelLinksList.tsx b/src/components/panel/PanelLinksList.tsx new file mode 100644 index 0000000..8992164 --- /dev/null +++ b/src/components/panel/PanelLinksList.tsx @@ -0,0 +1,62 @@ +import React, { useEffect } from 'react' +import { useParams } from 'react-router-dom' +import CenteredLoader from '../Loader' +import classes from './Panel.module.css' +import { ErrorResponse } from './PanelError' +import SidebarPanelLink from './PanelLink' + +type PanelLinksListProps = { + data: { results: [] } + error: { details: ErrorResponse } + loading: boolean + refetchList: () => void + type: string +} + +function PanelLinksList({ + data, + error, + loading, + refetchList, + type, +}: PanelLinksListProps) { + const { store, namespace, key } = useParams() + // const [selectedLink, setSelectedLink] = useState('') + + useEffect(() => { + refetchList() + }, [store, namespace, key, refetchList]) + + if (error) { + throw new Response('', { + status: error?.details.httpStatusCode, + statusText: error?.details.status || error.details.message, + }) + } + + return ( +
    + {loading && } + {data && ( +
      + {data.results.map((value: string, index) => { + const path = + type === 'namespace' + ? `/${store}/edit/${value}` + : `/${store}/edit/${namespace}/${value}` + return ( + + ) + })} +
    + )} +
    + ) +} + +export default PanelLinksList diff --git a/src/components/panel/PanelRouter.tsx b/src/components/panel/PanelRouter.tsx new file mode 100644 index 0000000..61caa08 --- /dev/null +++ b/src/components/panel/PanelRouter.tsx @@ -0,0 +1,48 @@ +import React from 'react' +import { Navigate, createHashRouter } from 'react-router-dom' +import EmptyPanelEditor from './EmptyPanelEditor' +import Main from './Main' +import PanelEdit from './PanelEdit' +import PanelEmptyArea from './PanelEmptyArea' +import PanelError from './PanelError' +import PanelErrorPage from './PanelErrorPage' +import ThreePanelLayout from './ThreePanelLayout' + +export const threePanelRouter = createHashRouter([ + { + path: '/', + errorElement: , + element: , + children: [ + { index: true, element: }, + { + path: ':store', + children: [ + { + errorElement: , + children: [ + { + index: true, + element: , + }, + { + path: 'edit/:namespace', + element:
    , + children: [ + { + index: true, + element: , + }, + { + path: ':key', + element: , + }, + ], + }, + ], + }, + ], + }, + ], + }, +]) diff --git a/src/components/panel/SearchField.tsx b/src/components/panel/SearchField.tsx new file mode 100644 index 0000000..76e464c --- /dev/null +++ b/src/components/panel/SearchField.tsx @@ -0,0 +1,14 @@ +import { InputField } from '@dhis2/ui' +import React from 'react' +import i18n from '../../locales' +import classes from './Panel.module.css' + +const PanelSearchField = () => { + return ( +
    + +
    + ) +} + +export default PanelSearchField diff --git a/src/components/panel/SidebarPanel.tsx b/src/components/panel/SidebarPanel.tsx new file mode 100644 index 0000000..87a1210 --- /dev/null +++ b/src/components/panel/SidebarPanel.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import CreateButton from './CreateButton' +import classes from './Panel.module.css' +import { ErrorResponse } from './PanelError' +import PanelLinksList from './PanelLinksList' +import PanelSearchField from './SearchField' + +type SidebarPanelProps = { + data: { results: [] } + error: { details: ErrorResponse } + loading: boolean + refetchList: () => void + type: string +} + +const SidebarPanel = ({ + data, + error, + loading, + refetchList, + type, +}: SidebarPanelProps) => { + console.log(data, type, 'sidebar panel') + return ( +
    + + + +
    + ) +} + +export default SidebarPanel diff --git a/src/components/panel/ThreePanelLayout.tsx b/src/components/panel/ThreePanelLayout.tsx new file mode 100644 index 0000000..bd627ab --- /dev/null +++ b/src/components/panel/ThreePanelLayout.tsx @@ -0,0 +1,19 @@ +import React from 'react' +import { Outlet } from 'react-router-dom' +import NamespacesSidePanel from './NamespacesSidePanel' +import classes from './Panel.module.css' + +function ThreePanelLayout() { + return ( +
    + +
    + +
    +
    + ) +} + +export default ThreePanelLayout diff --git a/src/components/sidebar/sidebar.tsx b/src/components/sidebar/sidebar.tsx index 106830a..9487089 100644 --- a/src/components/sidebar/sidebar.tsx +++ b/src/components/sidebar/sidebar.tsx @@ -49,7 +49,7 @@ const Sidebar = () => { } else { setOption(store) } - }, [store]) + }, [store, navigate]) const handleDataStoreSelect = ({ selected }) => { setOption(selected) From 29af7dde9ce0222b64b45d2964a69c9431112188 Mon Sep 17 00:00:00 2001 From: Diana Nanyanzi Date: Sat, 7 Dec 2024 00:18:03 +0300 Subject: [PATCH 2/8] chore: reorganise files --- i18n/en.pot | 16 ++++++++-------- src/App.tsx | 2 +- .../panel/{PanelEdit.tsx => EditPanel.tsx} | 0 .../panel/{KeysSidePanel.tsx => KeysPanel.tsx} | 6 +++--- ...mespacesSidePanel.tsx => NamespacesPanel.tsx} | 12 +++++++----- src/components/panel/Panel.module.css | 2 +- src/components/panel/PanelErrorPage.tsx | 13 ------------- .../{PanelEmptyArea.tsx => empty/EmptyArea.tsx} | 14 +++++++------- .../EmptyEditor.tsx} | 14 +++++--------- .../{PanelError.tsx => error/ErrorComponent.tsx} | 10 +++++----- src/components/panel/error/ErrorPanel.tsx | 13 +++++++++++++ src/components/panel/{ => routes}/Main.tsx | 4 ++-- .../panel/{ => routes}/PanelRouter.tsx | 10 +++++----- .../panel/{ => routes}/ThreePanelLayout.tsx | 4 ++-- .../panel/{ => sidepanel}/CreateButton.tsx | 4 ++-- .../panel/{ => sidepanel}/DataStoreControl.tsx | 2 +- .../panel/{ => sidepanel}/PanelLink.tsx | 2 +- .../panel/{ => sidepanel}/PanelLinksList.tsx | 6 +++--- .../panel/{ => sidepanel}/SearchField.tsx | 4 ++-- .../SidePanel.tsx} | 12 ++++++------ 20 files changed, 74 insertions(+), 76 deletions(-) rename src/components/panel/{PanelEdit.tsx => EditPanel.tsx} (100%) rename src/components/panel/{KeysSidePanel.tsx => KeysPanel.tsx} (96%) rename src/components/panel/{NamespacesSidePanel.tsx => NamespacesPanel.tsx} (89%) delete mode 100644 src/components/panel/PanelErrorPage.tsx rename src/components/panel/{PanelEmptyArea.tsx => empty/EmptyArea.tsx} (71%) rename src/components/panel/{EmptyPanelEditor.tsx => empty/EmptyEditor.tsx} (60%) rename src/components/panel/{PanelError.tsx => error/ErrorComponent.tsx} (89%) create mode 100644 src/components/panel/error/ErrorPanel.tsx rename src/components/panel/{ => routes}/Main.tsx (78%) rename src/components/panel/{ => routes}/PanelRouter.tsx (86%) rename src/components/panel/{ => routes}/ThreePanelLayout.tsx (81%) rename src/components/panel/{ => sidepanel}/CreateButton.tsx (88%) rename src/components/panel/{ => sidepanel}/DataStoreControl.tsx (95%) rename src/components/panel/{ => sidepanel}/PanelLink.tsx (97%) rename src/components/panel/{ => sidepanel}/PanelLinksList.tsx (92%) rename src/components/panel/{ => sidepanel}/SearchField.tsx (78%) rename src/components/panel/{SidebarPanel.tsx => sidepanel/SidePanel.tsx} (79%) diff --git a/i18n/en.pot b/i18n/en.pot index 45add9d..d09fdc0 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-12-06T19:16:44.628Z\n" -"PO-Revision-Date: 2024-12-06T19:16:44.628Z\n" +"POT-Creation-Date: 2024-12-06T20:56:19.444Z\n" +"PO-Revision-Date: 2024-12-06T20:56:19.445Z\n" msgid "View keys" msgstr "View keys" @@ -89,6 +89,12 @@ msgstr "Namespaces" msgid "This will delete all the keys in this namespace" msgstr "This will delete all the keys in this namespace" +msgid "Select a namespace and key to edit its values" +msgstr "Select a namespace and key to edit its values" + +msgid "Error" +msgstr "Error" + msgid "New" msgstr "New" @@ -98,11 +104,5 @@ msgstr "DataStore" msgid "User DataStore" msgstr "User DataStore" -msgid "Select a namespace and key to edit its values" -msgstr "Select a namespace and key to edit its values" - -msgid "Error" -msgstr "Error" - msgid "Search" msgstr "Search" diff --git a/src/App.tsx b/src/App.tsx index b993b01..b3c9254 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ import React, { FC } from 'react' import { RouterProvider } from 'react-router-dom' import AppWrapper from './components/AppWrapper' -import { threePanelRouter } from './components/panel/PanelRouter' +import { threePanelRouter } from './components/panel/routes/PanelRouter' // import { router } from './routes/Router' const App: FC = () => { diff --git a/src/components/panel/PanelEdit.tsx b/src/components/panel/EditPanel.tsx similarity index 100% rename from src/components/panel/PanelEdit.tsx rename to src/components/panel/EditPanel.tsx diff --git a/src/components/panel/KeysSidePanel.tsx b/src/components/panel/KeysPanel.tsx similarity index 96% rename from src/components/panel/KeysSidePanel.tsx rename to src/components/panel/KeysPanel.tsx index 57f58a9..6866365 100644 --- a/src/components/panel/KeysSidePanel.tsx +++ b/src/components/panel/KeysPanel.tsx @@ -2,7 +2,7 @@ import { useDataQuery } from '@dhis2/app-service-data' import React, { useEffect } from 'react' import { useParams } from 'react-router-dom' import { PanelHeader } from './PanelHeader' -import SidebarPanel from './SidebarPanel' +import SidebarPanel from './sidepanel/SidePanel' interface QueryResults { results: [] @@ -22,7 +22,7 @@ const userDataStoreQuery = { }, } -const KeysSidePanel = () => { +const KeysPanel = () => { // const navigate = useNavigate() const { store, namespace } = useParams() // const [option, setOption] = useState(store || '') @@ -106,4 +106,4 @@ const KeysSidePanel = () => { ) } -export default KeysSidePanel +export default KeysPanel diff --git a/src/components/panel/NamespacesSidePanel.tsx b/src/components/panel/NamespacesPanel.tsx similarity index 89% rename from src/components/panel/NamespacesSidePanel.tsx rename to src/components/panel/NamespacesPanel.tsx index d76ec6e..a89a747 100644 --- a/src/components/panel/NamespacesSidePanel.tsx +++ b/src/components/panel/NamespacesPanel.tsx @@ -1,9 +1,9 @@ import { useDataQuery } from '@dhis2/app-service-data' import React, { useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' -import DataStoreControl from './DataStoreControl' import { PanelHeader } from './PanelHeader' -import SidebarPanel from './SidebarPanel' +import DataStoreControl from './sidepanel/DataStoreControl' +import SidebarPanel from './sidepanel/SidePanel' interface QueryResults { results: [] @@ -21,10 +21,10 @@ const userDataStoreQuery = { }, } -const NamespacesSidePanel = () => { +const NamespacesPanel = () => { const navigate = useNavigate() const { store } = useParams() - const [option, setOption] = useState(store || '') + const [option, setOption] = useState(store || 'dataStore') const RenderUserDataStorePanel = () => { const { @@ -77,8 +77,10 @@ const NamespacesSidePanel = () => { navigate(`/${value}`) } + console.log('store', store) useEffect(() => { const storeOptions = ['dataStore', 'userDataStore'] + // console.log("store", store) if (!storeOptions.includes(store)) { navigate('/dataStore') } else { @@ -100,4 +102,4 @@ const NamespacesSidePanel = () => { ) } -export default NamespacesSidePanel +export default NamespacesPanel diff --git a/src/components/panel/Panel.module.css b/src/components/panel/Panel.module.css index 8d8971d..b7ca098 100644 --- a/src/components/panel/Panel.module.css +++ b/src/components/panel/Panel.module.css @@ -8,7 +8,7 @@ /* font-size: 1rem; */ display: grid; grid-template-columns: 400px auto; - border-bottom: 1px solid var(--colors-grey100); + border: 1px solid var(--colors-grey300); } .panelHeader { diff --git a/src/components/panel/PanelErrorPage.tsx b/src/components/panel/PanelErrorPage.tsx deleted file mode 100644 index d97bf08..0000000 --- a/src/components/panel/PanelErrorPage.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' -import i18n from '../../locales' -import EmptyPanelEditor from './EmptyPanelEditor' -import PanelError from './PanelError' - -export default function PanelErrorPage() { - return ( - <> - - - - ) -} diff --git a/src/components/panel/PanelEmptyArea.tsx b/src/components/panel/empty/EmptyArea.tsx similarity index 71% rename from src/components/panel/PanelEmptyArea.tsx rename to src/components/panel/empty/EmptyArea.tsx index f297431..ad6c706 100644 --- a/src/components/panel/PanelEmptyArea.tsx +++ b/src/components/panel/empty/EmptyArea.tsx @@ -1,18 +1,18 @@ import { NoticeBox } from '@dhis2/ui' import React from 'react' import { useParams } from 'react-router-dom' -import i18n from '../../locales' -import EmptyPanelEditor from './EmptyPanelEditor' -import classes from './Panel.module.css' -import { PanelHeader } from './PanelHeader' +import i18n from '../../../locales' +import classes from '../Panel.module.css' +import { PanelHeader } from '../PanelHeader' +import EmptyPanelEditor from './EmptyEditor' -const PanelEmptyArea = () => { +const EmptyArea = () => { const { store, namespace } = useParams() return ( <>
    - Keys Panel + {''} {store && !namespace && (
    @@ -26,4 +26,4 @@ const PanelEmptyArea = () => { ) } -export default PanelEmptyArea +export default EmptyArea diff --git a/src/components/panel/EmptyPanelEditor.tsx b/src/components/panel/empty/EmptyEditor.tsx similarity index 60% rename from src/components/panel/EmptyPanelEditor.tsx rename to src/components/panel/empty/EmptyEditor.tsx index 5bccba5..b3774ae 100644 --- a/src/components/panel/EmptyPanelEditor.tsx +++ b/src/components/panel/empty/EmptyEditor.tsx @@ -1,20 +1,16 @@ import React from 'react' -import i18n from '../../locales' -import PanelEditor from './PanelEditor' -import { PanelHeader } from './PanelHeader' +import i18n from '../../../locales' +import PanelEditor from '../PanelEditor' +import { PanelHeader } from '../PanelHeader' -export default function EmptyPanelEditor({ - placeholder, -}: { - placeholder?: string -}) { +export default function EmptyEditor({ placeholder }: { placeholder?: string }) { const defaultMessage = i18n.t( 'Select a namespace and key to edit its values' ) return (
    - Editor + {''} - Error + {''}
    diff --git a/src/components/panel/error/ErrorPanel.tsx b/src/components/panel/error/ErrorPanel.tsx new file mode 100644 index 0000000..6d2ee20 --- /dev/null +++ b/src/components/panel/error/ErrorPanel.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import i18n from '../../../locales' +import EmptyPanelEditor from '../empty/EmptyEditor' +import ErrorComponent from './ErrorComponent' + +export default function ErrorPanel() { + return ( + <> + + + + ) +} diff --git a/src/components/panel/Main.tsx b/src/components/panel/routes/Main.tsx similarity index 78% rename from src/components/panel/Main.tsx rename to src/components/panel/routes/Main.tsx index bfad11d..38cbf5a 100644 --- a/src/components/panel/Main.tsx +++ b/src/components/panel/routes/Main.tsx @@ -1,7 +1,7 @@ import React from 'react' import { Outlet } from 'react-router-dom' -import KeysSidePanel from './KeysSidePanel' -import classes from './Panel.module.css' +import KeysSidePanel from '../KeysPanel' +import classes from '../Panel.module.css' export default function Main() { return ( diff --git a/src/components/panel/PanelRouter.tsx b/src/components/panel/routes/PanelRouter.tsx similarity index 86% rename from src/components/panel/PanelRouter.tsx rename to src/components/panel/routes/PanelRouter.tsx index 61caa08..b210e3f 100644 --- a/src/components/panel/PanelRouter.tsx +++ b/src/components/panel/routes/PanelRouter.tsx @@ -1,11 +1,11 @@ import React from 'react' import { Navigate, createHashRouter } from 'react-router-dom' -import EmptyPanelEditor from './EmptyPanelEditor' +import PanelEdit from '../EditPanel' +import PanelEmptyArea from '../empty/EmptyArea' +import EmptyPanelEditor from '../empty/EmptyEditor' +import PanelError from '../error/ErrorComponent' +import PanelErrorPage from '../error/ErrorPanel' import Main from './Main' -import PanelEdit from './PanelEdit' -import PanelEmptyArea from './PanelEmptyArea' -import PanelError from './PanelError' -import PanelErrorPage from './PanelErrorPage' import ThreePanelLayout from './ThreePanelLayout' export const threePanelRouter = createHashRouter([ diff --git a/src/components/panel/ThreePanelLayout.tsx b/src/components/panel/routes/ThreePanelLayout.tsx similarity index 81% rename from src/components/panel/ThreePanelLayout.tsx rename to src/components/panel/routes/ThreePanelLayout.tsx index bd627ab..e4edc35 100644 --- a/src/components/panel/ThreePanelLayout.tsx +++ b/src/components/panel/routes/ThreePanelLayout.tsx @@ -1,7 +1,7 @@ import React from 'react' import { Outlet } from 'react-router-dom' -import NamespacesSidePanel from './NamespacesSidePanel' -import classes from './Panel.module.css' +import NamespacesSidePanel from '../NamespacesPanel' +import classes from '../Panel.module.css' function ThreePanelLayout() { return ( diff --git a/src/components/panel/CreateButton.tsx b/src/components/panel/sidepanel/CreateButton.tsx similarity index 88% rename from src/components/panel/CreateButton.tsx rename to src/components/panel/sidepanel/CreateButton.tsx index 9a0f307..03ffbbb 100644 --- a/src/components/panel/CreateButton.tsx +++ b/src/components/panel/sidepanel/CreateButton.tsx @@ -1,8 +1,8 @@ import { Button } from '@dhis2/ui' import { IconAdd16 } from '@dhis2/ui-icons' import React from 'react' -import i18n from '../../locales' -import classes from './Panel.module.css' +import i18n from '../../../locales' +import classes from '../Panel.module.css' const CreateButton = () => { return ( diff --git a/src/components/panel/DataStoreControl.tsx b/src/components/panel/sidepanel/DataStoreControl.tsx similarity index 95% rename from src/components/panel/DataStoreControl.tsx rename to src/components/panel/sidepanel/DataStoreControl.tsx index 83c7e51..995c6c5 100644 --- a/src/components/panel/DataStoreControl.tsx +++ b/src/components/panel/sidepanel/DataStoreControl.tsx @@ -1,6 +1,6 @@ import { SegmentedControl } from '@dhis2/ui' import React from 'react' -import i18n from '../../locales' +import i18n from '../../../locales' type DataStoreControlProps = { option: string diff --git a/src/components/panel/PanelLink.tsx b/src/components/panel/sidepanel/PanelLink.tsx similarity index 97% rename from src/components/panel/PanelLink.tsx rename to src/components/panel/sidepanel/PanelLink.tsx index d662aa7..41f6997 100644 --- a/src/components/panel/PanelLink.tsx +++ b/src/components/panel/sidepanel/PanelLink.tsx @@ -7,7 +7,7 @@ import { } from '@dhis2/ui-icons' import React from 'react' import { NavLink } from 'react-router-dom' -import classes from './Panel.module.css' +import classes from '../Panel.module.css' type SidebarPanelLinkProps = { label: string diff --git a/src/components/panel/PanelLinksList.tsx b/src/components/panel/sidepanel/PanelLinksList.tsx similarity index 92% rename from src/components/panel/PanelLinksList.tsx rename to src/components/panel/sidepanel/PanelLinksList.tsx index 8992164..0cc5a2a 100644 --- a/src/components/panel/PanelLinksList.tsx +++ b/src/components/panel/sidepanel/PanelLinksList.tsx @@ -1,8 +1,8 @@ import React, { useEffect } from 'react' import { useParams } from 'react-router-dom' -import CenteredLoader from '../Loader' -import classes from './Panel.module.css' -import { ErrorResponse } from './PanelError' +import CenteredLoader from '../../Loader' +import { ErrorResponse } from '../error/ErrorComponent' +import classes from '../Panel.module.css' import SidebarPanelLink from './PanelLink' type PanelLinksListProps = { diff --git a/src/components/panel/SearchField.tsx b/src/components/panel/sidepanel/SearchField.tsx similarity index 78% rename from src/components/panel/SearchField.tsx rename to src/components/panel/sidepanel/SearchField.tsx index 76e464c..6e51b56 100644 --- a/src/components/panel/SearchField.tsx +++ b/src/components/panel/sidepanel/SearchField.tsx @@ -1,7 +1,7 @@ import { InputField } from '@dhis2/ui' import React from 'react' -import i18n from '../../locales' -import classes from './Panel.module.css' +import i18n from '../../../locales' +import classes from '../Panel.module.css' const PanelSearchField = () => { return ( diff --git a/src/components/panel/SidebarPanel.tsx b/src/components/panel/sidepanel/SidePanel.tsx similarity index 79% rename from src/components/panel/SidebarPanel.tsx rename to src/components/panel/sidepanel/SidePanel.tsx index 87a1210..f499d7c 100644 --- a/src/components/panel/SidebarPanel.tsx +++ b/src/components/panel/sidepanel/SidePanel.tsx @@ -1,11 +1,11 @@ import React from 'react' +import { ErrorResponse } from '../error/ErrorComponent' +import classes from '../Panel.module.css' import CreateButton from './CreateButton' -import classes from './Panel.module.css' -import { ErrorResponse } from './PanelError' import PanelLinksList from './PanelLinksList' import PanelSearchField from './SearchField' -type SidebarPanelProps = { +type SidePanelProps = { data: { results: [] } error: { details: ErrorResponse } loading: boolean @@ -13,13 +13,13 @@ type SidebarPanelProps = { type: string } -const SidebarPanel = ({ +const SidePanel = ({ data, error, loading, refetchList, type, -}: SidebarPanelProps) => { +}: SidePanelProps) => { console.log(data, type, 'sidebar panel') return (
    @@ -36,4 +36,4 @@ const SidebarPanel = ({ ) } -export default SidebarPanel +export default SidePanel From c62f5368109e51abaaa83e24a64e77eb79eb4beb Mon Sep 17 00:00:00 2001 From: Diana Nanyanzi Date: Sat, 7 Dec 2024 01:17:30 +0300 Subject: [PATCH 3/8] feat: implement add namespace and key functionality --- src/components/panel/modals/CreateModal.tsx | 79 ++++++++++++++++++ .../panel/sidepanel/CreateButton.tsx | 14 ++-- src/components/panel/sidepanel/SidePanel.tsx | 81 ++++++++++++++++++- 3 files changed, 163 insertions(+), 11 deletions(-) create mode 100644 src/components/panel/modals/CreateModal.tsx diff --git a/src/components/panel/modals/CreateModal.tsx b/src/components/panel/modals/CreateModal.tsx new file mode 100644 index 0000000..f908fb2 --- /dev/null +++ b/src/components/panel/modals/CreateModal.tsx @@ -0,0 +1,79 @@ +import { + Modal, + ModalTitle, + ModalContent, + ModalActions, + Button, + ButtonStrip, + InputField, +} from '@dhis2/ui' +import React from 'react' +import i18n from '../../../locales' +import { CreateFieldValues } from '../sidepanel/SidePanel' + +type CreateModalProps = { + createFn: (values) => void, + values: CreateFieldValues, + setValues: (values) => void, + closeModal: () => void, + title: string, + type: string, + buttonLabel: string +} + +const CreateModal = ({ + createFn, + values, + setValues, + closeModal, + title, + type, + buttonLabel +}: CreateModalProps) => { + return ( + + + {title} + + + {type === 'namespace' && ( + { + setValues({ + ...values, + ['namespace']: value, + }) + }} + /> + )} + { + setValues({ + ...values, + ['key']: value, + }) + }} + /> + + + + + + + + + ) +} +export default CreateModal diff --git a/src/components/panel/sidepanel/CreateButton.tsx b/src/components/panel/sidepanel/CreateButton.tsx index 03ffbbb..67cf2e9 100644 --- a/src/components/panel/sidepanel/CreateButton.tsx +++ b/src/components/panel/sidepanel/CreateButton.tsx @@ -4,19 +4,17 @@ import React from 'react' import i18n from '../../../locales' import classes from '../Panel.module.css' -const CreateButton = () => { +const CreateButton = ({ label, handleClick }) => { return (
    ) diff --git a/src/components/panel/sidepanel/SidePanel.tsx b/src/components/panel/sidepanel/SidePanel.tsx index f499d7c..f41221d 100644 --- a/src/components/panel/sidepanel/SidePanel.tsx +++ b/src/components/panel/sidepanel/SidePanel.tsx @@ -1,9 +1,13 @@ -import React from 'react' +import React, { useState } from 'react' import { ErrorResponse } from '../error/ErrorComponent' import classes from '../Panel.module.css' import CreateButton from './CreateButton' import PanelLinksList from './PanelLinksList' import PanelSearchField from './SearchField' +import i18n from '../../../locales' +import CreateModal from '../modals/CreateModal' +import { useDataEngine } from '@dhis2/app-service-data' +import { useNavigate, useParams } from 'react-router' type SidePanelProps = { data: { results: [] } @@ -13,6 +17,11 @@ type SidePanelProps = { type: string } +export type CreateFieldValues = { + namespace?: string, + key?: string +} + const SidePanel = ({ data, error, @@ -20,11 +29,66 @@ const SidePanel = ({ refetchList, type, }: SidePanelProps) => { - console.log(data, type, 'sidebar panel') + const engine = useDataEngine() + const navigate = useNavigate() + const { store, namespace: currentNamespace } = useParams() + const [openModal, setOpenModal] = useState(false) + const [values, setValues] = useState({}) + + // const { showSuccess, showError } = useCustomAlert() + + const handleCreate = async (values: CreateFieldValues) => { + let resource = '' + if (type === 'namespace') { + resource = `${store}/${values?.namespace}/${values?.key}` + } else { + resource = `${store}/${currentNamespace}/${values?.key}` + } + + await engine.mutate( + { + type: 'create', + resource, + data: () => ({}), + }, + { + onComplete: () => { + let url = '' + if (type === 'namespace') { + url = `${store}/edit/${values?.namespace}/${values?.key}` + } else { + url = `${values?.key}` + } + const message = i18n.t('Key created successfully') + // showSuccess(message) + navigate(url) + setValues({}) + }, + onError: () => { + const message = i18n.t( + 'There was an error creating the key' + ) + // showError(message) + }, + } + ) + setOpenModal(false) + } + + const derivedModalProps = { + title: type === "namespace" ? i18n.t("Add New Namespace") : i18n.t("Add New Key"), + buttonLabel: type === "namespace" ? i18n.t("Add Namespace") : i18n.t("Add Key"), + } + const createButtonLabel = type === "namespace" ? i18n.t("New namespace") : i18n.t("New key"); + return ( + <>
    - + setOpenModal(true)} + />
    + {openModal && ( + setOpenModal(false)} + type={type} + {...derivedModalProps} + /> + )} + ) } From 59877d9fea821f42e47831ed99303a79f5044143 Mon Sep 17 00:00:00 2001 From: Diana Nanyanzi Date: Sat, 7 Dec 2024 01:41:20 +0300 Subject: [PATCH 4/8] refactor: error handling in editing panel --- src/components/panel/EditPanel.tsx | 40 +++++++++--------------- src/components/panel/NamespacesPanel.tsx | 2 -- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/components/panel/EditPanel.tsx b/src/components/panel/EditPanel.tsx index b7883c9..ef74ceb 100644 --- a/src/components/panel/EditPanel.tsx +++ b/src/components/panel/EditPanel.tsx @@ -24,24 +24,6 @@ const keyValuesQuery = ({ store }: { store: string }) => ({ }, }) -// const useKeyValuesQuery = ({ store, key, namespace }) => { -// if (key && namespace) { -// return useDataQuery(keyValuesQuery({ store }), { -// variables: { -// key, -// namespace, -// }, -// }) -// } else { -// return { -// data: null, -// loading: false, -// error: null, -// refetch: () => Promise.resolve(), -// } -// } -// } - const PanelEdit = () => { const { key, namespace, store } = useParams() const { showSuccess, showError } = useCustomAlert() @@ -81,6 +63,20 @@ const PanelEdit = () => { setValue(value) } + const handleUpdate = async () => { + try { + await updateKey({ + key, + namespace, + value, + }) + } catch (error) { + const message = i18n.t('There was an error updating the key') + showError(message) + } + + } + useEffect(() => { setValue(JSON.stringify(data?.results, null, 4)) }, [data]) @@ -110,13 +106,7 @@ const PanelEdit = () => { - - - - - ) -} - -CreateModal.propTypes = { - addNewKey: PropTypes.bool, - addNewNamespace: PropTypes.bool, - closeModal: PropTypes.func, - createFn: PropTypes.func, - setValues: PropTypes.func, - values: PropTypes.object, -} - -export default CreateModal diff --git a/src/components/create/Toolbar.tsx b/src/components/create/Toolbar.tsx deleted file mode 100644 index 172b5f6..0000000 --- a/src/components/create/Toolbar.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { useDataEngine } from '@dhis2/app-service-data' -import { Button, Divider } from '@dhis2/ui' -import React, { useState } from 'react' -import { useNavigate, useParams } from 'react-router-dom' -import classes from '../../App.module.css' -import useCustomAlert from '../../hooks/useCustomAlert' -import i18n from '../../locales' -import CreateModal from './CreateModal' - -const Toolbar = () => { - const { store, namespace } = useParams() - const engine = useDataEngine() - const navigate = useNavigate() - - const [addNewNamespace, setAddNewNamespace] = useState(false) - const [addNewKey, setAddNewKey] = useState(false) - const [values, setValues] = useState({}) - - const { showSuccess, showError } = useCustomAlert() - - const handleAddNamespaceOrKey = async (values: { - namespace?: string - key?: unknown - }) => { - let resource = '' - if (addNewNamespace) { - resource = `${store}/${values?.namespace}/${values?.key}` - } else if (addNewKey) { - resource = `${store}/${namespace}/${values?.key}` - } - - await engine.mutate( - { - type: 'create', - resource, - data: () => ({}), - }, - { - onComplete: () => { - let url = '' - if (addNewNamespace) { - url = `${store}/edit/${values?.namespace}/${values?.key}` - } else if (addNewKey) { - url = `${store}/edit/${namespace}/${values?.key}` - } - const message = i18n.t('Key created successfully') - showSuccess(message) - navigate(url) - setValues({}) - }, - onError: () => { - const message = i18n.t( - 'There was an error creating the key' - ) - showError(message) - }, - } - ) - closeModal() - } - - const closeModal = () => { - setAddNewKey(false) - setAddNewNamespace(false) - } - - return ( - <> - {store && ( - <> -
    - - {namespace && ( - - )} -
    - - - )} - {(addNewKey || addNewNamespace) && ( - - )} - - ) -} - -export default Toolbar diff --git a/src/components/delete/DeleteButton.tsx b/src/components/delete/DeleteButton.tsx deleted file mode 100644 index a2fe5e6..0000000 --- a/src/components/delete/DeleteButton.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Button } from '@dhis2-ui/button' -import PropTypes from 'prop-types' -import React from 'react' -import i18n from '../../locales' - -export default function DeleteButton({ openModal }) { - return ( - - ) -} - -DeleteButton.propTypes = { - openModal: PropTypes.func, -} diff --git a/src/components/delete/DeleteModal.tsx b/src/components/delete/DeleteModal.tsx deleted file mode 100644 index 14ef64c..0000000 --- a/src/components/delete/DeleteModal.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { - Modal, - ModalContent, - ModalActions, - Button, - ButtonStrip, -} from '@dhis2/ui' -import PropTypes from 'prop-types' -import React from 'react' -import i18n from '../../locales' - -const DeleteModal = ({ children, deleteFn, closeModal }) => { - return ( - - {children} - - - - - - - - ) -} - -DeleteModal.propTypes = { - children: PropTypes.node, - closeModal: PropTypes.func, - deleteFn: PropTypes.func, -} - -export default DeleteModal diff --git a/src/components/edit/Edit.tsx b/src/components/edit/Edit.tsx deleted file mode 100644 index 3591c9c..0000000 --- a/src/components/edit/Edit.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { useDataMutation, useDataQuery } from '@dhis2/app-runtime' -import { Button } from '@dhis2-ui/button' -import React, { useEffect, useState } from 'react' -import { useParams } from 'react-router-dom' -import useCustomAlert from '../../hooks/useCustomAlert' -import i18n from '../../locales' -import Error from '../Error' -import Editor from './Editor' - -const modifyKeyMutation = ({ store }) => ({ - type: 'update' as const, - resource: `${store}`, - id: ({ key, namespace }: { key: string; namespace: string }) => - `${namespace}/${key}`, - data: ({ value }) => JSON.parse(value), -}) - -const keyValuesQuery = ({ store }: { store: string }) => ({ - results: { - resource: `${store}`, - id: ({ key, namespace }: { key: string; namespace: string }) => - `${namespace}/${key}`, - }, -}) - -const Edit = () => { - const { key, namespace, store } = useParams() - const { showSuccess, showError } = useCustomAlert() - - const { - data, - loading: queryLoading, - error, - refetch, - } = useDataQuery(keyValuesQuery({ store }), { - variables: { - key, - namespace, - }, - }) - - const [value, setValue] = useState( - JSON.stringify(data?.results, null, 4) || '' - ) - - const [updateKey, { loading }] = useDataMutation( - // @ts-expect-error("") - modifyKeyMutation({ store }), - { - onComplete: () => { - const message = i18n.t('Key successfully updated') - showSuccess(message) - }, - onError: () => { - const message = i18n.t('There was an error updating the key') - showError(message) - }, - } - ) - - const handleEditorChange = (value) => { - setValue(value) - } - - useEffect(() => { - setValue(JSON.stringify(data?.results, null, 4)) - }, [data]) - - useEffect(() => { - refetch({ key, namespace }) - }, [key, namespace, store, refetch]) - - if (error) { - // throw new Response(error.message, { - // status: error.details.httpStatusCode, - // statusText: error.details.httpStatus, - // }) - return - } - - const loadingText = i18n.t('Loading') - - return ( -
    - -
    - -
    -
    - ) -} - -export default Edit diff --git a/src/components/edit/Editor.tsx b/src/components/edit/Editor.tsx deleted file mode 100644 index fa6ea01..0000000 --- a/src/components/edit/Editor.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { json } from '@codemirror/lang-json' -import CodeMirror from '@uiw/react-codemirror' -import PropTypes from 'prop-types' -import React from 'react' - -const Editor = ({ value, handleChange }) => { - return ( - - ) -} - -Editor.propTypes = { - handleChange: PropTypes.func, - value: PropTypes.string, -} - -export default Editor diff --git a/src/components/panel/empty/EmptyArea.tsx b/src/components/empty/EmptyArea.tsx similarity index 90% rename from src/components/panel/empty/EmptyArea.tsx rename to src/components/empty/EmptyArea.tsx index ad6c706..d00f736 100644 --- a/src/components/panel/empty/EmptyArea.tsx +++ b/src/components/empty/EmptyArea.tsx @@ -1,9 +1,9 @@ import { NoticeBox } from '@dhis2/ui' import React from 'react' import { useParams } from 'react-router-dom' -import i18n from '../../../locales' +import i18n from '../../locales' import classes from '../Panel.module.css' -import { PanelHeader } from '../PanelHeader' +import { PanelHeader } from '../sidepanel/PanelHeader' import EmptyPanelEditor from './EmptyEditor' const EmptyArea = () => { diff --git a/src/components/panel/empty/EmptyEditor.tsx b/src/components/empty/EmptyEditor.tsx similarity index 77% rename from src/components/panel/empty/EmptyEditor.tsx rename to src/components/empty/EmptyEditor.tsx index b3774ae..a189b36 100644 --- a/src/components/panel/empty/EmptyEditor.tsx +++ b/src/components/empty/EmptyEditor.tsx @@ -1,7 +1,7 @@ import React from 'react' -import i18n from '../../../locales' -import PanelEditor from '../PanelEditor' -import { PanelHeader } from '../PanelHeader' +import i18n from '../../locales' +import PanelEditor from '../sidepanel/PanelEditor' +import { PanelHeader } from '../sidepanel/PanelHeader' export default function EmptyEditor({ placeholder }: { placeholder?: string }) { const defaultMessage = i18n.t( diff --git a/src/components/panel/error/ErrorComponent.tsx b/src/components/error/ErrorComponent.tsx similarity index 95% rename from src/components/panel/error/ErrorComponent.tsx rename to src/components/error/ErrorComponent.tsx index babec59..4c5d42d 100644 --- a/src/components/panel/error/ErrorComponent.tsx +++ b/src/components/error/ErrorComponent.tsx @@ -1,9 +1,9 @@ import { NoticeBox } from '@dhis2/ui' import React from 'react' import { Link, isRouteErrorResponse, useRouteError } from 'react-router-dom' -import i18n from '../../../locales' +import i18n from '../../locales' import classes from '../Panel.module.css' -import { PanelHeader } from '../PanelHeader' +import { PanelHeader } from '../sidepanel/PanelHeader' interface Error { status?: number diff --git a/src/components/panel/error/ErrorPanel.tsx b/src/components/error/ErrorPanel.tsx similarity index 89% rename from src/components/panel/error/ErrorPanel.tsx rename to src/components/error/ErrorPanel.tsx index 6d2ee20..7e29525 100644 --- a/src/components/panel/error/ErrorPanel.tsx +++ b/src/components/error/ErrorPanel.tsx @@ -1,5 +1,5 @@ import React from 'react' -import i18n from '../../../locales' +import i18n from '../../locales' import EmptyPanelEditor from '../empty/EmptyEditor' import ErrorComponent from './ErrorComponent' diff --git a/src/components/keys/Keys.tsx b/src/components/keys/Keys.tsx deleted file mode 100644 index 1eaa45c..0000000 --- a/src/components/keys/Keys.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' -import KeysTable from './KeysTable' - -export default function Keys() { - return ( -
    - -
    - ) -} diff --git a/src/components/keys/keysTable.tsx b/src/components/keys/keysTable.tsx deleted file mode 100644 index f0d049b..0000000 --- a/src/components/keys/keysTable.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import { useDataEngine, useDataQuery } from '@dhis2/app-runtime' -import { - DataTable, - DataTableCell, - DataTableColumnHeader, - DataTableRow, - TableBody, - TableHead, -} from '@dhis2/ui' -import React, { useEffect, useState } from 'react' -import { useNavigate, useParams } from 'react-router-dom' -import classes from '../../App.module.css' -import useCustomAlert from '../../hooks/useCustomAlert' -import i18n from '../../locales' -import DeleteButton from '../delete/DeleteButton' -import DeleteModal from '../delete/DeleteModal' -import Error from '../Error' -import CenteredLoader from '../Loader' - -interface QueryResults { - results: [] -} - -const fetchNamespaceQuery = ({ store }) => ({ - results: { - resource: `${store}`, - id: ({ id }) => id, - }, -}) - -const KeysTable = () => { - const { store, namespace } = useParams() - const navigate = useNavigate() - const engine = useDataEngine() - const { showError, showSuccess } = useCustomAlert() - - const { data, loading, refetch, error } = useDataQuery( - fetchNamespaceQuery({ store }), - { - variables: { - id: namespace, - }, - } - ) - - const [deleteNamespace, setDeleteNamespace] = useState(false) - const [selectedKey, setSelectedKey] = useState('') - const [openModal, setOpenModal] = useState(false) - - useEffect(() => { - refetch({ id: namespace }) - }, [namespace, refetch]) - - const handleDeleteAction = async (key) => { - await engine.mutate( - { - type: 'delete', - resource: `${store}/${namespace}`, - id: key, - }, - { - onComplete: () => { - const message = i18n.t('Key deleted successfully') - showSuccess(message) - }, - onError: (error) => { - const message = i18n.t( - 'There was an error deleting the key', - { - error: error.message, - } - ) - showError(message) - }, - } - ) - setOpenModal(false) - - if (deleteNamespace) { - navigate(`/${store}`) - } else { - refetch({ id: namespace }) - } - } - - if (loading) { - return - } - - if (error) { - // throw new Response(error.message, { - // status: error.details.httpStatusCode, - // statusText: error.details.httpStatus, - // }) - return - } - - return ( -
    - {data && ( - - - - Keys - - Actions - - - - - {data?.results?.length && ( - <> - {data.results.map((key, index) => { - const handleClick = () => { - const url = `/${store}/edit/${namespace}/${key}` - navigate(url) - } - return ( - - - {key} - - - { - setOpenModal(true) - setDeleteNamespace( - data?.results - ?.length < 2 - ) - setSelectedKey(key) - }} - /> - - - ) - })} - - )} - - - )} - {openModal && ( - handleDeleteAction(selectedKey)} - closeModal={() => setOpenModal(false)} - > -

    - {i18n.t( - `Are you sure you want to delete '${selectedKey}' in ${namespace}?` - )} -

    - {deleteNamespace && ( -

    - {i18n.t( - `This will also delete the namespace '${namespace}'` - )} -

    - )} -
    - )} -
    - ) -} - -export default KeysTable diff --git a/src/components/panel/modals/CreateModal.tsx b/src/components/modals/CreateModal.tsx similarity index 86% rename from src/components/panel/modals/CreateModal.tsx rename to src/components/modals/CreateModal.tsx index f908fb2..acff421 100644 --- a/src/components/panel/modals/CreateModal.tsx +++ b/src/components/modals/CreateModal.tsx @@ -8,16 +8,16 @@ import { InputField, } from '@dhis2/ui' import React from 'react' -import i18n from '../../../locales' +import i18n from '../../locales' import { CreateFieldValues } from '../sidepanel/SidePanel' type CreateModalProps = { - createFn: (values) => void, - values: CreateFieldValues, - setValues: (values) => void, - closeModal: () => void, - title: string, - type: string, + createFn: (values) => void + values: CreateFieldValues + setValues: (values) => void + closeModal: () => void + title: string + type: string buttonLabel: string } @@ -28,13 +28,11 @@ const CreateModal = ({ closeModal, title, type, - buttonLabel + buttonLabel, }: CreateModalProps) => { return ( - - {title} - + {title} {type === 'namespace' && ( { - await engine.mutate( - { - type: 'delete', - resource: `${store}/${selectedNamespace}`, - id: key, - }, - { - onComplete: () => { - const message = i18n.t('Key deleted successfully', { - key, - }) - showSuccess(message) - }, - onError: (error) => { - const message = i18n.t( - 'There was an error while deleting the key', - { - error: error.message, - } - ) - showError(message) - }, - } - ) - - setOpenModal(false) - refetchList() - navigate(`${store}`) - } - - useEffect(() => { - refetchList() - }, [store, namespace, key, refetchList]) - - return ( -
    - {error && {i18n.t('Error fetching namespaces')}} - {loading && } - {data && ( - <> -

    {i18n.t('Namespaces')}

    -
      - {data.results.map((namespace: string, index) => { - return ( - { - setOpenModal(true) - setSelectedNamespace(namespace) - }} - /> - ) - })} -
    - - )} - {openModal && ( - handleDeleteAction(selectedNamespace)} - closeModal={() => setOpenModal(false)} - > -

    - {i18n.t( - `Are you sure you want to delete '${namespace}'?` - )} -

    -

    - {i18n.t( - `This will delete all the keys in this namespace` - )} -

    -
    - )} -
    - ) -} - -LinksList.propTypes = { - data: PropTypes.object, - error: PropTypes.any, - loading: PropTypes.any, - refetchList: PropTypes.func, -} - -export default LinksList diff --git a/src/components/panel/EditPanel.tsx b/src/components/panels/EditPanel.tsx similarity index 86% rename from src/components/panel/EditPanel.tsx rename to src/components/panels/EditPanel.tsx index f2a30c7..741ee0d 100644 --- a/src/components/panel/EditPanel.tsx +++ b/src/components/panels/EditPanel.tsx @@ -4,9 +4,9 @@ import React, { useEffect, useState } from 'react' import { useParams } from 'react-router-dom' import useCustomAlert from '../../hooks/useCustomAlert' import i18n from '../../locales' -import Error from '../Error' -import PanelEditor from './PanelEditor' -import { PanelHeader } from './PanelHeader' +import ErrorComponent from '../error/ErrorComponent' +import PanelEditor from '../sidepanel/PanelEditor' +import { PanelHeader } from '../sidepanel/PanelHeader' const modifyKeyMutation = ({ store }) => ({ type: 'update' as const, @@ -24,9 +24,10 @@ const keyValuesQuery = ({ store }: { store: string }) => ({ }, }) -const PanelEdit = () => { +const EditPanel = () => { const { key, namespace, store } = useParams() const { showSuccess, showError } = useCustomAlert() + // const [ updateError, setUpdateError ] = useState(null) const { data, @@ -44,7 +45,7 @@ const PanelEdit = () => { 'Select a namespace and key to edit its values' ) - const [updateKey, { loading }] = useDataMutation( + const [updateKey, { loading: mutationLoading }] = useDataMutation( // @ts-expect-error("") modifyKeyMutation({ store }), { @@ -61,9 +62,11 @@ const PanelEdit = () => { const handleEditorChange = (value) => { setValue(value) + // setUpdateError(null) } const handleUpdate = async () => { + // setUpdateError(null) try { await updateKey({ key, @@ -71,6 +74,7 @@ const PanelEdit = () => { value, }) } catch (error) { + // setUpdateError(error.message) const message = i18n.t('There was an error updating the key') showError(message) } @@ -85,7 +89,7 @@ const PanelEdit = () => { }, [key, namespace, store, refetch]) if (error) { - return + return } const loadingText = `${i18n.t('Loading')}...` @@ -118,7 +122,7 @@ const PanelEdit = () => { title="Save" primary small - loading={loading} + loading={mutationLoading} > {i18n.t('Save changes')} @@ -132,4 +136,4 @@ const PanelEdit = () => { ) } -export default PanelEdit +export default EditPanel diff --git a/src/components/panel/KeysPanel.tsx b/src/components/panels/KeysPanel.tsx similarity index 93% rename from src/components/panel/KeysPanel.tsx rename to src/components/panels/KeysPanel.tsx index 01387a2..726e5f9 100644 --- a/src/components/panel/KeysPanel.tsx +++ b/src/components/panels/KeysPanel.tsx @@ -1,8 +1,8 @@ -import { useDataQuery } from '@dhis2/app-service-data' +import { useDataQuery } from '@dhis2/app-runtime' import React, { useEffect } from 'react' import { useParams } from 'react-router-dom' -import { PanelHeader } from './PanelHeader' -import SidebarPanel from './sidepanel/SidePanel' +import { PanelHeader } from '../sidepanel/PanelHeader' +import SidePanel from '../sidepanel/SidePanel' interface QueryResults { results: [] @@ -44,7 +44,7 @@ const KeysPanel = () => { }, [store]) return ( - { }, [store]) return ( - { }, [store]) return ( - { }, [store]) return ( - { - return ( -
    - - - - -
    - ) -} - -DataStoreSelect.propTypes = { - handleChange: PropTypes.func, - option: PropTypes.string, -} - -export default DataStoreSelect diff --git a/src/components/sidebar/SidebarNavLink.tsx b/src/components/sidebar/SidebarNavLink.tsx deleted file mode 100644 index 10e2a83..0000000 --- a/src/components/sidebar/SidebarNavLink.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Button } from '@dhis2/ui' -import { IconDelete16 } from '@dhis2/ui-icons' -import PropTypes from 'prop-types' -import React from 'react' -import { NavLink } from 'react-router-dom' -import classes from '../../App.module.css' - -const SidebarNavLink = ({ to, label, handleDeleteModal }) => { - return ( -
  • - - isActive ? 'active' : isPending ? 'pending' : '' - } - > - {label} - -
  • - ) -} - -SidebarNavLink.propTypes = { - handleDeleteModal: PropTypes.func, - label: PropTypes.string, - to: PropTypes.string, -} - -export default SidebarNavLink diff --git a/src/components/sidebar/searchField.tsx b/src/components/sidebar/searchField.tsx deleted file mode 100644 index c2a0cf4..0000000 --- a/src/components/sidebar/searchField.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { InputField } from '@dhis2/ui' -import React from 'react' -import classes from '../../App.module.css' -import i18n from '../../locales' - -const SearchField = () => { - return ( -
    - -
    - ) -} - -export default SearchField diff --git a/src/components/sidebar/sidebar.tsx b/src/components/sidebar/sidebar.tsx deleted file mode 100644 index 9487089..0000000 --- a/src/components/sidebar/sidebar.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { useDataQuery } from '@dhis2/app-service-data' -import { Card, Divider } from '@dhis2/ui' -import React, { useEffect, useState } from 'react' -import { useNavigate, useParams } from 'react-router-dom' -import classes from '../../App.module.css' -import LinksList from '../namespaces/LinksList' -import DataStoreSelect from './DataStoreSelect' -// import SearchField from './SearchField' - -interface QueryResults { - results: [] -} - -const userDataStoreQuery = { - results: { - resource: 'userDataStore', - }, -} - -const dataStoreQuery = { - results: { - resource: 'dataStore', - }, -} - -const Sidebar = () => { - const navigate = useNavigate() - const { store } = useParams() - const [option, setOption] = useState(store || '') - - const { - error: dataStoreQueryError, - loading: dataStoreQueryLoading, - data: dataStoreQueryData, - refetch: refetchDataStore, - } = useDataQuery(dataStoreQuery) - - const { - error: userDataStoreQueryError, - loading: userDataStoreQueryLoading, - data: userDataStoreQueryData, - refetch: refetchUserDataStore, - } = useDataQuery(userDataStoreQuery) - - useEffect(() => { - const storeOptions = ['dataStore', 'userDataStore'] - if (!storeOptions.includes(store)) { - navigate('/dataStore') - } else { - setOption(store) - } - }, [store, navigate]) - - const handleDataStoreSelect = ({ selected }) => { - setOption(selected) - navigate(`/${selected}`) - } - return ( - -
    - -
    - - {store && ( - <> - {/* */} - {store === 'userDataStore' && ( - - )} - {store === 'dataStore' && ( - - )} - - )} -
    - ) -} - -export default Sidebar diff --git a/src/components/panel/sidepanel/CreateButton.tsx b/src/components/sidepanel/CreateButton.tsx similarity index 68% rename from src/components/panel/sidepanel/CreateButton.tsx rename to src/components/sidepanel/CreateButton.tsx index 67cf2e9..071bfd3 100644 --- a/src/components/panel/sidepanel/CreateButton.tsx +++ b/src/components/sidepanel/CreateButton.tsx @@ -1,16 +1,21 @@ import { Button } from '@dhis2/ui' import { IconAdd16 } from '@dhis2/ui-icons' import React from 'react' -import i18n from '../../../locales' +import i18n from '../../locales' import classes from '../Panel.module.css' -const CreateButton = ({ label, handleClick }) => { +type CreateButtonProps = { + label: string + handleClick: () => void +} + +const CreateButton = ({ label, handleClick }: CreateButtonProps) => { return (
    + + + + + ) +} +export default DeleteModal diff --git a/src/components/panels/EditPanel.tsx b/src/components/panels/EditPanel.tsx index 741ee0d..4156b58 100644 --- a/src/components/panels/EditPanel.tsx +++ b/src/components/panels/EditPanel.tsx @@ -75,6 +75,7 @@ const EditPanel = () => { }) } catch (error) { // setUpdateError(error.message) + console.error(error.message) const message = i18n.t('There was an error updating the key') showError(message) } diff --git a/src/components/sidepanel/ContextButton.tsx b/src/components/sidepanel/ContextButton.tsx new file mode 100644 index 0000000..4d9603a --- /dev/null +++ b/src/components/sidepanel/ContextButton.tsx @@ -0,0 +1,62 @@ +import { Button, IconMore16, Popover, IconDelete16 } from '@dhis2/ui' +import React, { useRef } from 'react' +import { useSidePanelContext } from '../../context/SidePanelContext' +import i18n from '../../locales' +import classes from '../Panel.module.css' + +type ContextMenuButtonProps = { + handleContextMenu: () => void + openContextMenu: boolean + setOpenContextMenu: (boolean) => void +} + +const ContextMenuButton = ({ + handleContextMenu, + openContextMenu, + setOpenContextMenu, +}: ContextMenuButtonProps) => { + const ref = useRef(null) + const { setOpenDeleteModal } = useSidePanelContext() + + return ( +
    + +
    + + )} +
    + ) +} + +export default ContextMenuButton diff --git a/src/components/sidepanel/CreateButton.tsx b/src/components/sidepanel/CreateButton.tsx index 071bfd3..6736dbd 100644 --- a/src/components/sidepanel/CreateButton.tsx +++ b/src/components/sidepanel/CreateButton.tsx @@ -1,15 +1,18 @@ import { Button } from '@dhis2/ui' import { IconAdd16 } from '@dhis2/ui-icons' import React from 'react' +import { useSidePanelContext } from '../../context/SidePanelContext' import i18n from '../../locales' import classes from '../Panel.module.css' type CreateButtonProps = { - label: string handleClick: () => void } -const CreateButton = ({ label, handleClick }: CreateButtonProps) => { +const CreateButton = ({ handleClick }: CreateButtonProps) => { + const { panelType: type } = useSidePanelContext() + const label = + type === 'namespace' ? i18n.t('New namespace') : i18n.t('New key') return (