@hisptz/dhis2-analytics 2.0.42 → 2.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,27 +38,53 @@ const query = {
38
38
  const chunkSize = 5;
39
39
  function useGetScorecardData(dataEngine) {
40
40
  const [totalRequests, setTotalRequests] = react.useState(0);
41
+ const engine = appRuntime.useDataEngine();
41
42
  const [noOfCompleteRequests, setNoOfCompleteRequests] = react.useState(0);
43
+ const { show, hide: hideAlert } = appRuntime.useAlert(
44
+ ({ message }) => message,
45
+ ({ type, actions }) => ({ ...type, actions, duration: 3e3 })
46
+ );
42
47
  const fetchData = async ({
43
48
  periods,
44
49
  dataItems,
45
50
  orgUnits
46
51
  }) => {
47
- const rawAnalyticsData = await refetch({
48
- periods,
49
- dataItems,
50
- orgUnits
51
- });
52
- if (!rawAnalyticsData)
53
- return [];
54
- const tableData = getTableData(rawAnalyticsData);
55
- dataEngine.updateData(tableData);
56
- setNoOfCompleteRequests((prev) => prev + 1);
52
+ try {
53
+ const rawAnalyticsData = await engine.query(query, {
54
+ variables: {
55
+ periods,
56
+ dataItems,
57
+ orgUnits
58
+ }
59
+ });
60
+ if (!rawAnalyticsData)
61
+ return [];
62
+ const tableData = getTableData(rawAnalyticsData);
63
+ dataEngine.updateData(tableData);
64
+ setNoOfCompleteRequests((prev) => prev + 1);
65
+ } catch (error) {
66
+ if (error instanceof Error || error instanceof appRuntime.FetchError) {
67
+ setTotalRequests(0);
68
+ setNoOfCompleteRequests(0);
69
+ dataFetchQueue.current.remove(() => true);
70
+ show({
71
+ message: `${i18n__default.default.t("Error getting scorecard data")}: ${error.message}`,
72
+ type: { critical: true },
73
+ actions: [
74
+ {
75
+ label: i18n__default.default.t("Retry"),
76
+ onClick: () => {
77
+ hideAlert();
78
+ initializeFetch();
79
+ }
80
+ }
81
+ ]
82
+ });
83
+ } else {
84
+ console.error(error);
85
+ }
86
+ }
57
87
  };
58
- const { show } = appRuntime.useAlert(
59
- ({ message }) => message,
60
- ({ type }) => ({ ...type, duration: 3e3 })
61
- );
62
88
  const dataFetchQueue = react.useRef(asyncEs.queue(async.asyncify(fetchData)));
63
89
  const config = components.useScorecardConfig();
64
90
  const meta = components.useScorecardMeta();
@@ -88,23 +114,6 @@ function useGetScorecardData(dataEngine) {
88
114
  }).flat();
89
115
  return lodash.uniq([...periodsIds, ...pastPeriods]);
90
116
  }, [periodsIds]);
