Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: delete namespaces and keys #140

Open
wants to merge 5 commits into
base: DHIS2-18531/create-namespaces-and-keys
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -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-19T16:36:13.574Z\n"
"PO-Revision-Date: 2024-12-19T16:36:13.575Z\n"
"POT-Creation-Date: 2024-12-19T22:29:04.401Z\n"
"PO-Revision-Date: 2024-12-19T22:29:04.402Z\n"

msgid "An error has occurred"
msgstr "An error has occurred"
Expand All @@ -26,6 +26,9 @@ msgstr "Cancel"
msgid "Add"
msgstr "Add"

msgid "Delete"
msgstr "Delete"

msgid "Key"
msgstr "Key"

Expand Down Expand Up @@ -56,6 +59,18 @@ msgstr "DataStore"
msgid "UserDataStore"
msgstr "UserDataStore"

msgid "Key '{{key}}' added successfully"
msgstr "Key '{{key}}' added successfully"

msgid "There was a problem adding this key - {{error}}"
msgstr "There was a problem adding this key - {{error}}"

msgid "Key '{{selectedKey}}' deleted successfully!"
msgstr "Key '{{selectedKey}}' deleted successfully!"

msgid "There was a problem deleting this key - {{error}}"
msgstr "There was a problem deleting this key - {{error}}"

msgid "keys"
msgstr "keys"

Expand All @@ -68,6 +83,21 @@ msgstr "Search keys"
msgid "Add New Key"
msgstr "Add New Key"

msgid "Delete Key"
msgstr "Delete Key"

msgid "Namespace '{{namespace}}' and key '{{key}}' added successfully!"
msgstr "Namespace '{{namespace}}' and key '{{key}}' added successfully!"

msgid "There was a problem adding this namespace - {{error}}"
msgstr "There was a problem adding this namespace - {{error}}"

msgid "Namespace '{{namespace}}' deleted successfully!"
msgstr "Namespace '{{namespace}}' deleted successfully!"

msgid "There was a problem deleting this namespace - {{error}}"
msgstr "There was a problem deleting this namespace - {{error}}"

msgid "Search namespaces"
msgstr "Search namespaces"

Expand All @@ -77,12 +107,15 @@ msgstr "New Namespace"
msgid "Add New Namespace"
msgstr "Add New Namespace"

msgid "Delete Namespace"
msgstr "Delete Namespace"

msgid "This will delete all the keys in this namespace"
msgstr "This will delete all the keys in this namespace"

msgid "Search"
msgstr "Search"

msgid "Delete"
msgstr "Delete"

msgid "Actions"
msgstr "Actions"

Expand Down
43 changes: 43 additions & 0 deletions src/components/modals/DeleteModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {
Modal,
ModalContent,
ModalActions,
ModalTitle,
Button,
ButtonStrip,
} from '@dhis2/ui'
import React from 'react'
import i18n from '../../locales'

type DeleteModalProps = {
closeModal: () => void
handleDelete: () => void
children: React.ReactNode
title: string
}

const DeleteModal = ({
children,
handleDelete,
closeModal,
title,
}: DeleteModalProps) => {
return (
<Modal position="middle">
<ModalTitle>{title}</ModalTitle>
<ModalContent>{children}</ModalContent>
<ModalActions>
<ButtonStrip end>
<Button secondary onClick={closeModal}>
{i18n.t('Cancel')}
</Button>
<Button destructive onClick={() => handleDelete()}>
{i18n.t('Delete')}
</Button>
</ButtonStrip>
</ModalActions>
</Modal>
)
}

