From 37b288f8457fc2f9f6d84fe843ecfd4a18ff35e8 Mon Sep 17 00:00:00 2001 From: Gift Nnko Date: Tue, 1 Oct 2024 14:07:47 +0300 Subject: [PATCH] feat: migration Added migration routing in the scorecard list page --- .idea/vcs.xml | 6 +++ packages/app/i18n/en.pot | 7 +++- packages/app/src/locales/en/translations.json | 1 + .../components/EmptyScoreCardList/index.tsx | 10 ++--- .../app/src/modules/ScorecardList/index.tsx | 10 +++-- .../components/MigrationNavigateButton.tsx | 40 ++++++++++++++++++ .../components/OldScorecardList.tsx | 41 ++++++++++++++++--- .../modules/ScorecardMigration/hooks/data.ts | 11 ++++- .../hooks/useMigrateScorecard.ts | 12 +++--- .../src/modules/ScorecardMigration/index.tsx | 9 +++- 10 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 packages/app/src/modules/ScorecardMigration/components/MigrationNavigateButton.tsx diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7f4..4c6280eb4 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,5 +1,11 @@ + + + + + + diff --git a/packages/app/i18n/en.pot b/packages/app/i18n/en.pot index ab7f3a1e6..8fe00b1eb 100644 --- a/packages/app/i18n/en.pot +++ b/packages/app/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-09-30T13:38:08.282Z\n" -"PO-Revision-Date: 2024-09-30T13:38:08.282Z\n" +"POT-Creation-Date: 2024-10-01T09:23:10.631Z\n" +"PO-Revision-Date: 2024-10-01T09:23:10.631Z\n" msgid "Scorecard deleted successfully" msgstr "Scorecard deleted successfully" @@ -461,6 +461,9 @@ msgstr "A scorecard needs at least one data group" msgid "You must select at least one organisation unit" msgstr "You must select at least one organisation unit" +msgid "{{count}} scorecards successfully migrated" +msgstr "{{count}} scorecards successfully migrated" + msgid "Migrating scorecard(s)... ({{progress}}/{{count}})" msgid_plural "Migrating scorecard(s)... ({{progress}}/{{count}})" msgstr[0] "Migrating scorecard(s)... ({{progress}}/{{count}})" diff --git a/packages/app/src/locales/en/translations.json b/packages/app/src/locales/en/translations.json index 13b343788..630f5624d 100644 --- a/packages/app/src/locales/en/translations.json +++ b/packages/app/src/locales/en/translations.json @@ -144,6 +144,7 @@ "A data group must have at least one data item": "A data group must have at least one data item", "A scorecard needs at least one data group": "A scorecard needs at least one data group", "You must select at least one organisation unit": "You must select at least one organisation unit", + "{{count}} scorecards successfully migrated": "{{count}} scorecards successfully migrated", "Migrating scorecard(s)... ({{progress}}/{{count}})": "Migrating scorecard(s)... ({{progress}}/{{count}})", "Migrating scorecard(s)... ({{progress}}/{{count}})_plural": "Migrating scorecard(s)... ({{progress}}/{{count}})", "Migrate {{count}} scorecard(s)": "Migrate {{count}} scorecard(s)", diff --git a/packages/app/src/modules/ScorecardList/components/EmptyScoreCardList/index.tsx b/packages/app/src/modules/ScorecardList/components/EmptyScoreCardList/index.tsx index 90d7a2526..e66d5726c 100644 --- a/packages/app/src/modules/ScorecardList/components/EmptyScoreCardList/index.tsx +++ b/packages/app/src/modules/ScorecardList/components/EmptyScoreCardList/index.tsx @@ -15,18 +15,18 @@ export default function EmptyScoreCardList() {
- +

{i18n.t( - "Create a scorecard instantly, over tea break", + "Create a scorecard instantly, over tea break" )} ...