91
- const { refetch } = appRuntime.useDataQuery(query, {
92
- variables: {
93
- periods: analyticsPeriod,
94
- dataItems: dataItemsIds,
95
- orgUnits: orgUnitsIds
96
- },
97
- lazy: true,
98
- onError: (error) => {
99
- setTotalRequests(0);
100
- setNoOfCompleteRequests(0);
101
- dataFetchQueue.current.remove(() => true);
102
- show({
103
- message: `${i18n__default.default.t("Error getting scorecard data")}: ${error.message}`,
104
- type: { critical: true }
105
- });
106
- }
107
- });
108
117
  const progress = react.useMemo(() => {
109
118
  return noOfCompleteRequests / totalRequests;
110
119
  }, [totalRequests, noOfCompleteRequests]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/Scorecard/hooks/data.ts"],"names":[],"mappings":"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","sourcesContent":["import { useScorecardConfig, useScorecardMeta } from \"../components\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { getDimensionsFromMeta } from \"../utils/analytics\";\nimport { useAlert, useDataQuery } from \"@dhis2/app-runtime\";\nimport {\n\tcreateFixedPeriodFromPeriodId,\n\tgetAdjacentFixedPeriods,\n} from \"@dhis2/multi-calendar-dates\";\nimport { chunk, maxBy, uniq } from \"lodash\";\nimport { sanitizeAnalyticsData } from \"../utils/data\";\nimport { useCalendar } from \"./metadata\";\nimport { queue } from \"async-es\";\nimport { asyncify, type QueueObject } from \"async\";\nimport type { ScorecardDataEngine } from \"../utils/dataEngine\";\nimport i18n from \"@dhis2/d2-i18n\";\n\nconst query: any = {\n\tdata: {\n\t\tresource: \"analytics\",\n\t\tparams: ({\n\t\t\tperiods,\n\t\t\torgUnits,\n\t\t\tdataItems,\n\t\t}: {\n\t\t\tperiods: string[];\n\t\t\torgUnits: string[];\n\t\t\tdataItems: string[];\n\t\t}) => {\n\t\t\treturn {\n\t\t\t\tskipMeta: true,\n\t\t\t\tdimension: [\n\t\t\t\t\t`pe:${periods.join(\";\")}`,\n\t\t\t\t\t`dx:${dataItems.join(\";\")}`,\n\t\t\t\t\t`ou:${orgUnits.join(\";\")}`,\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t},\n};\n\nexport interface ScorecardDataQueryResponse {\n\tdata: {\n\t\theaderWidth: number;\n\t\theaders: Array<{\n\t\t\tname: string;\n\t\t\thidden: boolean;\n\t\t\tmeta: boolean;\n\t\t\tcolumn: string;\n\t\t\tvalueType: string;\n\t\t}>;\n\t\trows: Array<Array<string>>;\n\t\theight: number;\n\t\twidth: number;\n\t};\n}\n\nconst chunkSize = 5;\n\nexport function useGetScorecardData(dataEngine: ScorecardDataEngine) {\n\tconst [totalRequests, setTotalRequests] = useState<number>(0);\n\tconst [noOfCompleteRequests, setNoOfCompleteRequests] = useState<number>(0);\n\tconst fetchData = async ({\n\t\tperiods,\n\t\tdataItems,\n\t\torgUnits,\n\t}: {\n\t\tperiods: string[];\n\t\torgUnits: string[];\n\t\tdataItems: string[];\n\t}) => {\n\t\tconst rawAnalyticsData = (await refetch({\n\t\t\tperiods,\n\t\t\tdataItems,\n\t\t\torgUnits,\n\t\t})) as unknown as ScorecardDataQueryResponse;\n\t\tif (!rawAnalyticsData) return [];\n\t\tconst tableData = getTableData(rawAnalyticsData);\n\t\tdataEngine.updateData(tableData);\n\t\tsetNoOfCompleteRequests((prev) => prev + 1);\n\t};\n\n\tconst { show } = useAlert(\n\t\t({ message }) => message,\n\t\t({ type }) => ({ ...type, duration: 3000 }),\n\t);\n\tconst dataFetchQueue = useRef<QueueObject<any>>(queue(asyncify(fetchData)));\n\tconst config = useScorecardConfig();\n\tconst meta = useScorecardMeta();\n\tconst calendar = useCalendar();\n\tif (!config || !meta) {\n\t\tthrow new Error(\n\t\t\t\"Invalid scorecard setup. Make sure the valid config and state props are passed.\",\n\t\t);\n\t}\n\tconst { dataItemsIds, orgUnitsIds, periodsIds } = useMemo(\n\t\t() =>\n\t\t\tgetDimensionsFromMeta({\n\t\t\t\tmeta,\n\t\t\t}),\n\t\t[meta],\n\t);\n\n\t//We need to make sure each period has a past period\n\tconst analyticsPeriod = useMemo(() => {\n\t\tconst pastPeriods = periodsIds\n\t\t\t.map((periodId) => {\n\t\t\t\tconst pe = getAdjacentFixedPeriods({\n\t\t\t\t\tcalendar,\n\t\t\t\t\tsteps: -1,\n\t\t\t\t\tperiod: createFixedPeriodFromPeriodId({\n\t\t\t\t\t\tcalendar,\n\t\t\t\t\t\tperiodId,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\treturn pe.map(({ id }) => id);\n\t\t\t})\n\t\t\t.flat();\n\n\t\treturn uniq([...periodsIds, ...pastPeriods]);\n\t}, [periodsIds]);\n\n\tconst { refetch } = useDataQuery<ScorecardDataQueryResponse>(query, {\n\t\tvariables: {\n\t\t\tperiods: analyticsPeriod,\n\t\t\tdataItems: dataItemsIds,\n\t\t\torgUnits: orgUnitsIds,\n\t\t},\n\t\tlazy: true,\n\t\tonError: (error) => {\n\t\t\tsetTotalRequests(0);\n\t\t\tsetNoOfCompleteRequests(0);\n\t\t\tdataFetchQueue.current.remove(() => true);\n\t\t\tshow({\n\t\t\t\tmessage: `${i18n.t(\"Error getting scorecard data\")}: ${\n\t\t\t\t\terror.message\n\t\t\t\t}`,\n\t\t\t\ttype: { critical: true },\n\t\t\t});\n\t\t},\n\t});\n\n\tconst progress = useMemo(() => {\n\t\treturn noOfCompleteRequests / totalRequests;\n\t}, [totalRequests, noOfCompleteRequests]);\n\n\tconst getTableData = (rawAnalyticsData: ScorecardDataQueryResponse) => {\n\t\treturn sanitizeAnalyticsData(rawAnalyticsData);\n\t};\n\n\tconst initializeFetch = async () => {\n\t\tconst getTheLongestDimension = () => {\n\t\t\tconst dimensions = [\n\t\t\t\t{\n\t\t\t\t\tdimension: \"pe\",\n\t\t\t\t\tlength: analyticsPeriod.length,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdimension: \"dx\",\n\t\t\t\t\tlength: dataItemsIds.length,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdimension: \"ou\",\n\t\t\t\t\tlength: orgUnitsIds.length,\n\t\t\t\t},\n\t\t\t] as const;\n\n\t\t\treturn maxBy(dimensions, \"length\")!.dimension;\n\t\t};\n\n\t\tconst getChunkedData = async (maxItem: \"dx\" | \"pe\" | \"ou\") => {\n\t\t\tswitch (maxItem) {\n\t\t\t\tcase \"dx\":\n\t\t\t\t\tconst dataItemChunks = chunk(dataItemsIds, chunkSize);\n\t\t\t\t\tsetTotalRequests(dataItemChunks.length);\n\t\t\t\t\tfor (const dataItemChunk of dataItemChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\t\t\t\tdataItems: dataItemChunk,\n\t\t\t\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"pe\":\n\t\t\t\t\tconst periodChunks = chunk(analyticsPeriod, chunkSize);\n\t\t\t\t\tsetTotalRequests(periodChunks.length);\n\t\t\t\t\tfor (const periodChunk of periodChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: periodChunk,\n\t\t\t\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"ou\":\n\t\t\t\t\tconst orgUnitChunks = chunk(orgUnitsIds, chunkSize);\n\t\t\t\t\tsetTotalRequests(orgUnitChunks.length);\n\t\t\t\t\tfor (const orgUnitChunk of orgUnitChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\t\t\t\torgUnits: orgUnitChunk,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t};\n\t\t//Here is where we need to paginate the requests.\n\t\t//First, Are there any dimensions greater than 5? if not then we can just call all the data\n\t\tsetTotalRequests(0);\n\t\tsetNoOfCompleteRequests(0);\n\t\tdataFetchQueue.current.remove(() => true);\n\t\tdataFetchQueue.current.drain(() => {\n\t\t\tdataEngine.complete();\n\t\t});\n\n\t\tdataEngine.clear();\n\t\tif (\n\t\t\tanalyticsPeriod.length <= 5 &&\n\t\t\tdataItemsIds.length <= 5 &&\n\t\t\torgUnitsIds.length <= 5\n\t\t) {\n\t\t\tsetTotalRequests(1);\n\t\t\tsetNoOfCompleteRequests(0);\n\t\t\tawait fetchData({\n\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t});\n\t\t\tsetNoOfCompleteRequests(1);\n\t\t\tdataEngine.complete();\n\t\t\treturn;\n\t\t}\n\t\t//If not then let's figure out how to paginate one of the\n\t\tsetNoOfCompleteRequests(0);\n\t\tconst dimensionWithMaxItems = getTheLongestDimension();\n\t\tawait getChunkedData(dimensionWithMaxItems);\n\t};\n\n\tuseEffect(() => {\n\t\tinitializeFetch();\n\t}, []);\n\n\treturn {\n\t\trawData: [],\n\t\tprogress,\n\t};\n}\n"]}