export default DeleteModal
85 changes: 81 additions & 4 deletions src/components/sections/KeysDataSection.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { useDataEngine, useDataQuery } from '@dhis2/app-runtime'
import { IconAdd16, colors } from '@dhis2/ui'
import React, { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
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 PanelHeader from '../header/PanelHeader'
import CenteredLoader from '../loader/Loader'
import CreateModal from '../modals/CreateModal'
import DeleteModal from '../modals/DeleteModal'
import { KeysField } from '../modals/Fields'
import ItemsTable from '../table/ItemsTable'
import CreateButton from './CreateButton'
Expand All @@ -20,12 +21,15 @@ interface QueryResults {

const KeysDataSection = ({ query }) => {
const engine = useDataEngine()
const navigate = useNavigate()
const { store, namespace: currentNamespace } = useParams()

const [openCreateModal, setOpenCreateModal] = useState(false)

const { showError, showSuccess } = useCustomAlert()

const [openCreateModal, setOpenCreateModal] = useState(false)
const [openDeleteModal, setOpenDeleteModal] = useState(false)
const [selectedKey, setSelectedKey] = useState(null)

const { error, loading, data, refetch } = useDataQuery<QueryResults>(
query,
{
Expand All @@ -35,6 +39,8 @@ const KeysDataSection = ({ query }) => {
}
)

const numberOfKeysInNamespace = data?.results?.length

const handleCreate = async ({ key }) => {
await engine.mutate(
{
Expand Down Expand Up @@ -67,6 +73,52 @@ const KeysDataSection = ({ query }) => {
)
}

const handleDelete = async () => {
const namespaceHasMultipleKeys = numberOfKeysInNamespace > 1
const resource = namespaceHasMultipleKeys
? `${store}/${currentNamespace}`
: `${store}`
const id = namespaceHasMultipleKeys ? selectedKey : currentNamespace

const onComplete = () => {
setOpenDeleteModal(false)
showSuccess(
i18n.t("Key '{{selectedKey}}' deleted successfully!", {
selectedKey,
})
)
const navigatePath = namespaceHasMultipleKeys
? `/${store}/edit/${currentNamespace}`
: `/${store}`
navigate(navigatePath)

if (namespaceHasMultipleKeys) {
refetch({ id: currentNamespace })
}
}

const onError = (error) => {
showError(
i18n.t('There was a problem deleting this key - {{error}}', {
error: error.message,
interpolation: { escapeValue: false },
})
)
}

await engine.mutate(
{
type: 'delete' as const,
resource: resource,
id: id,
},
{
onComplete,
onError,
}
)
}

useEffect(() => {
refetch({ id: currentNamespace })
}, [currentNamespace])
Expand Down Expand Up @@ -95,7 +147,14 @@ const KeysDataSection = ({ query }) => {
<SearchField placeholder={i18n.t('Search keys')} />
</div>
<div>
{data && <ItemsTable data={data} label={i18n.t('Key')} />}
{data && (
<ItemsTable
data={data}
label={i18n.t('Key')}
setOpenDeleteModal={setOpenDeleteModal}
setSelectedItem={setSelectedKey}
/>
)}
</div>
{openCreateModal && (
<CreateModal
Expand All @@ -106,6 +165,24 @@ const KeysDataSection = ({ query }) => {
<KeysField initialFocus />
</CreateModal>
)}
{openDeleteModal && (
<DeleteModal
closeModal={() => setOpenDeleteModal(false)}
handleDelete={handleDelete}
title={i18n.t('Delete Key')}
>
{i18n.t(
`Are you sure you want to delete '${selectedKey}' in ${currentNamespace}?`
)}
{numberOfKeysInNamespace < 2 && (
<p>
{i18n.t(
`This will also delete the namespace '${currentNamespace}'`
)}
</p>
)}
</DeleteModal>
)}
</>
)
}
Expand Down
68 changes: 66 additions & 2 deletions src/components/sections/NamespaceDataSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import i18n from '../../locales'
import ErrorNotice from '../error/ErrorNotice'
import CenteredLoader from '../loader/Loader'
import CreateModal from '../modals/CreateModal'
import DeleteModal from '../modals/DeleteModal'
import { KeysField, NamespaceField } from '../modals/Fields'
import ItemsTable from '../table/ItemsTable'
import CreateButton from './CreateButton'
Expand All @@ -21,10 +22,13 @@ const NamespaceDataSection = ({ query }) => {
const engine = useDataEngine()
const navigate = useNavigate()
const { store } = useParams()
const [openCreateModal, setOpenCreateModal] = useState(false)

const { showError, showSuccess } = useCustomAlert()

const [openCreateModal, setOpenCreateModal] = useState(false)
const [openDeleteModal, setOpenDeleteModal] = useState(false)
const [selectedNamespace, setSelectedNamespace] = useState(null)

const { error, loading, data, refetch } = useDataQuery<QueryResults>(query)

const handleCreate = async (values) => {
Expand Down Expand Up @@ -64,6 +68,41 @@ const NamespaceDataSection = ({ query }) => {
)
}

const handleDelete = async () => {
await engine.mutate(
{
type: 'delete' as const,
resource: `${store}`,
id: selectedNamespace,
},
{
onComplete: () => {
setOpenDeleteModal(false)
refetch()
showSuccess(
i18n.t(
"Namespace '{{namespace}}' deleted successfully!",
{
namespace: selectedNamespace,
}
)
)
},
onError(error) {
showError(
i18n.t(
'There was a problem deleting this namespace - {{error}}',
{
error: error.message,
interpolation: { escapeValue: false },
}
)
)
},
}
)
}

if (error) {
return <ErrorNotice />
}
Expand All @@ -83,7 +122,14 @@ const NamespaceDataSection = ({ query }) => {
/>
</div>
<div>
{data && <ItemsTable data={data} label={i18n.t('Namespace')} />}
{data && (
<ItemsTable
data={data}
label={i18n.t('Namespace')}
setOpenDeleteModal={setOpenDeleteModal}
setSelectedItem={setSelectedNamespace}
/>
)}
</div>
{openCreateModal && (
<CreateModal
Expand All @@ -95,6 +141,24 @@ const NamespaceDataSection = ({ query }) => {
<KeysField />
</CreateModal>
)}
{openDeleteModal && (
<DeleteModal
closeModal={() => setOpenDeleteModal(false)}
handleDelete={handleDelete}
title={i18n.t('Delete Namespace')}
>
<p>
{i18n.t(
`Are you sure you want to delete '${selectedNamespace}'?`
)}
</p>
<p>
{i18n.t(
`This will delete all the keys in this namespace`
)}
</p>
</DeleteModal>
)}
</>
)
}
Expand Down
10 changes: 8 additions & 2 deletions src/components/table/DeleteAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import { Button } from '@dhis2-ui/button'
import React from 'react'
import i18n from '../../locales'

export default function DeleteAction() {
interface DeleteActionProps {
handleDeleteBtnClick: () => void
}

export default function DeleteAction({
handleDeleteBtnClick,
}: DeleteActionProps) {
return (
<Button
aria-label={i18n.t('Delete')}
icon={<IconDelete16 />}
name="delete"
onClick={() => console.log('delete item')}
onClick={handleDeleteBtnClick}
title={i18n.t('Delete')}
/>
)
Expand Down
Loading
Loading