From 652e0bb2caf558e2973afb40fd7c450581afd13e Mon Sep 17 00:00:00 2001 From: bnitsch Date: Wed, 10 Jul 2024 13:28:23 +0200 Subject: [PATCH 01/14] #377: Data Preview * Show visualisation of observation data in Charts --- openapi/StudyManagerAPI.yaml | 152 ++++- package-lock.json | 17 + package.json | 1 + src/components/ParticipationDataList.vue | 597 ++++++++++++++++-- src/components/TimelineList.vue | 10 +- .../subComponents/DatapointList.vue | 8 +- src/i18n/de.json | 31 + src/i18n/en.json | 31 + src/models/Common.ts | 12 + src/models/ParticipationData.ts | 48 ++ src/models/Timeline.ts | 6 +- src/styles/more-light/theme.pcss | 1 - 12 files changed, 833 insertions(+), 81 deletions(-) create mode 100644 src/models/Common.ts diff --git a/openapi/StudyManagerAPI.yaml b/openapi/StudyManagerAPI.yaml index 2a96a457..96b07046 100644 --- a/openapi/StudyManagerAPI.yaml +++ b/openapi/StudyManagerAPI.yaml @@ -1167,13 +1167,13 @@ paths: description: bad request /studies/{studyId}/data: + parameters: + - $ref: '#/components/parameters/StudyId' get: tags: - data description: Get Study Participation Data operationId: getParticipationData - parameters: - - $ref: '#/components/parameters/StudyId' responses: '200': description: Operation successful @@ -1186,14 +1186,71 @@ paths: '404': description: not found + /studies/{studyId}/observations/{observationId}/views: + parameters: + - $ref: '#/components/parameters/StudyId' + - $ref: '#/components/parameters/ObservationId' + get: + operationId: listObservationViews + description: "Get a list of available views" + tags: + - data + responses: + 200: + description: List of available Views + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ObservationDataView' + + /studies/{studyId}/observations/{observationId}/views/{viewName}: + parameters: + - $ref: '#/components/parameters/StudyId' + - $ref: '#/components/parameters/ObservationId' + - name: viewName + in: path + required: true + schema: + type: string + get: + tags: + - data + description: "Get observation view data" + operationId: getObservationViewData + parameters: + - name: studyGroupId + in: query + schema: + type: integer + required: false + - name: participantId + in: query + schema: + type: integer + required: false + - $ref: '#/components/parameters/From' + - $ref: '#/components/parameters/To' + responses: + '200': + description: Operation successful + content: + application/json: + schema: + $ref: '#/components/schemas/ObservationDataViewData' + '404': + description: not found + /studies/{studyId}/datapoints: + parameters: + - $ref: '#/components/parameters/StudyId' get: tags: - data description: Get Data Points operationId: getDataPoints parameters: - - $ref: '#/components/parameters/StudyId' - name: observationId in: query schema: @@ -1209,7 +1266,6 @@ paths: schema: type: string format: date-time - readOnly: true - name: size in: query schema: @@ -1283,6 +1339,7 @@ paths: application/json: schema: $ref: '#/components/schemas/FrontendConfiguration' + /config/buildInfo: get: tags: @@ -1669,6 +1726,52 @@ components: type: string format: date-time readOnly: true + + ObservationDataView: + type: object + properties: + name: + type: string + label: + type: string + title: + type: string + description: + type: string + required: + - name + + ObservationDataViewData: + type: object + properties: + view: + $ref: '#/components/schemas/ObservationDataView' + chartType: + type: string + enum: + - line + - bar + - pie + labels: + type: array + items: + type: string + data: + type: array + items: + $ref: '#/components/schemas/ObservationDataViewDataRow' + + ObservationDataViewDataRow: + type: object + properties: + label: + type: string + values: + type: array + items: + type: number + format: double + DataPoint: type: object properties: @@ -1795,6 +1898,28 @@ components: type: array items: $ref: '#/components/schemas/Intervention' + participants: + type: array + items: + $ref: '#/components/schemas/ParticipantInfo' + integrations: + type: array + items: + $ref: '#/components/schemas/IntegrationInfo' + + ParticipantInfo: + type: object + properties: + studyGroup: + type: integer + + IntegrationInfo: + type: object + properties: + name: + type: string + observationId: + $ref: '#/components/schemas/Id' UserSearchResultList: type: object @@ -1992,6 +2117,7 @@ components: required: - auth readOnly: true + BuildInfo: type: object properties: @@ -2058,6 +2184,24 @@ components: type: integer format: int32 required: true + DateTime: + name: dateTime + in: query + schema: + type: string + format: date-time + From: + name: from + in: query + schema: + type: string + format: date-time + To: + name: to + in: query + schema: + type: string + format: date-time securitySchemes: OAuth: diff --git a/package-lock.json b/package-lock.json index f2a63a5e..7ff0fb25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@vuepic/vue-datepicker": "8.6.0", "axios": "1.7.1", + "chart.js": "^4.4.3", "cron-validate": "1.4.5", "keycloak-js": "24.0.4", "normalize.css": "8.0.1", @@ -1260,6 +1261,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, "node_modules/@lukeed/csprng": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", @@ -4200,6 +4206,17 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "node_modules/chart.js": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", diff --git a/package.json b/package.json index 76c4f7f3..14787e83 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "dependencies": { "@vuepic/vue-datepicker": "8.6.0", "axios": "1.7.1", + "chart.js": "^4.4.3", "cron-validate": "1.4.5", "keycloak-js": "24.0.4", "normalize.css": "8.0.1", diff --git a/src/components/ParticipationDataList.vue b/src/components/ParticipationDataList.vue index aaa48c2f..f6f740b2 100644 --- a/src/components/ParticipationDataList.vue +++ b/src/components/ParticipationDataList.vue @@ -6,31 +6,58 @@ Licensed under the Elastic License 2.0. */ @@ -175,23 +580,95 @@ Licensed under the Elastic License 2.0. */ > {{ $t('data.dataList.title') }} + +
+
+
+ {{ $t('data.labels.dateRange') }}: + +
+
+ {{ $t('studyGroup.singular') }}: + +
+
+ {{ $t('participants.singular') }}: + +
+
+
+
+
+ - + + + + + +
+ + +
+
+
diff --git a/src/components/TimelineList.vue b/src/components/TimelineList.vue index ad38b13d..30f77df4 100644 --- a/src/components/TimelineList.vue +++ b/src/components/TimelineList.vue @@ -33,13 +33,9 @@ Licensed under the Elastic License 2.0. */ import { useErrorHandling } from '../composable/useErrorHandling'; import { dateToDateString } from '../utils/dateUtils'; import TimelineDialog from './dialog/TimelineDialog.vue'; - import { - DropdownOption, - GroupOption, - EventDetail, - EventOptions, - } from '../models/Timeline'; + import { GroupOption, EventDetail, EventOptions } from '../models/Timeline'; import { useGlobalStore } from '../stores/globalStore'; + import { DropdownOption } from '../models/Common'; const dialog = useDialog(); const dateFormat = useGlobalStore().getDateFormat; const { t, locale } = useI18n(); @@ -284,7 +280,7 @@ Licensed under the Elastic License 2.0. */ const filteredParticipants: Participant[] = []; filteredOptions.push({ - label: t('global.placeholder.entireStudy'), + label: t('participants.placeholder.allParticipants'), value: undefined, } as DropdownOption); diff --git a/src/components/subComponents/DatapointList.vue b/src/components/subComponents/DatapointList.vue index 48fc2add..4b406fa6 100644 --- a/src/components/subComponents/DatapointList.vue +++ b/src/components/subComponents/DatapointList.vue @@ -46,13 +46,13 @@ Licensed under the Elastic License 2.0. */ const participant: Ref