1
+ {"version":3,"sources":["../../../../src/components/Scorecard/hooks/data.ts"],"names":[],"mappings":"AAAA,SAAS,oBAAoB,wBAAwB;AACrD,SAAS,WAAW,SAAS,QAAQ,gBAAgB;AACrD,SAAS,6BAA6B;AACtC,SAAS,YAAY,UAAU,qBAAqB;AACpD;AAAA,EACC;AAAA,EACA;AAAA,OACM;AACP,SAAS,OAAO,OAAO,YAAY;AACnC,SAAS,6BAA6B;AACtC,SAAS,mBAAmB;AAC5B,SAAS,aAAa;AACtB,SAAS,gBAAkC;AAE3C,OAAO,UAAU;AAEjB,MAAM,QAAa;AAAA,EAClB,MAAM;AAAA,IACL,UAAU;AAAA,IACV,QAAQ,CAAC;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACD,MAIM;AACL,aAAO;AAAA,QACN,UAAU;AAAA,QACV,WAAW;AAAA,UACV,MAAM,QAAQ,KAAK,GAAG,CAAC;AAAA,UACvB,MAAM,UAAU,KAAK,GAAG,CAAC;AAAA,UACzB,MAAM,SAAS,KAAK,GAAG,CAAC;AAAA,QACzB;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAkBA,MAAM,YAAY;AAEX,SAAS,oBAAoB,YAAiC;AACpE,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAiB,CAAC;AAC5D,QAAM,SAAS,cAAc;AAC7B,QAAM,CAAC,sBAAsB,uBAAuB,IAAI,SAAiB,CAAC;AAC1E,QAAM,EAAE,MAAM,MAAM,UAAU,IAAI;AAAA,IACjC,CAAC,EAAE,QAAQ,MAAM;AAAA,IACjB,CAAC,EAAE,MAAM,QAAQ,OAAO,EAAE,GAAG,MAAM,SAAS,UAAU,IAAK;AAAA,EAC5D;AACA,QAAM,YAAY,OAAO;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACD,MAIM;AACL,QAAI;AACH,YAAM,mBAAoB,MAAM,OAAO,MAAM,OAAO;AAAA,QACnD,WAAW;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAAA,MACD,CAAC;AACD,UAAI,CAAC;AAAkB,eAAO,CAAC;AAC/B,YAAM,YAAY,aAAa,gBAAgB;AAC/C,iBAAW,WAAW,SAAS;AAC/B,8BAAwB,CAAC,SAAS,OAAO,CAAC;AAAA,IAC3C,SAAS,OAAO;AACf,UAAI,iBAAiB,SAAS,iBAAiB,YAAY;AAC1D,yBAAiB,CAAC;AAClB,gCAAwB,CAAC;AACzB,uBAAe,QAAQ,OAAO,MAAM,IAAI;AACxC,aAAK;AAAA,UACJ,SAAS,GAAG,KAAK,EAAE,8BAA8B,CAAC,KACjD,MAAM,OACP;AAAA,UACA,MAAM,EAAE,UAAU,KAAK;AAAA,UACvB,SAAS;AAAA,YACR;AAAA,cACC,OAAO,KAAK,EAAE,OAAO;AAAA,cACrB,SAAS,MAAM;AACd,0BAAU;AACV,gCAAgB;AAAA,cACjB;AAAA,YACD;AAAA,UACD;AAAA,QACD,CAAC;AAAA,MACF,OAAO;AACN,gBAAQ,MAAM,KAAK;AAAA,MACpB;AAAA,IACD;AAAA,EACD;AACA,QAAM,iBAAiB,OAAyB,MAAM,SAAS,SAAS,CAAC,CAAC;AAC1E,QAAM,SAAS,mBAAmB;AAClC,QAAM,OAAO,iBAAiB;AAC9B,QAAM,WAAW,YAAY;AAC7B,MAAI,CAAC,UAAU,CAAC,MAAM;AACrB,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,QAAM,EAAE,cAAc,aAAa,WAAW,IAAI;AAAA,IACjD,MACC,sBAAsB;AAAA,MACrB;AAAA,IACD,CAAC;AAAA,IACF,CAAC,IAAI;AAAA,EACN;AAGA,QAAM,kBAAkB,QAAQ,MAAM;AACrC,UAAM,cAAc,WAClB,IAAI,CAAC,aAAa;AAClB,YAAM,KAAK,wBAAwB;AAAA,QAClC;AAAA,QACA,OAAO;AAAA,QACP,QAAQ,8BAA8B;AAAA,UACrC;AAAA,UACA;AAAA,QACD,CAAC;AAAA,MACF,CAAC;AACD,aAAO,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE;AAAA,IAC7B,CAAC,EACA,KAAK;AAEP,WAAO,KAAK,CAAC,GAAG,YAAY,GAAG,WAAW,CAAC;AAAA,EAC5C,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,WAAW,QAAQ,MAAM;AAC9B,WAAO,uBAAuB;AAAA,EAC/B,GAAG,CAAC,eAAe,oBAAoB,CAAC;AAExC,QAAM,eAAe,CAAC,qBAAiD;AACtE,WAAO,sBAAsB,gBAAgB;AAAA,EAC9C;AAEA,QAAM,kBAAkB,YAAY;AACnC,UAAM,yBAAyB,MAAM;AACpC,YAAM,aAAa;AAAA,QAClB;AAAA,UACC,WAAW;AAAA,UACX,QAAQ,gBAAgB;AAAA,QACzB;AAAA,QACA;AAAA,UACC,WAAW;AAAA,UACX,QAAQ,aAAa;AAAA,QACtB;AAAA,QACA;AAAA,UACC,WAAW;AAAA,UACX,QAAQ,YAAY;AAAA,QACrB;AAAA,MACD;AAEA,aAAO,MAAM,YAAY,QAAQ,EAAG;AAAA,IACrC;AAEA,UAAM,iBAAiB,OAAO,YAAgC;AAC7D,cAAQ,SAAS;AAAA,QAChB,KAAK;AACJ,gBAAM,iBAAiB,MAAM,cAAc,SAAS;AACpD,2BAAiB,eAAe,MAAM;AACtC,qBAAW,iBAAiB,gBAAgB;AAC3C,2BAAe,QAAQ,KAAK;AAAA,cAC3B,SAAS;AAAA,cACT,WAAW;AAAA,cACX,UAAU;AAAA,YACX,CAAC;AAAA,UACF;AACA;AAAA,QACD,KAAK;AACJ,gBAAM,eAAe,MAAM,iBAAiB,SAAS;AACrD,2BAAiB,aAAa,MAAM;AACpC,qBAAW,eAAe,cAAc;AACvC,2BAAe,QAAQ,KAAK;AAAA,cAC3B,SAAS;AAAA,cACT,WAAW;AAAA,cACX,UAAU;AAAA,YACX,CAAC;AAAA,UACF;AACA;AAAA,QACD,KAAK;AACJ,gBAAM,gBAAgB,MAAM,aAAa,SAAS;AAClD,2BAAiB,cAAc,MAAM;AACrC,qBAAW,gBAAgB,eAAe;AACzC,2BAAe,QAAQ,KAAK;AAAA,cAC3B,SAAS;AAAA,cACT,WAAW;AAAA,cACX,UAAU;AAAA,YACX,CAAC;AAAA,UACF;AACA;AAAA,MACF;AAAA,IACD;AAGA,qBAAiB,CAAC;AAClB,4BAAwB,CAAC;AACzB,mBAAe,QAAQ,OAAO,MAAM,IAAI;AACxC,mBAAe,QAAQ,MAAM,MAAM;AAClC,iBAAW,SAAS;AAAA,IACrB,CAAC;AAED,eAAW,MAAM;AACjB,QACC,gBAAgB,UAAU,KAC1B,aAAa,UAAU,KACvB,YAAY,UAAU,GACrB;AACD,uBAAiB,CAAC;AAClB,8BAAwB,CAAC;AACzB,YAAM,UAAU;AAAA,QACf,SAAS;AAAA,QACT,WAAW;AAAA,QACX,UAAU;AAAA,MACX,CAAC;AACD,8BAAwB,CAAC;AACzB,iBAAW,SAAS;AACpB;AAAA,IACD;AAEA,4BAAwB,CAAC;AACzB,UAAM,wBAAwB,uBAAuB;AACrD,UAAM,eAAe,qBAAqB;AAAA,EAC3C;AAEA,YAAU,MAAM;AACf,oBAAgB;AAAA,EACjB,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACN,SAAS,CAAC;AAAA,IACV;AAAA,EACD;AACD","sourcesContent":["import { useScorecardConfig, useScorecardMeta } from \"../components\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { getDimensionsFromMeta } from \"../utils/analytics\";\nimport { FetchError, useAlert, useDataEngine } from \"@dhis2/app-runtime\";\nimport {\n\tcreateFixedPeriodFromPeriodId,\n\tgetAdjacentFixedPeriods,\n} from \"@dhis2/multi-calendar-dates\";\nimport { chunk, maxBy, uniq } from \"lodash\";\nimport { sanitizeAnalyticsData } from \"../utils/data\";\nimport { useCalendar } from \"./metadata\";\nimport { queue } from \"async-es\";\nimport { asyncify, type QueueObject } from \"async\";\nimport type { ScorecardDataEngine } from \"../utils/dataEngine\";\nimport i18n from \"@dhis2/d2-i18n\";\n\nconst query: any = {\n\tdata: {\n\t\tresource: \"analytics\",\n\t\tparams: ({\n\t\t\tperiods,\n\t\t\torgUnits,\n\t\t\tdataItems,\n\t\t}: {\n\t\t\tperiods: string[];\n\t\t\torgUnits: string[];\n\t\t\tdataItems: string[];\n\t\t}) => {\n\t\t\treturn {\n\t\t\t\tskipMeta: true,\n\t\t\t\tdimension: [\n\t\t\t\t\t`pe:${periods.join(\";\")}`,\n\t\t\t\t\t`dx:${dataItems.join(\";\")}`,\n\t\t\t\t\t`ou:${orgUnits.join(\";\")}`,\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t},\n};\n\nexport interface ScorecardDataQueryResponse {\n\tdata: {\n\t\theaderWidth: number;\n\t\theaders: Array<{\n\t\t\tname: string;\n\t\t\thidden: boolean;\n\t\t\tmeta: boolean;\n\t\t\tcolumn: string;\n\t\t\tvalueType: string;\n\t\t}>;\n\t\trows: Array<Array<string>>;\n\t\theight: number;\n\t\twidth: number;\n\t};\n}\n\nconst chunkSize = 5;\n\nexport function useGetScorecardData(dataEngine: ScorecardDataEngine) {\n\tconst [totalRequests, setTotalRequests] = useState<number>(0);\n\tconst engine = useDataEngine();\n\tconst [noOfCompleteRequests, setNoOfCompleteRequests] = useState<number>(0);\n\tconst { show, hide: hideAlert } = useAlert(\n\t\t({ message }) => message,\n\t\t({ type, actions }) => ({ ...type, actions, duration: 3000 }),\n\t);\n\tconst fetchData = async ({\n\t\tperiods,\n\t\tdataItems,\n\t\torgUnits,\n\t}: {\n\t\tperiods: string[];\n\t\torgUnits: string[];\n\t\tdataItems: string[];\n\t}) => {\n\t\ttry {\n\t\t\tconst rawAnalyticsData = (await engine.query(query, {\n\t\t\t\tvariables: {\n\t\t\t\t\tperiods,\n\t\t\t\t\tdataItems,\n\t\t\t\t\torgUnits,\n\t\t\t\t},\n\t\t\t})) as unknown as ScorecardDataQueryResponse;\n\t\t\tif (!rawAnalyticsData) return [];\n\t\t\tconst tableData = getTableData(rawAnalyticsData);\n\t\t\tdataEngine.updateData(tableData);\n\t\t\tsetNoOfCompleteRequests((prev) => prev + 1);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error || error instanceof FetchError) {\n\t\t\t\tsetTotalRequests(0);\n\t\t\t\tsetNoOfCompleteRequests(0);\n\t\t\t\tdataFetchQueue.current.remove(() => true);\n\t\t\t\tshow({\n\t\t\t\t\tmessage: `${i18n.t(\"Error getting scorecard data\")}: ${\n\t\t\t\t\t\terror.message\n\t\t\t\t\t}`,\n\t\t\t\t\ttype: { critical: true },\n\t\t\t\t\tactions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: i18n.t(\"Retry\"),\n\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\thideAlert();\n\t\t\t\t\t\t\t\tinitializeFetch();\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconsole.error(error);\n\t\t\t}\n\t\t}\n\t};\n\tconst dataFetchQueue = useRef<QueueObject<any>>(queue(asyncify(fetchData)));\n\tconst config = useScorecardConfig();\n\tconst meta = useScorecardMeta();\n\tconst calendar = useCalendar();\n\tif (!config || !meta) {\n\t\tthrow new Error(\n\t\t\t\"Invalid scorecard setup. Make sure the valid config and state props are passed.\",\n\t\t);\n\t}\n\tconst { dataItemsIds, orgUnitsIds, periodsIds } = useMemo(\n\t\t() =>\n\t\t\tgetDimensionsFromMeta({\n\t\t\t\tmeta,\n\t\t\t}),\n\t\t[meta],\n\t);\n\n\t//We need to make sure each period has a past period\n\tconst analyticsPeriod = useMemo(() => {\n\t\tconst pastPeriods = periodsIds\n\t\t\t.map((periodId) => {\n\t\t\t\tconst pe = getAdjacentFixedPeriods({\n\t\t\t\t\tcalendar,\n\t\t\t\t\tsteps: -1,\n\t\t\t\t\tperiod: createFixedPeriodFromPeriodId({\n\t\t\t\t\t\tcalendar,\n\t\t\t\t\t\tperiodId,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\treturn pe.map(({ id }) => id);\n\t\t\t})\n\t\t\t.flat();\n\n\t\treturn uniq([...periodsIds, ...pastPeriods]);\n\t}, [periodsIds]);\n\n\tconst progress = useMemo(() => {\n\t\treturn noOfCompleteRequests / totalRequests;\n\t}, [totalRequests, noOfCompleteRequests]);\n\n\tconst getTableData = (rawAnalyticsData: ScorecardDataQueryResponse) => {\n\t\treturn sanitizeAnalyticsData(rawAnalyticsData);\n\t};\n\n\tconst initializeFetch = async () => {\n\t\tconst getTheLongestDimension = () => {\n\t\t\tconst dimensions = [\n\t\t\t\t{\n\t\t\t\t\tdimension: \"pe\",\n\t\t\t\t\tlength: analyticsPeriod.length,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdimension: \"dx\",\n\t\t\t\t\tlength: dataItemsIds.length,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdimension: \"ou\",\n\t\t\t\t\tlength: orgUnitsIds.length,\n\t\t\t\t},\n\t\t\t] as const;\n\n\t\t\treturn maxBy(dimensions, \"length\")!.dimension;\n\t\t};\n\n\t\tconst getChunkedData = async (maxItem: \"dx\" | \"pe\" | \"ou\") => {\n\t\t\tswitch (maxItem) {\n\t\t\t\tcase \"dx\":\n\t\t\t\t\tconst dataItemChunks = chunk(dataItemsIds, chunkSize);\n\t\t\t\t\tsetTotalRequests(dataItemChunks.length);\n\t\t\t\t\tfor (const dataItemChunk of dataItemChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\t\t\t\tdataItems: dataItemChunk,\n\t\t\t\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"pe\":\n\t\t\t\t\tconst periodChunks = chunk(analyticsPeriod, chunkSize);\n\t\t\t\t\tsetTotalRequests(periodChunks.length);\n\t\t\t\t\tfor (const periodChunk of periodChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: periodChunk,\n\t\t\t\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"ou\":\n\t\t\t\t\tconst orgUnitChunks = chunk(orgUnitsIds, chunkSize);\n\t\t\t\t\tsetTotalRequests(orgUnitChunks.length);\n\t\t\t\t\tfor (const orgUnitChunk of orgUnitChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\t\t\t\torgUnits: orgUnitChunk,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t};\n\t\t//Here is where we need to paginate the requests.\n\t\t//First, Are there any dimensions greater than 5? if not then we can just call all the data\n\t\tsetTotalRequests(0);\n\t\tsetNoOfCompleteRequests(0);\n\t\tdataFetchQueue.current.remove(() => true);\n\t\tdataFetchQueue.current.drain(() => {\n\t\t\tdataEngine.complete();\n\t\t});\n\n\t\tdataEngine.clear();\n\t\tif (\n\t\t\tanalyticsPeriod.length <= 5 &&\n\t\t\tdataItemsIds.length <= 5 &&\n\t\t\torgUnitsIds.length <= 5\n\t\t) {\n\t\t\tsetTotalRequests(1);\n\t\t\tsetNoOfCompleteRequests(0);\n\t\t\tawait fetchData({\n\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t});\n\t\t\tsetNoOfCompleteRequests(1);\n\t\t\tdataEngine.complete();\n\t\t\treturn;\n\t\t}\n\t\t//If not then let's figure out how to paginate one of the\n\t\tsetNoOfCompleteRequests(0);\n\t\tconst dimensionWithMaxItems = getTheLongestDimension();\n\t\tawait getChunkedData(dimensionWithMaxItems);\n\t};\n\n\tuseEffect(() => {\n\t\tinitializeFetch();\n\t}, []);\n\n\treturn {\n\t\trawData: [],\n\t\tprogress,\n\t};\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { useScorecardConfig, useScorecardMeta } from '../components';
2
2
  import { useState, useRef, useMemo, useEffect } from 'react';
3
3
  import { getDimensionsFromMeta } from '../utils/analytics';
4
- import { useAlert, useDataQuery } from '@dhis2/app-runtime';
4
+ import { useDataEngine, useAlert, FetchError } from '@dhis2/app-runtime';
5
5
  import { getAdjacentFixedPeriods, createFixedPeriodFromPeriodId } from '@dhis2/multi-calendar-dates';
6
6
  import { uniq, maxBy, chunk } from 'lodash';
7
7
  import { sanitizeAnalyticsData } from '../utils/data';
@@ -32,27 +32,53 @@ const query = {
32
32
  const chunkSize = 5;
33
33
  function useGetScorecardData(dataEngine) {
34
34
  const [totalRequests, setTotalRequests] = useState(0);
35
+ const engine = useDataEngine();
35
36
  const [noOfCompleteRequests, setNoOfCompleteRequests] = useState(0);
37
+ const { show, hide: hideAlert } = useAlert(
38
+ ({ message }) => message,
39
+ ({ type, actions }) => ({ ...type, actions, duration: 3e3 })
40
+ );
36
41
  const fetchData = async ({
37
42
  periods,
38
43
  dataItems,
39
44
  orgUnits
40
45
  }) => {
41
- const rawAnalyticsData = await refetch({
42
- periods,
43
- dataItems,
44
- orgUnits
45
- });
46
- if (!rawAnalyticsData)
47
- return [];
48
- const tableData = getTableData(rawAnalyticsData);
49
- dataEngine.updateData(tableData);
50
- setNoOfCompleteRequests((prev) => prev + 1);
46
+ try {
47
+ const rawAnalyticsData = await engine.query(query, {
48
+ variables: {
49
+ periods,
50
+ dataItems,
51
+ orgUnits
52
+ }
53
+ });
54
+ if (!rawAnalyticsData)
55
+ return [];
56
+ const tableData = getTableData(rawAnalyticsData);
57
+ dataEngine.updateData(tableData);
58
+ setNoOfCompleteRequests((prev) => prev + 1);
59
+ } catch (error) {
60
+ if (error instanceof Error || error instanceof FetchError) {
61
+ setTotalRequests(0);
62
+ setNoOfCompleteRequests(0);
63
+ dataFetchQueue.current.remove(() => true);
64
+ show({
65
+ message: `${i18n.t("Error getting scorecard data")}: ${error.message}`,
66
+ type: { critical: true },
67
+ actions: [
68
+ {
69
+ label: i18n.t("Retry"),
70
+ onClick: () => {
71
+ hideAlert();
72
+ initializeFetch();
73
+ }
74
+ }
75
+ ]
76
+ });
77
+ } else {
78
+ console.error(error);
79
+ }
80
+ }
51
81
  };
52
- const { show } = useAlert(
53
- ({ message }) => message,
54
- ({ type }) => ({ ...type, duration: 3e3 })
55
- );
56
82
  const dataFetchQueue = useRef(queue(asyncify(fetchData)));
57
83
  const config = useScorecardConfig();
58
84
  const meta = useScorecardMeta();
@@ -82,23 +108,6 @@ function useGetScorecardData(dataEngine) {
82
108
  }).flat();
83
109
  return uniq([...periodsIds, ...pastPeriods]);
84
110
  }, [periodsIds]);
85
- const { refetch } = useDataQuery(query, {
86
- variables: {
87
- periods: analyticsPeriod,
88
- dataItems: dataItemsIds,
89
- orgUnits: orgUnitsIds
90
- },
91
- lazy: true,
92
- onError: (error) => {
93
- setTotalRequests(0);
94
- setNoOfCompleteRequests(0);
95
- dataFetchQueue.current.remove(() => true);
96
- show({
97
- message: `${i18n.t("Error getting scorecard data")}: ${error.message}`,
98
- type: { critical: true }
99
- });
100
- }
101
- });
102
111
  const progress = useMemo(() => {
103
112
  return noOfCompleteRequests / totalRequests;
104
113
  }, [totalRequests, noOfCompleteRequests]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/components/Scorecard/hooks/data.ts"],"names":[],"mappings":"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","sourcesContent":["import { useScorecardConfig, useScorecardMeta } from \"../components\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { getDimensionsFromMeta } from \"../utils/analytics\";\nimport { useAlert, useDataQuery } from \"@dhis2/app-runtime\";\nimport {\n\tcreateFixedPeriodFromPeriodId,\n\tgetAdjacentFixedPeriods,\n} from \"@dhis2/multi-calendar-dates\";\nimport { chunk, maxBy, uniq } from \"lodash\";\nimport { sanitizeAnalyticsData } from \"../utils/data\";\nimport { useCalendar } from \"./metadata\";\nimport { queue } from \"async-es\";\nimport { asyncify, type QueueObject } from \"async\";\nimport type { ScorecardDataEngine } from \"../utils/dataEngine\";\nimport i18n from \"@dhis2/d2-i18n\";\n\nconst query: any = {\n\tdata: {\n\t\tresource: \"analytics\",\n\t\tparams: ({\n\t\t\tperiods,\n\t\t\torgUnits,\n\t\t\tdataItems,\n\t\t}: {\n\t\t\tperiods: string[];\n\t\t\torgUnits: string[];\n\t\t\tdataItems: string[];\n\t\t}) => {\n\t\t\treturn {\n\t\t\t\tskipMeta: true,\n\t\t\t\tdimension: [\n\t\t\t\t\t`pe:${periods.join(\";\")}`,\n\t\t\t\t\t`dx:${dataItems.join(\";\")}`,\n\t\t\t\t\t`ou:${orgUnits.join(\";\")}`,\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t},\n};\n\nexport interface ScorecardDataQueryResponse {\n\tdata: {\n\t\theaderWidth: number;\n\t\theaders: Array<{\n\t\t\tname: string;\n\t\t\thidden: boolean;\n\t\t\tmeta: boolean;\n\t\t\tcolumn: string;\n\t\t\tvalueType: string;\n\t\t}>;\n\t\trows: Array<Array<string>>;\n\t\theight: number;\n\t\twidth: number;\n\t};\n}\n\nconst chunkSize = 5;\n\nexport function useGetScorecardData(dataEngine: ScorecardDataEngine) {\n\tconst [totalRequests, setTotalRequests] = useState<number>(0);\n\tconst [noOfCompleteRequests, setNoOfCompleteRequests] = useState<number>(0);\n\tconst fetchData = async ({\n\t\tperiods,\n\t\tdataItems,\n\t\torgUnits,\n\t}: {\n\t\tperiods: string[];\n\t\torgUnits: string[];\n\t\tdataItems: string[];\n\t}) => {\n\t\tconst rawAnalyticsData = (await refetch({\n\t\t\tperiods,\n\t\t\tdataItems,\n\t\t\torgUnits,\n\t\t})) as unknown as ScorecardDataQueryResponse;\n\t\tif (!rawAnalyticsData) return [];\n\t\tconst tableData = getTableData(rawAnalyticsData);\n\t\tdataEngine.updateData(tableData);\n\t\tsetNoOfCompleteRequests((prev) => prev + 1);\n\t};\n\n\tconst { show } = useAlert(\n\t\t({ message }) => message,\n\t\t({ type }) => ({ ...type, duration: 3000 }),\n\t);\n\tconst dataFetchQueue = useRef<QueueObject<any>>(queue(asyncify(fetchData)));\n\tconst config = useScorecardConfig();\n\tconst meta = useScorecardMeta();\n\tconst calendar = useCalendar();\n\tif (!config || !meta) {\n\t\tthrow new Error(\n\t\t\t\"Invalid scorecard setup. Make sure the valid config and state props are passed.\",\n\t\t);\n\t}\n\tconst { dataItemsIds, orgUnitsIds, periodsIds } = useMemo(\n\t\t() =>\n\t\t\tgetDimensionsFromMeta({\n\t\t\t\tmeta,\n\t\t\t}),\n\t\t[meta],\n\t);\n\n\t//We need to make sure each period has a past period\n\tconst analyticsPeriod = useMemo(() => {\n\t\tconst pastPeriods = periodsIds\n\t\t\t.map((periodId) => {\n\t\t\t\tconst pe = getAdjacentFixedPeriods({\n\t\t\t\t\tcalendar,\n\t\t\t\t\tsteps: -1,\n\t\t\t\t\tperiod: createFixedPeriodFromPeriodId({\n\t\t\t\t\t\tcalendar,\n\t\t\t\t\t\tperiodId,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\treturn pe.map(({ id }) => id);\n\t\t\t})\n\t\t\t.flat();\n\n\t\treturn uniq([...periodsIds, ...pastPeriods]);\n\t}, [periodsIds]);\n\n\tconst { refetch } = useDataQuery<ScorecardDataQueryResponse>(query, {\n\t\tvariables: {\n\t\t\tperiods: analyticsPeriod,\n\t\t\tdataItems: dataItemsIds,\n\t\t\torgUnits: orgUnitsIds,\n\t\t},\n\t\tlazy: true,\n\t\tonError: (error) => {\n\t\t\tsetTotalRequests(0);\n\t\t\tsetNoOfCompleteRequests(0);\n\t\t\tdataFetchQueue.current.remove(() => true);\n\t\t\tshow({\n\t\t\t\tmessage: `${i18n.t(\"Error getting scorecard data\")}: ${\n\t\t\t\t\terror.message\n\t\t\t\t}`,\n\t\t\t\ttype: { critical: true },\n\t\t\t});\n\t\t},\n\t});\n\n\tconst progress = useMemo(() => {\n\t\treturn noOfCompleteRequests / totalRequests;\n\t}, [totalRequests, noOfCompleteRequests]);\n\n\tconst getTableData = (rawAnalyticsData: ScorecardDataQueryResponse) => {\n\t\treturn sanitizeAnalyticsData(rawAnalyticsData);\n\t};\n\n\tconst initializeFetch = async () => {\n\t\tconst getTheLongestDimension = () => {\n\t\t\tconst dimensions = [\n\t\t\t\t{\n\t\t\t\t\tdimension: \"pe\",\n\t\t\t\t\tlength: analyticsPeriod.length,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdimension: \"dx\",\n\t\t\t\t\tlength: dataItemsIds.length,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdimension: \"ou\",\n\t\t\t\t\tlength: orgUnitsIds.length,\n\t\t\t\t},\n\t\t\t] as const;\n\n\t\t\treturn maxBy(dimensions, \"length\")!.dimension;\n\t\t};\n\n\t\tconst getChunkedData = async (maxItem: \"dx\" | \"pe\" | \"ou\") => {\n\t\t\tswitch (maxItem) {\n\t\t\t\tcase \"dx\":\n\t\t\t\t\tconst dataItemChunks = chunk(dataItemsIds, chunkSize);\n\t\t\t\t\tsetTotalRequests(dataItemChunks.length);\n\t\t\t\t\tfor (const dataItemChunk of dataItemChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\t\t\t\tdataItems: dataItemChunk,\n\t\t\t\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"pe\":\n\t\t\t\t\tconst periodChunks = chunk(analyticsPeriod, chunkSize);\n\t\t\t\t\tsetTotalRequests(periodChunks.length);\n\t\t\t\t\tfor (const periodChunk of periodChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: periodChunk,\n\t\t\t\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"ou\":\n\t\t\t\t\tconst orgUnitChunks = chunk(orgUnitsIds, chunkSize);\n\t\t\t\t\tsetTotalRequests(orgUnitChunks.length);\n\t\t\t\t\tfor (const orgUnitChunk of orgUnitChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\t\t\t\torgUnits: orgUnitChunk,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t};\n\t\t//Here is where we need to paginate the requests.\n\t\t//First, Are there any dimensions greater than 5? if not then we can just call all the data\n\t\tsetTotalRequests(0);\n\t\tsetNoOfCompleteRequests(0);\n\t\tdataFetchQueue.current.remove(() => true);\n\t\tdataFetchQueue.current.drain(() => {\n\t\t\tdataEngine.complete();\n\t\t});\n\n\t\tdataEngine.clear();\n\t\tif (\n\t\t\tanalyticsPeriod.length <= 5 &&\n\t\t\tdataItemsIds.length <= 5 &&\n\t\t\torgUnitsIds.length <= 5\n\t\t) {\n\t\t\tsetTotalRequests(1);\n\t\t\tsetNoOfCompleteRequests(0);\n\t\t\tawait fetchData({\n\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t});\n\t\t\tsetNoOfCompleteRequests(1);\n\t\t\tdataEngine.complete();\n\t\t\treturn;\n\t\t}\n\t\t//If not then let's figure out how to paginate one of the\n\t\tsetNoOfCompleteRequests(0);\n\t\tconst dimensionWithMaxItems = getTheLongestDimension();\n\t\tawait getChunkedData(dimensionWithMaxItems);\n\t};\n\n\tuseEffect(() => {\n\t\tinitializeFetch();\n\t}, []);\n\n\treturn {\n\t\trawData: [],\n\t\tprogress,\n\t};\n}\n"]}
