@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.
- package/dist/components/Scorecard/hooks/data.js +40 -31
- package/dist/components/Scorecard/hooks/data.js.map +1 -1
- package/dist/esm/components/Scorecard/hooks/data.js +41 -32
- package/dist/esm/components/Scorecard/hooks/data.js.map +1 -1
- package/dist/types/components/Scorecard/hooks/data.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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":"AAAA,SAAS,oBAAoB,wBAAwB;AACrD,SAAS,WAAW,SAAS,QAAQ,gBAAgB;AACrD,SAAS,6BAA6B;AACtC,SAAS,UAAU,oBAAoB;AACvC;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,CAAC,sBAAsB,uBAAuB,IAAI,SAAiB,CAAC;AAC1E,QAAM,YAAY,OAAO;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACD,MAIM;AACL,UAAM,mBAAoB,MAAM,QAAQ;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAC;AACD,QAAI,CAAC;AAAkB,aAAO,CAAC;AAC/B,UAAM,YAAY,aAAa,gBAAgB;AAC/C,eAAW,WAAW,SAAS;AAC/B,4BAAwB,CAAC,SAAS,OAAO,CAAC;AAAA,EAC3C;AAEA,QAAM,EAAE,KAAK,IAAI;AAAA,IAChB,CAAC,EAAE,QAAQ,MAAM;AAAA,IACjB,CAAC,EAAE,KAAK,OAAO,EAAE,GAAG,MAAM,UAAU,IAAK;AAAA,EAC1C;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,EAAE,QAAQ,IAAI,aAAyC,OAAO;AAAA,IACnE,WAAW;AAAA,MACV,SAAS;AAAA,MACT,WAAW;AAAA,MACX,UAAU;AAAA,IACX;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,UAAU;AACnB,uBAAiB,CAAC;AAClB,8BAAwB,CAAC;AACzB,qBAAe,QAAQ,OAAO,MAAM,IAAI;AACxC,WAAK;AAAA,QACJ,SAAS,GAAG,KAAK,EAAE,8BAA8B,CAAC,KACjD,MAAM,OACP;AAAA,QACA,MAAM,EAAE,UAAU,KAAK;AAAA,MACxB,CAAC;AAAA,IACF;AAAA,EACD,CAAC;AAED,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 { 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,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,
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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;;;
|
|
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"}
|