diff --git a/packages/app/src/modules/ScorecardList/index.tsx b/packages/app/src/modules/ScorecardList/index.tsx index 9c89efddd..f498d5970 100644 --- a/packages/app/src/modules/ScorecardList/index.tsx +++ b/packages/app/src/modules/ScorecardList/index.tsx @@ -11,10 +11,9 @@ import { useAlert } from "@dhis2/app-runtime"; import { useNavigate } from "react-router-dom"; import { ScorecardListArea } from "./components/ScorecardListArea"; import { ErrorBoundary } from "react-error-boundary"; -import { useAutoMigration } from "../ScorecardMigration/hooks/autoMigration"; +import { MigrationNavigateButton } from "../ScorecardMigration/components/MigrationNavigateButton"; export default function ScorecardList() { - useAutoMigration(); const [scorecardViewType, { set }] = useSetting("scorecardViewType"); const [helpEnabled, setHelpEnabled] = useState(false); const { show } = useAlert( @@ -54,8 +53,8 @@ export default function ScorecardList() { onExit={onHelpExit} initialStep={0} /> -
-
+
+
+
+ +
); diff --git a/packages/app/src/modules/ScorecardMigration/components/MigrationNavigateButton.tsx b/packages/app/src/modules/ScorecardMigration/components/MigrationNavigateButton.tsx new file mode 100644 index 000000000..cac6f5bf4 --- /dev/null +++ b/packages/app/src/modules/ScorecardMigration/components/MigrationNavigateButton.tsx @@ -0,0 +1,40 @@ +import { CircularLoader } from "@dhis2/ui"; +import i18n from "@dhis2/d2-i18n"; +import { DATASTORE_OLD_SCORECARD_ENDPOINT } from "@scorecard/shared"; +import { useDataQuery } from "@dhis2/app-runtime"; +import { isEmpty } from "lodash"; +import { Link } from "react-router-dom"; + + +const query = { + data: { + resource: `${DATASTORE_OLD_SCORECARD_ENDPOINT}` + } +}; + +type Response = { + data: string[] +} + +export function MigrationNavigateButton() { + const { data, loading } = useDataQuery(query); + + if (loading) { + return ( + + ); + } + + if (data && !isEmpty(data)) { + return ( + + {i18n.t("Migrate scorecards from v1")} + + ); + } + + + return null; +} diff --git a/packages/app/src/modules/ScorecardMigration/components/OldScorecardList.tsx b/packages/app/src/modules/ScorecardMigration/components/OldScorecardList.tsx index 61a4fb751..26ca79644 100644 --- a/packages/app/src/modules/ScorecardMigration/components/OldScorecardList.tsx +++ b/packages/app/src/modules/ScorecardMigration/components/OldScorecardList.tsx @@ -1,10 +1,10 @@ import { useOldScorecards } from "../hooks/data"; import { FullPageError } from "@scorecard/shared"; -import { CircularLoader } from "@dhis2/ui"; +import { CircularLoader, Tag } from "@dhis2/ui"; import { SimpleDataTable, SimpleDataTableColumn } from "@hisptz/dhis2-ui"; import i18n from "@dhis2/d2-i18n"; -import { useMemo, useState } from "react"; -import { uniq } from "lodash"; +import { useEffect, useMemo, useState } from "react"; +import { fromPairs, get, uniq } from "lodash"; import { MigrateButton } from "./MigrateButton"; @@ -16,15 +16,20 @@ const columns: SimpleDataTableColumn[] = [ { key: "description", label: i18n.t("Description") + }, + { + key: "status", + label: i18n.t("Status") } ]; export function OldScorecardList() { - const { loading, scorecards, error, refetch } = useOldScorecards(); + const { loading, scorecards, error, refetch, existingScorecards } = useOldScorecards(); const [selectedConfig, setSelectedConfig] = useState([]); const [progress, setProgress] = useState>({}); + const onRemove = (values: string[]) => { setSelectedConfig((prevState) => { return prevState.filter((value) => !values.includes(value)); @@ -35,15 +40,39 @@ export function OldScorecardList() { setSelectedConfig((prevState) => uniq([...prevState, ...values])); }; + const getStatus = (status?: "SUCCESS" | "EXISTS" | "FAILED") => { + switch (status) { + case "SUCCESS": + return {i18n.t("Success")}; + case "EXISTS": + return {i18n.t("Migrated")}; + case "FAILED": + return {i18n.t("Failed")}; + default: + return ""; + } + }; + const rows = useMemo(() => scorecards?.map((config) => { return { id: config.id, title: config.header.title, - description: config.header.description + description: config.header.description, + status: getStatus(get(progress, config.id)), + cellsStyle: { + bordered: true, + selectable: get(progress, config.id) === "EXISTS" + } }; }) ?? [], [scorecards]); + useEffect(() => { + if (existingScorecards) { + setProgress(fromPairs(existingScorecards.map((id) => ([id, "EXISTS"])))); + } + }, [existingScorecards]); + if (loading) { return
@@ -60,7 +89,7 @@ export function OldScorecardList() { return (
- +
{ !!scorecards && ( setSelectedConfig([])} progress={progress} onProgressUpdate={setProgress} selected={selectedConfig} scorecards={scorecards!} />) diff --git a/packages/app/src/modules/ScorecardMigration/hooks/data.ts b/packages/app/src/modules/ScorecardMigration/hooks/data.ts index 87f060ca8..0ad0ec50b 100644 --- a/packages/app/src/modules/ScorecardMigration/hooks/data.ts +++ b/packages/app/src/modules/ScorecardMigration/hooks/data.ts @@ -1,4 +1,4 @@ -import { DATASTORE_OLD_SCORECARD_ENDPOINT } from "@scorecard/shared"; +import { DATASTORE_NAMESPACE, DATASTORE_OLD_SCORECARD_ENDPOINT } from "@scorecard/shared"; import { OldScorecardSchema } from "../schemas/old"; import { useDataQuery } from "@dhis2/app-runtime"; import { Pager } from "@hisptz/dhis2-ui"; @@ -11,6 +11,9 @@ const query = { fields: ".", paging: false } + }, + newConfig: { + resource: `dataStore/${DATASTORE_NAMESPACE}` } }; @@ -21,7 +24,8 @@ type Response = { value: OldScorecardSchema }>, pager: Pager - } + }, + newConfig: string[] } export function useOldScorecards() { @@ -32,8 +36,11 @@ export function useOldScorecards() { id: key })); + const existingScorecards = data?.newConfig ?? []; + return { scorecards, + existingScorecards, loading, error, refetch diff --git a/packages/app/src/modules/ScorecardMigration/hooks/useMigrateScorecard.ts b/packages/app/src/modules/ScorecardMigration/hooks/useMigrateScorecard.ts index 7be5e07f1..6d9dd6478 100644 --- a/packages/app/src/modules/ScorecardMigration/hooks/useMigrateScorecard.ts +++ b/packages/app/src/modules/ScorecardMigration/hooks/useMigrateScorecard.ts @@ -1,6 +1,6 @@ import { useCallback } from "react"; import { OldScorecardSchema } from "../schemas/old"; -import { FetchError, useDataEngine, useDataQuery } from "@dhis2/app-runtime"; +import { FetchError, useDataEngine } from "@dhis2/app-runtime"; import { DATASTORE_NAMESPACE, migrateScorecard } from "@scorecard/shared"; import { useSaveScorecard } from "../../ScorecardManagement/hooks/save"; @@ -15,9 +15,6 @@ const newScorecardConfigQuery: any = { export function useMigrateScorecard() { const engine = useDataEngine(); const { saveSilently } = useSaveScorecard(); - const { refetch } = useDataQuery(newScorecardConfigQuery, { - lazy: true - }); const createNewConfiguration = useCallback(async (oldScorecard: OldScorecardSchema) => { return migrateScorecard({ oldScorecard, engine }); @@ -28,9 +25,14 @@ export function useMigrateScorecard() { const config = await createNewConfiguration(oldScorecard); //check if the scorecard exists try { - await refetch({ id: config.id }); + await engine.query(newScorecardConfigQuery, { + variables: { + id: config.id + } + }); return "EXISTS"; } catch (error) { + console.log(error); try { if (error instanceof FetchError) { //My bad, It's not there. Let's put it diff --git a/packages/app/src/modules/ScorecardMigration/index.tsx b/packages/app/src/modules/ScorecardMigration/index.tsx index 4c1a96629..8d1e8818d 100644 --- a/packages/app/src/modules/ScorecardMigration/index.tsx +++ b/packages/app/src/modules/ScorecardMigration/index.tsx @@ -1,11 +1,18 @@ import React from "react"; import i18n from "@dhis2/d2-i18n"; import { OldScorecardList } from "./components/OldScorecardList"; +import { Button, IconArrowLeft24 } from "@dhis2/ui"; +import { useNavigate } from "react-router-dom"; export default function ScorecardMigration() { - + const navigate = useNavigate(); return (
+
+ +

{i18n.t("Scorecards to migrate")}

{i18n.t("Select the scorecards configuration that you would like to migrate")}