diff --git a/i18n/en.pot b/i18n/en.pot index 2dc9dcc..bc65235 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,27 +5,39 @@ 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-18T09:41:03.249Z\n" -"PO-Revision-Date: 2024-12-18T09:41:03.250Z\n" +"POT-Creation-Date: 2024-12-19T16:36:13.574Z\n" +"PO-Revision-Date: 2024-12-19T16:36:13.575Z\n" msgid "An error has occurred" msgstr "An error has occurred" +msgid "404 Page Not Found" +msgstr "404 Page Not Found" + msgid "Back to datastore" msgstr "Back to datastore" -msgid "Back to all namespaces" -msgstr "Back to all namespaces" +msgid "An error has occurred. Try again" +msgstr "An error has occurred. Try again" -msgid "Search namespaces" -msgstr "Search namespaces" +msgid "Cancel" +msgstr "Cancel" -msgid "New Namespace" -msgstr "New Namespace" +msgid "Add" +msgstr "Add" + +msgid "Key" +msgstr "Key" msgid "Namespace" msgstr "Namespace" +msgid "Back to all namespaces" +msgstr "Back to all namespaces" + +msgid "Configure Namespaces" +msgstr "Configure Namespaces" + msgid "Close" msgstr "Close" @@ -38,8 +50,14 @@ msgstr "Save changes" msgid "Choose a key to start editing" msgstr "Choose a key to start editing" -msgid "Keys" -msgstr "Keys" +msgid "DataStore" +msgstr "DataStore" + +msgid "UserDataStore" +msgstr "UserDataStore" + +msgid "keys" +msgstr "keys" msgid "New Key" msgstr "New Key" @@ -47,14 +65,17 @@ msgstr "New Key" msgid "Search keys" msgstr "Search keys" -msgid "Key" -msgstr "Key" +msgid "Add New Key" +msgstr "Add New Key" -msgid "DataStore" -msgstr "DataStore" +msgid "Search namespaces" +msgstr "Search namespaces" -msgid "UserDataStore" -msgstr "UserDataStore" +msgid "New Namespace" +msgstr "New Namespace" + +msgid "Add New Namespace" +msgstr "Add New Namespace" msgid "Search" msgstr "Search" diff --git a/src/components/modals/CreateModal.tsx b/src/components/modals/CreateModal.tsx new file mode 100644 index 0000000..b0ddb2e --- /dev/null +++ b/src/components/modals/CreateModal.tsx @@ -0,0 +1,61 @@ +import { + Modal, + ModalTitle, + ModalContent, + ModalActions, + Button, + ButtonStrip, + ReactFinalForm, +} from '@dhis2/ui' +import React from 'react' +import i18n from '../../locales' + +const { Form } = ReactFinalForm + +interface FieldValues { + key: string + namespace?: string +} + +interface CreateModalProps { + closeModal: () => void + handleCreate: ({ key, namespace }: FieldValues) => void + children: React.ReactNode + title: string +} + +const CreateModal = ({ + handleCreate, + closeModal, + children, + title, +}: CreateModalProps) => { + const onSubmit = (values) => { + handleCreate(values) + } + + return ( + +
+ {({ handleSubmit }) => ( + + {title} + {children} + + + + + + +
+ )} + +
+ ) +} + +export default CreateModal diff --git a/src/components/modals/Fields.tsx b/src/components/modals/Fields.tsx new file mode 100644 index 0000000..80a8873 --- /dev/null +++ b/src/components/modals/Fields.tsx @@ -0,0 +1,41 @@ +import { + ReactFinalForm, + InputFieldFF, + hasValue, + composeValidators, + alphaNumeric, +} from '@dhis2/ui' +import React from 'react' +import i18n from '../../locales' + +const { Field } = ReactFinalForm + +export const KeysField = ({ initialFocus }: { initialFocus?: boolean }) => { + return ( + + ) +} + +export const NamespaceField = ({ + initialFocus, +}: { + initialFocus?: boolean +}) => { + return ( + + ) +} diff --git a/src/components/pages/Namespaces.tsx b/src/components/pages/Namespaces.tsx index a7494bb..c1ec27d 100644 --- a/src/components/pages/Namespaces.tsx +++ b/src/components/pages/Namespaces.tsx @@ -18,11 +18,6 @@ const dataStoreNamespacesQuery = { }, } -export type FieldValues = { - namespace?: string - key?: string -} - const NamespacesPage = () => { const navigate = useNavigate() const { store } = useParams() diff --git a/src/components/sections/KeysDataSection.tsx b/src/components/sections/KeysDataSection.tsx index 0de43c6..a05a934 100644 --- a/src/components/sections/KeysDataSection.tsx +++ b/src/components/sections/KeysDataSection.tsx @@ -1,12 +1,15 @@ -import { useDataQuery } from '@dhis2/app-runtime' +import { useDataEngine, useDataQuery } from '@dhis2/app-runtime' import { IconAdd16, colors } from '@dhis2/ui' -import React, { useEffect } from 'react' +import React, { useEffect, useState } from 'react' import { useParams } from 'react-router-dom' import classes from '../../App.module.css' +import useCustomAlert from '../../hooks/useCustomAlert' import i18n from '../../locales' import ErrorNotice from '../error/ErrorNotice' import PanelHeader from '../header/PanelHeader' import CenteredLoader from '../loader/Loader' +import CreateModal from '../modals/CreateModal' +import { KeysField } from '../modals/Fields' import ItemsTable from '../table/ItemsTable' import CreateButton from './CreateButton' import SearchField from './SearchField' @@ -16,7 +19,12 @@ interface QueryResults { } const KeysDataSection = ({ query }) => { - const { namespace: currentNamespace } = useParams() + const engine = useDataEngine() + const { store, namespace: currentNamespace } = useParams() + + const [openCreateModal, setOpenCreateModal] = useState(false) + + const { showError, showSuccess } = useCustomAlert() const { error, loading, data, refetch } = useDataQuery( query, @@ -27,6 +35,38 @@ const KeysDataSection = ({ query }) => { } ) + const handleCreate = async ({ key }) => { + await engine.mutate( + { + type: 'create', + resource: `${store}/${currentNamespace}/${key}`, + data: () => ({}), + }, + { + onComplete() { + setOpenCreateModal(false) + showSuccess( + i18n.t("Key '{{key}}' added successfully", { + key, + }) + ) + refetch({ id: currentNamespace }) + }, + onError(error) { + showError( + i18n.t( + 'There was a problem adding this key - {{error}}', + { + error: error.message, + interpolation: { escapeValue: false }, + } + ) + ) + }, + } + ) + } + useEffect(() => { refetch({ id: currentNamespace }) }, [currentNamespace]) @@ -47,7 +87,7 @@ const KeysDataSection = ({ query }) => { console.log('create new key')} + handleClick={() => setOpenCreateModal(true)} icon={} /> @@ -57,6 +97,15 @@ const KeysDataSection = ({ query }) => {
{data && }
+ {openCreateModal && ( + setOpenCreateModal(false)} + handleCreate={handleCreate} + > + + + )} ) } diff --git a/src/components/sections/NamespaceDataSection.tsx b/src/components/sections/NamespaceDataSection.tsx index 56eed5d..34a6a4d 100644 --- a/src/components/sections/NamespaceDataSection.tsx +++ b/src/components/sections/NamespaceDataSection.tsx @@ -1,10 +1,14 @@ -import { useDataQuery } from '@dhis2/app-runtime' +import { useDataEngine, useDataQuery } from '@dhis2/app-runtime' import { IconAdd24, colors } from '@dhis2/ui' -import React from 'react' +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 ErrorNotice from '../error/ErrorNotice' import CenteredLoader from '../loader/Loader' +import CreateModal from '../modals/CreateModal' +import { KeysField, NamespaceField } from '../modals/Fields' import ItemsTable from '../table/ItemsTable' import CreateButton from './CreateButton' import SearchField from './SearchField' @@ -14,7 +18,51 @@ interface QueryResults { } const NamespaceDataSection = ({ query }) => { - const { error, loading, data } = useDataQuery(query) + const engine = useDataEngine() + const navigate = useNavigate() + const { store } = useParams() + const [openCreateModal, setOpenCreateModal] = useState(false) + + const { showError, showSuccess } = useCustomAlert() + + const { error, loading, data, refetch } = useDataQuery(query) + + const handleCreate = async (values) => { + await engine.mutate( + { + type: 'create', + resource: `${store}/${values?.namespace}/${values?.key}`, + data: () => ({}), + }, + { + onComplete() { + showSuccess( + i18n.t( + "Namespace '{{namespace}}' and key '{{key}}' added successfully!", + { + namespace: values.namespace, + key: values.key, + } + ) + ) + refetch() + navigate(`edit/${values?.namespace}`) + setOpenCreateModal(false) + }, + onError(error) { + showError( + i18n.t( + 'There was a problem adding this namespace - {{error}}', + { + error: error.message, + interpolation: { escapeValue: false }, + } + ) + ) + }, + } + ) + } if (error) { return @@ -30,13 +78,23 @@ const NamespaceDataSection = ({ query }) => { console.log('create new namespace')} + handleClick={() => setOpenCreateModal(true)} icon={} />
{data && }
+ {openCreateModal && ( + setOpenCreateModal(false)} + handleCreate={handleCreate} + > + + + + )} ) } diff --git a/src/hooks/useCustomAlert.tsx b/src/hooks/useCustomAlert.tsx new file mode 100644 index 0000000..4b01b94 --- /dev/null +++ b/src/hooks/useCustomAlert.tsx @@ -0,0 +1,15 @@ +import { useAlert } from '@dhis2/app-runtime' + +const useCustomAlert = () => { + const { show } = useAlert( + ({ message }) => message, + ({ isError }) => + isError ? { critical: true } : { success: true, duration: 3000 } + ) + return { + showSuccess: (message) => show({ message }), + showError: (message) => show({ message, isError: true }), + } +} + +export default useCustomAlert