diff --git a/src/components/ParticipationDataList.vue b/src/components/ParticipationDataList.vue index 77ad7d3..9a941de 100644 --- a/src/components/ParticipationDataList.vue +++ b/src/components/ParticipationDataList.vue @@ -22,11 +22,11 @@ Licensed under the Elastic License 2.0. */ import { useErrorHandling } from '../composable/useErrorHandling'; import { reactive, ref, Ref, watch } from 'vue'; import { - ChartProperties, + ChartProperties, ObservationDataView, ObservationDataViewData, ObservationDataViewDataRow, ParticipationDataGrouping, - ParticipationDataMapping, + ParticipationDataMapping } from '../models/ParticipationData'; import { AxiosError, AxiosResponse } from 'axios'; import { @@ -44,7 +44,7 @@ Licensed under the Elastic License 2.0. */ import { useStudyGroupStore } from '../stores/studyGroupStore'; import Button from 'primevue/button'; - const { t } = useI18n(); + const { t, d } = useI18n(); const { handleIndividualError } = useErrorHandling(); const { componentsApi } = useComponentsApi(); const { participantsApi } = useParticipantsApi(); @@ -68,7 +68,7 @@ Licensed under the Elastic License 2.0. */ const filterDateRange = ref(); watch(filterDateRange, () => { if (filterDateRange.value?.every((v: Date | null) => v !== null)) { - changeView(); + applyFilters(); } }); const filterStudyGroup = ref(); @@ -149,14 +149,14 @@ Licensed under the Elastic License 2.0. */ ); participantOptions.value = filteredOptions; - changeView(); + applyFilters(); } function clearAllFilters(): void { filterParticipant.value = undefined; filterStudyGroup.value = undefined; filterDateRange.value = undefined; - changeView(); + applyFilters(); } function getStudyGroupIdByParticipantId(id: number): string | undefined { @@ -169,7 +169,7 @@ Licensed under the Elastic License 2.0. */ function onParticipantFilterChange(e: DropdownChangeEvent): void { filterStudyGroup.value = getStudyGroupIdByParticipantId(parseInt(e.value)); - changeView(); + applyFilters(); } async function listParticipant(): Promise { @@ -227,7 +227,9 @@ Licensed under the Elastic License 2.0. */ }); } - function getUniqueObservationIds(data: ParticipationDataMapping[]): Set { + function getUniqueObservationIds( + data: ParticipationDataMapping[], + ): Set { const uniqueIds = new Set(); data.forEach((item) => { @@ -244,29 +246,29 @@ Licensed under the Elastic License 2.0. */ .getViewsForObservation(props.studyId, observationId) .then((response: AxiosResponse) => { console.log('Possible views:', response.data); - observationsViewData[observationId] = { - chartType: null, - chartData: null, - possibleViews: response.data, - selectedView: ref( - response.data.length > 0 ? response.data[0].name : '', - ), - }; - if (response.data.length > 0) { - dataApi - .getObservationData( - props.studyId, - observationId, - observationsViewData[observationId].selectedView, - ) - .then((rs: AxiosResponse) => { - console.log('Response:', rs); - const chartData = convertChartTypeData(rs.data); - console.log('chartData:', chartData); - observationsViewData[observationId].chartType = rs.data.chartType; - observationsViewData[observationId].chartData = chartData; - console.log('observationsViewData:', observationsViewData); - }); + if (response.data?.length > 0) { + observationsViewData[observationId] = []; + response.data.forEach((view: ObservationDataView) => { + dataApi + .getObservationData(props.studyId, observationId, view.name) + .then((rs: AxiosResponse) => { + console.log('Response:', rs); + const chartData = convertChartTypeData(rs.data); + console.log('chartData:', chartData); + console.log('observationsViewData:', observationsViewData); + observationsViewData[observationId].push({ + chartType: rs.data?.chartType ?? null, + chartData: chartData, + view: view, + }); + }) + .catch((e: AxiosError) => { + handleIndividualError( + e, + 'cannot list view data for observation', + ); + }); + }); } }) .catch((e: AxiosError) => { @@ -275,33 +277,14 @@ Licensed under the Elastic License 2.0. */ } } - function changeView(observationId?: number): void { - if (observationId) { - dataApi - .getObservationData( - props.studyId, - observationId, - observationsViewData[observationId].selectedView, - filterStudyGroup.value, - filterParticipant.value, - filterDateRange.value ? filterDateRange.value[0] : undefined, - filterDateRange.value ? filterDateRange.value[1] : undefined, - ) - .then((rs: AxiosResponse) => { - console.log('Response:', rs); - const chartData = convertChartTypeData(rs.data); - console.log('chartData:', chartData); - observationsViewData[observationId].chartType = rs.data.chartType; - observationsViewData[observationId].chartData = chartData; - console.log('observationsViewData:', observationsViewData); - }); - } else { - for (const id in observationsViewData) { + function applyFilters(): void { + for (const observationId in observationsViewData) { + for (const viewData in observationsViewData[observationId]) { dataApi .getObservationData( props.studyId, - +id, - observationsViewData[id].selectedView, + +observationId, + observationsViewData[observationId][viewData].view.name, filterStudyGroup.value, filterParticipant.value, filterDateRange.value ? filterDateRange.value[0] : undefined, @@ -311,8 +294,8 @@ Licensed under the Elastic License 2.0. */ console.log('Response:', rs); const chartData = convertChartTypeData(rs.data); console.log('chartData:', chartData); - observationsViewData[id].chartType = rs.data.chartType; - observationsViewData[id].chartData = chartData; + observationsViewData[observationId][viewData].chartType = rs.data.chartType; + observationsViewData[observationId][viewData].chartData = chartData; console.log('observationsViewData:', observationsViewData); }); } @@ -340,7 +323,7 @@ Licensed under the Elastic License 2.0. */ function transformToPieChartData( observationDataViewData: ObservationDataViewData, ): ChartProperties | null { - if (!observationDataViewData.data.length) { + if (!observationDataViewData.data?.length) { return null; } @@ -352,7 +335,11 @@ Licensed under the Elastic License 2.0. */ }, title: { display: true, - text: observationDataViewData.view.title, + text: t(observationDataViewData.view.title), + }, + subtitle: { + display: true, + text: t(observationDataViewData.view.description), }, }, }; @@ -381,18 +368,59 @@ Licensed under the Elastic License 2.0. */ function transformToLineChartData( observationDataViewData: ObservationDataViewData, ): ChartProperties | null { - if (!observationDataViewData.data.length) { + if (!observationDataViewData.data?.length) { return null; } - // TODO - return null; + const chartOptions = { + responsive: false, + plugins: { + title: { + display: true, + text: t(observationDataViewData.view.title), + }, + subtitle: { + display: true, + text: t(observationDataViewData.view.description), + }, + }, + // scales: { + // y: { + // beginAtZero: true, + // ticks: { + // precision: 0, + // }, + // }, + // }, + }; + + const labels: string[] | null = formatDateLabels( + observationDataViewData.labels, + ); + + const obj = mergeStudyGroups(observationDataViewData.data); + const dataSets = []; + for (const [key, values] of Object.entries(obj)) { + dataSets.push({ + label: key, + data: replaceZeroValuesWithNull(values), + }); + } + + return { + type: 'line', + data: { + labels: labels, + datasets: dataSets, + }, + options: chartOptions, + } as ChartProperties; } function transformToBarChartData( observationDataViewData: ObservationDataViewData, ): ChartProperties | null { - if (!observationDataViewData.data.length) { + if (!observationDataViewData.data?.length) { return null; } @@ -406,6 +434,16 @@ Licensed under the Elastic License 2.0. */ }, }, }, + plugins: { + title: { + display: true, + text: t(observationDataViewData.view.title), + }, + subtitle: { + display: true, + text: t(observationDataViewData.view.description), + }, + }, }; const labels: string[] = observationDataViewData.labels; @@ -429,7 +467,33 @@ Licensed under the Elastic License 2.0. */ } as ChartProperties; } + function replaceZeroValuesWithNull( + values: (number | null)[], + ): (number | null)[] { + for (let i = 0, len = values.length; i < len; i++) { + if (values[i] === 0) { + values[i] = null; + } + } + + return values; + } + + function formatDateLabels(labels: string[]): string[] | null { + if (!labels) { + return null; + } + for (let i = 0, len = labels.length; i < len; i++) { + labels[i] = d(new Date(labels[i]), 'long'); + } + + return labels; + } + function mergeStudyGroups(groups: any[]): { [key: string]: number[] } { + if (!groups) { + return {}; + } return groups.reduce( (acc, group) => { if (acc[group.label]) { @@ -443,13 +507,6 @@ Licensed under the Elastic License 2.0. */ ); } - function getViewLabelByName(observationId: number, name: string): string | undefined { - console.log(observationId); - console.log(name); - const item = observationsViewData[observationId]?.possibleViews.find((el) => el.name === name); - return item ? item.title : undefined; - } - let factories: ComponentFactory[]; function getObservationTypeLabel(observationType: string): string { @@ -536,7 +593,7 @@ Licensed under the Elastic License 2.0. */ {{ $t('data.dataList.title') }} -
+
{{ $t('data.labels.dateRange') }}: @@ -603,46 +660,19 @@ Licensed under the Elastic License 2.0. */ /> -
+
-
- - -
-