1
+ {"version":3,"sources":["../../../../../src/components/Scorecard/hooks/data.ts"],"names":[],"mappings":"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","sourcesContent":["import { useScorecardConfig, useScorecardMeta } from \"../components\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { getDimensionsFromMeta } from \"../utils/analytics\";\nimport { FetchError, useAlert, useDataEngine } from \"@dhis2/app-runtime\";\nimport {\n\tcreateFixedPeriodFromPeriodId,\n\tgetAdjacentFixedPeriods,\n} from \"@dhis2/multi-calendar-dates\";\nimport { chunk, maxBy, uniq } from \"lodash\";\nimport { sanitizeAnalyticsData } from \"../utils/data\";\nimport { useCalendar } from \"./metadata\";\nimport { queue } from \"async-es\";\nimport { asyncify, type QueueObject } from \"async\";\nimport type { ScorecardDataEngine } from \"../utils/dataEngine\";\nimport i18n from \"@dhis2/d2-i18n\";\n\nconst query: any = {\n\tdata: {\n\t\tresource: \"analytics\",\n\t\tparams: ({\n\t\t\tperiods,\n\t\t\torgUnits,\n\t\t\tdataItems,\n\t\t}: {\n\t\t\tperiods: string[];\n\t\t\torgUnits: string[];\n\t\t\tdataItems: string[];\n\t\t}) => {\n\t\t\treturn {\n\t\t\t\tskipMeta: true,\n\t\t\t\tdimension: [\n\t\t\t\t\t`pe:${periods.join(\";\")}`,\n\t\t\t\t\t`dx:${dataItems.join(\";\")}`,\n\t\t\t\t\t`ou:${orgUnits.join(\";\")}`,\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t},\n};\n\nexport interface ScorecardDataQueryResponse {\n\tdata: {\n\t\theaderWidth: number;\n\t\theaders: Array<{\n\t\t\tname: string;\n\t\t\thidden: boolean;\n\t\t\tmeta: boolean;\n\t\t\tcolumn: string;\n\t\t\tvalueType: string;\n\t\t}>;\n\t\trows: Array<Array<string>>;\n\t\theight: number;\n\t\twidth: number;\n\t};\n}\n\nconst chunkSize = 5;\n\nexport function useGetScorecardData(dataEngine: ScorecardDataEngine) {\n\tconst [totalRequests, setTotalRequests] = useState<number>(0);\n\tconst engine = useDataEngine();\n\tconst [noOfCompleteRequests, setNoOfCompleteRequests] = useState<number>(0);\n\tconst { show, hide: hideAlert } = useAlert(\n\t\t({ message }) => message,\n\t\t({ type, actions }) => ({ ...type, actions, duration: 3000 }),\n\t);\n\tconst fetchData = async ({\n\t\tperiods,\n\t\tdataItems,\n\t\torgUnits,\n\t}: {\n\t\tperiods: string[];\n\t\torgUnits: string[];\n\t\tdataItems: string[];\n\t}) => {\n\t\ttry {\n\t\t\tconst rawAnalyticsData = (await engine.query(query, {\n\t\t\t\tvariables: {\n\t\t\t\t\tperiods,\n\t\t\t\t\tdataItems,\n\t\t\t\t\torgUnits,\n\t\t\t\t},\n\t\t\t})) as unknown as ScorecardDataQueryResponse;\n\t\t\tif (!rawAnalyticsData) return [];\n\t\t\tconst tableData = getTableData(rawAnalyticsData);\n\t\t\tdataEngine.updateData(tableData);\n\t\t\tsetNoOfCompleteRequests((prev) => prev + 1);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error || error instanceof FetchError) {\n\t\t\t\tsetTotalRequests(0);\n\t\t\t\tsetNoOfCompleteRequests(0);\n\t\t\t\tdataFetchQueue.current.remove(() => true);\n\t\t\t\tshow({\n\t\t\t\t\tmessage: `${i18n.t(\"Error getting scorecard data\")}: ${\n\t\t\t\t\t\terror.message\n\t\t\t\t\t}`,\n\t\t\t\t\ttype: { critical: true },\n\t\t\t\t\tactions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: i18n.t(\"Retry\"),\n\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\thideAlert();\n\t\t\t\t\t\t\t\tinitializeFetch();\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconsole.error(error);\n\t\t\t}\n\t\t}\n\t};\n\tconst dataFetchQueue = useRef<QueueObject<any>>(queue(asyncify(fetchData)));\n\tconst config = useScorecardConfig();\n\tconst meta = useScorecardMeta();\n\tconst calendar = useCalendar();\n\tif (!config || !meta) {\n\t\tthrow new Error(\n\t\t\t\"Invalid scorecard setup. Make sure the valid config and state props are passed.\",\n\t\t);\n\t}\n\tconst { dataItemsIds, orgUnitsIds, periodsIds } = useMemo(\n\t\t() =>\n\t\t\tgetDimensionsFromMeta({\n\t\t\t\tmeta,\n\t\t\t}),\n\t\t[meta],\n\t);\n\n\t//We need to make sure each period has a past period\n\tconst analyticsPeriod = useMemo(() => {\n\t\tconst pastPeriods = periodsIds\n\t\t\t.map((periodId) => {\n\t\t\t\tconst pe = getAdjacentFixedPeriods({\n\t\t\t\t\tcalendar,\n\t\t\t\t\tsteps: -1,\n\t\t\t\t\tperiod: createFixedPeriodFromPeriodId({\n\t\t\t\t\t\tcalendar,\n\t\t\t\t\t\tperiodId,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\treturn pe.map(({ id }) => id);\n\t\t\t})\n\t\t\t.flat();\n\n\t\treturn uniq([...periodsIds, ...pastPeriods]);\n\t}, [periodsIds]);\n\n\tconst progress = useMemo(() => {\n\t\treturn noOfCompleteRequests / totalRequests;\n\t}, [totalRequests, noOfCompleteRequests]);\n\n\tconst getTableData = (rawAnalyticsData: ScorecardDataQueryResponse) => {\n\t\treturn sanitizeAnalyticsData(rawAnalyticsData);\n\t};\n\n\tconst initializeFetch = async () => {\n\t\tconst getTheLongestDimension = () => {\n\t\t\tconst dimensions = [\n\t\t\t\t{\n\t\t\t\t\tdimension: \"pe\",\n\t\t\t\t\tlength: analyticsPeriod.length,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdimension: \"dx\",\n\t\t\t\t\tlength: dataItemsIds.length,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdimension: \"ou\",\n\t\t\t\t\tlength: orgUnitsIds.length,\n\t\t\t\t},\n\t\t\t] as const;\n\n\t\t\treturn maxBy(dimensions, \"length\")!.dimension;\n\t\t};\n\n\t\tconst getChunkedData = async (maxItem: \"dx\" | \"pe\" | \"ou\") => {\n\t\t\tswitch (maxItem) {\n\t\t\t\tcase \"dx\":\n\t\t\t\t\tconst dataItemChunks = chunk(dataItemsIds, chunkSize);\n\t\t\t\t\tsetTotalRequests(dataItemChunks.length);\n\t\t\t\t\tfor (const dataItemChunk of dataItemChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\t\t\t\tdataItems: dataItemChunk,\n\t\t\t\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"pe\":\n\t\t\t\t\tconst periodChunks = chunk(analyticsPeriod, chunkSize);\n\t\t\t\t\tsetTotalRequests(periodChunks.length);\n\t\t\t\t\tfor (const periodChunk of periodChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: periodChunk,\n\t\t\t\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"ou\":\n\t\t\t\t\tconst orgUnitChunks = chunk(orgUnitsIds, chunkSize);\n\t\t\t\t\tsetTotalRequests(orgUnitChunks.length);\n\t\t\t\t\tfor (const orgUnitChunk of orgUnitChunks) {\n\t\t\t\t\t\tdataFetchQueue.current.push({\n\t\t\t\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\t\t\t\torgUnits: orgUnitChunk,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t};\n\t\t//Here is where we need to paginate the requests.\n\t\t//First, Are there any dimensions greater than 5? if not then we can just call all the data\n\t\tsetTotalRequests(0);\n\t\tsetNoOfCompleteRequests(0);\n\t\tdataFetchQueue.current.remove(() => true);\n\t\tdataFetchQueue.current.drain(() => {\n\t\t\tdataEngine.complete();\n\t\t});\n\n\t\tdataEngine.clear();\n\t\tif (\n\t\t\tanalyticsPeriod.length <= 5 &&\n\t\t\tdataItemsIds.length <= 5 &&\n\t\t\torgUnitsIds.length <= 5\n\t\t) {\n\t\t\tsetTotalRequests(1);\n\t\t\tsetNoOfCompleteRequests(0);\n\t\t\tawait fetchData({\n\t\t\t\tperiods: analyticsPeriod,\n\t\t\t\tdataItems: dataItemsIds,\n\t\t\t\torgUnits: orgUnitsIds,\n\t\t\t});\n\t\t\tsetNoOfCompleteRequests(1);\n\t\t\tdataEngine.complete();\n\t\t\treturn;\n\t\t}\n\t\t//If not then let's figure out how to paginate one of the\n\t\tsetNoOfCompleteRequests(0);\n\t\tconst dimensionWithMaxItems = getTheLongestDimension();\n\t\tawait getChunkedData(dimensionWithMaxItems);\n\t};\n\n\tuseEffect(() => {\n\t\tinitializeFetch();\n\t}, []);\n\n\treturn {\n\t\trawData: [],\n\t\tprogress,\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../../../src/components/Scorecard/hooks/data.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AA2B/D,MAAM,WAAW,0BAA0B;IAC1C,IAAI,EAAE;QACL,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,KAAK,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,OAAO,CAAC;YAChB,IAAI,EAAE,OAAO,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,SAAS,EAAE,MAAM,CAAC;SAClB,CAAC,CAAC;QACH,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3B,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACd,CAAC;CACF;AAID,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,mBAAmB;;;EA4LlE"}
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../../../src/components/Scorecard/hooks/data.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AA2B/D,MAAM,WAAW,0BAA0B;IAC1C,IAAI,EAAE;QACL,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,KAAK,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,OAAO,CAAC;YAChB,IAAI,EAAE,OAAO,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,SAAS,EAAE,MAAM,CAAC;SAClB,CAAC,CAAC;QACH,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3B,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACd,CAAC;CACF;AAID,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,mBAAmB;;;EAmMlE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hisptz/dhis2-analytics",
3
- "version": "2.0.42",
3
+ "version": "2.0.43",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/esm/index.js",
6
6
  "types": "./dist/types/index.d.ts",