diff --git a/.github/workflows/test-build-push.yml b/.github/workflows/test-build-push.yml
index c4687bef..f6916d57 100644
--- a/.github/workflows/test-build-push.yml
+++ b/.github/workflows/test-build-push.yml
@@ -3,6 +3,10 @@ name: Test, Build and Publish
on:
push:
workflow_dispatch:
+ inputs:
+ dockerTag:
+ description: If set, docker img is built and tagged accordingly
+ required: false
env:
REGISTRY: ghcr.io
@@ -57,15 +61,15 @@ jobs:
- name: Check licenses
run: npm run license:check
-# - name: Run tests
-# run: npm run test:unit:once
-#
-# - name: Upload Test Results
-# if: always()
-# uses: actions/upload-artifact@v3
-# with:
-# name: Test Results
-# path: "target/testResults.xml"
+ # - name: Run tests
+ # run: npm run test:unit:once
+ #
+ # - name: Upload Test Results
+ # if: always()
+ # uses: actions/upload-artifact@v3
+ # with:
+ # name: Test Results
+ # path: "target/testResults.xml"
- name: Run build
run: npm run package
@@ -73,7 +77,7 @@ jobs:
build-and-push-image:
name: Build and Push Docker Image
runs-on: ubuntu-latest
- if: (github.ref_type == 'branch' && github.ref_name == 'main') || (github.ref_type == 'tag' && startsWith(github.ref_name, 'v'))
+ if: github.ref_name == 'main' || github.event.inputs.dockerTag != ''
needs:
- test
permissions:
@@ -97,7 +101,7 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
- type=raw,value=latest,enable={{is_default_branch}}
+ type=raw,value=${{github.event.inputs.dockerTag || 'latest'}}
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
diff --git a/docs/gherkin/absolute-scheduler_after-cleanup.md b/docs/gherkin/absolute-scheduler_after-cleanup.md
new file mode 100644
index 00000000..f012337c
--- /dev/null
+++ b/docs/gherkin/absolute-scheduler_after-cleanup.md
@@ -0,0 +1,32 @@
+# Manual integration Test: Clean up absolute scheduler
+
+### Background:
+- Study was created or exists.
+
+## Absolute Scheduler in SMF (updated version)
+
+| **Scenario** | **Given** | **Steps** | **Expected Result** | **Result** | **Note** |
+|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Open absolute schedule dialog | Observation Dialog is open |
WHEN I click on the button 'Add absolute Schedule',
| THEN the 'Manage absolute schedule' dialog opens. | as expected | |
+| Enter start and end for the schedule. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. |
WHEN I click the Start Date Picker, setting the date to 23.11.2023
AND click the Start Time Picker, setting the time to 10:00
AND click the End Date Picker, setting the date to 30.11.2023
AND click the End time Picker, setting the time to 18:00
AND clickclick save.
| THEN the start date and time and the end date and time should be displayed as 23/11/2023, 10:00 and 30/11/2023, 18:00. | as expected | |
+| Enter a start date that is after the end date. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. |
WHEN I click the start Date Picker
AND set it to 26.11.2023
| THEN both start and end date and time should display 26/11/2023, 12:00. | as expected | |
+| Set entire day checkbox. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. |
WHEN I click the Entire day checkbox (so that it's checked),
AND I click save.
| THEN the start time is set to 00:00 and the end time is set to 23:59. | as expected | |
+| Set Individual observation checkbox. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. |
When I click the Individula Observation checkbox to checked.
AND I click save.
| THEN the End will be collapsed and it will show the start date 23/11/2023, with start time 12:00 and end time 15:00. The end date has been changed to the start date as well. | as expected | |
+| Set Individual observation and entire day checkbox. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. |
WHEN I check the entire day checkbox to checked
AND the individual observation checkbox to checked
| THEN the end will be collapsed and it will show the start date 23/11/2023, with start time 00:00 and end time 23:59. The end date has been changed to the start date as well. | as expected | |
+| Toggle Repeat observation | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. |
WHEN I click individual observation
| THEN the repeat observation event option appears. | as expected | |
+| Check repeat options. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. Individual observation is checked. |
WHEN I click repeat
| THEN a switch button with options Daily and Weekly appears. | as expected | |
+| Check repeat error messages when daily is clicked. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. Individual observation and repeat checkboxes are checked. |
WHEN i click on Daily
| THEN the repetition end options appear with Until end of study and after. A error message is displayed beneath that informs the user to set an end to the repetition period. | as expected | |
+| Check repeat error messages when weekly is clicked. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. Individual observation and repeat checkboxes are checked. |
WHEN i click on Weekly
| THEN the Weekdays are displayed. Beneath them is an error message that reminds the user to set weekdays for the repetition And the repetition end options appear with Until end of study and after. A error message is displayed beneath that informs the user to set an end to the repetition period. | as expected | |
+| Check repeat error messages when weekly and weekdays are chosen. | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. Individual observation and repeat checkboxes are checked. Weekly is chosen |
WHEN I click on at least one weekday
| THEN the error beneath the weekdays dissapears. | as expected | |
+| Check repeat error message when Repetition ends is chosen. - Until end of study | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. Individual observation and repeat checkboxes are checked. |
WHEN I click daily
OR Weekly with at least one week day selected
AND click 'until end of study'
AND until end of study
| THEN all errors are gone from the 'Manage absolute schedule' dialog. | as expected | |
+| Check repeat error messages when Repetition ends is chosen. - After | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. Individual observation and repeat checkboxes are checked. |
WHEN I click daily
OR Weekly with at least one week day selected
AND I click 'After'
| THEN and input field with either day(s) or week(s) (based on chosen repetition: daily, weekly) with an error message below is displayed. | as expected | |
+| Check repeat error messages when Repetition ends is chosen. - After, count | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. start is set to 23.11.2023, 12:00 and end is set to 24.11.2023, 15:00. Individual observation and repeat checkboxes are checked. |
WHEN I click daily
OR Weekly with at least one week day selected
AND 'After'
AND enter a number in the count input field
| THEN all errors are gone from the 'Manage absolute schedule' dialog. | 21.11.2023: BUG
22.11.2023: as expected | 21.11.2023: BUG-1: Absoule Schedule repeat values don't reset, when indeividual observation is unchecked when one enters the dates as described, but in the same "session" (without saving and closing the manage absolute schedule dialog) had the individual observation, repeat Daily/weekly. Until end of study/after selected or filled out and THEN unchecks Individual Observation again and saves, all the repeat event values still get saved and displayed
22.11.2023: Bug was fixed. |
+| Save absolute scheduler. - Start and end Date | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. |
WHEN I set the start date to 23.11.2023, 10:00
AND the end date to 25.11.2023, 18:00
AND click on save
| THEN the observation dialog should show the Absolute schedule preview with Start: 23/11/2023, 10:00 and End: 25/11/2023, 18:00 | as expected | |
+| Save absolute scheduler. - Individual Observation | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023 |
WHEN I set individaul observation to checked
AND set the date to 23.11.2023
AND start time to 11:00
AND end time to 15:00
AND click on save
| THEN the observation dialog should show the Absolute schedule preview with Start: 23/11/2023, 11:00 and End: 23/11/2023, 15:00 | as expected | |
+| Save absolute scheduler. - Entire Day | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023 |
WHEN I set entire day to checked
AND set the start date to 23.11.2023
AND set the end date to 25.11.2023
AND click on save
| THEN the observation dialog should show the Absolute schedule preview with Start: 23/11/2023, 00:00 and End: 25/11/2023, 23:59 | as expected | |
+| Save absolute scheduler. - Repetition Daily, after | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. Initial values: Start: 23.11.2023, 11:00 and End: 23.11.2023, 15:00 |
WHEN I click individual observation
AND check repeat
AND set repetiton to daily
AND set Repetition ends to After 14 day(s)
AND click save
| THEN the observation dialog should show the Absolute schedule preview with Start: 23/11/2023, 11:00 and End: 23/11/2023, 15:00. And the repetition values of Every: day, Ends in 14 day(s). | as expected | |
+| Save absolute scheduler. - Repetition Weekly, after | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. Initial values: Start: 23.11.2023, 11:00 and End: 23.11.2023, 15:00 |
WHEN I click individual Observation
AND check repeat
AND set repetiton to weekly
AND choose MO, WE and SA for the weekdays
AND set Repetition ends to After 11 day(s)
AND click save
| THEN the observation dialog should show the Absolute schedule preview with Start: 23/11/2023, 11:00 and End: 23/11/2023, 15:00. And the repetition values of Every: week, Selected days: MO, WE, SA, Ends in 11 week(s). | 21.11.2023: BUG
22.11.2023: as expected | 21.11.2023: BUG-2: Absolute Schedule can be saved without After value (in specific situations) In certain circumstances it is possible to save when no value is entered in the after section. In this case when one clicks the field (without entering anything) then clicks on until end of study. Then the error should go away. then the user can save without having anything entered.
22.11.2023: Bug was fixed. |
+| Save absolute scheduler. - Repetition Daily, until study end | Manage absolute schedule dialog is open. Planned study start is before 23.11.2023 and planned end is after 30.11.2023. Initial values: Start: 23.11.2023, 11:00 and End: 23.11.2023, 15:00 |
WHEN I click individual Observation
AND check repeat
AND set repetiton to daily
AND set Repetition ends to until end of study
AND click save
| THEN the observation dialog should show the Absolute schedule preview with Start: 23/11/2023, 11:00 and End: 23/11/2023, 15:00. And the repetition values of Every: day, Ends on 'Date of Planned end of study' | as expected | |
+| Save observation and check data. - Without repetition | Manage observation dialog is open. Scheduler was entered with following values: Planned study start is before 23.11.2023 and planned end is after 30.11.2023. Initial values: Start: 23.11.2023, 11:00 and End: 23.11.2023, 15:00 |
WHEN I enter a observation title
AND I created an absolut schedule with the values described in 'GIVEN'
AND I enter participant information
AND click save on the observation dialog
AND click the cog icon (settings) of the created observation inside the observation list.
| THEN the observation dialog shows the absolute scheudle preview with following data: Start: 23/11/2023, 11:00 and End: 23/11/2023, 15:00 | as expected | |
+| Save observation and check data. - With repetition | Manage observation dialog is open. Scheduler was entered with following values: Planned study start is before 23.11.2023 and planned end is after 30.11.2023. Initial values: Start: 23.11.2023, 11:00 and End: 23.11.2023, 15:00, repetition values: Every: week, Selected days: MO, WE, SA, Ends in 11 day(s). |
WHEN I click save on the observation dialog
AND open the created observation inside the observation list again.
| THEN the observation dialog shows the absolute scheudle preview with following data: Start: 23/11/2023, 11:00 and End: 23/11/2023, 15:00; Repetition values: Every: week, Selected days: MO, WE, SA, Ends in 11 day(s). | as expected | |
+
diff --git a/docs/gherkin/relative-scheduler_manual-integration-test.md b/docs/gherkin/relative-scheduler_manual-integration-test.md
new file mode 100644
index 00000000..19de1bb2
--- /dev/null
+++ b/docs/gherkin/relative-scheduler_manual-integration-test.md
@@ -0,0 +1,80 @@
+# Manual integration Test for Relative Scheduler Feature
+
+### Background:
+- Study was created or exists.
+
+## Realtive Scheduler in SMF
+
+| **Scenario** | **Given** | **Steps** | **Expected Result** | **Result** | **Notes** |
+|-----------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Open relative schedule dialog | Observation Dialog is open |
WHEN I click on the button 'Add relative Schedule',
| THEN the 'Manage relative schedule' dialog opens. | 21.11.2023: ✅ | Wording improvement implemented:
changed wording to Starts on day 3 / Ends on day 3 instead of starts on 3 day(s) / Ends on 3 day(s)
|
+| 'Save' start and end from 'Managae relative Schedule' dialog. | Manage relative schedule dialog is open. |
WHEN I set 'Starts on' 'Date' to 'Day 2'
AND the 'Starts on' 'Time' to '09:00',
AND the 'Ends on' to 'Day 3'
AND the 'Ends on' 'Time' to '18:00',
AND click the 'Save' Button,
| THEN the 'Manage relative schedule' dialog should close and the observation dialog should display the preview for 'Individual Event' under Scheduler with the entered values (Starsts on: Day 2, 9:00; Ends on: Day 3, 18:00). | 21.11.2023: ✅ | - |
+| 'Save' observation with simple relative schedule. | Manage relative schedule dialog is open and the values for starts on and ends on are already entered ('Starst on': Day 2, 9:00; 'Ends on': Day 3, 18:00). |
WHEN I fill out all required fields for the observation
AND click 'Save' on the 'observation dialog'
| THEN the Observation List shown should update and show now the new created observation with the Schedule data: 'Type': Relative, 'Start': Day 2, 9:00; 'End': Day 3, 18:00 | 21.11.2023: ✅ | Wording improvement implemented:
Schedule Type is displayed as: 'RelativeEvent'. Inserted a translation for Event and RelativeEvent Enums
|
+| Check schedule data inside the observation dialog of observation in observation list, that has a relative schedule. | Observation list does have already an item inside the list that has a relative schedule. |
WHEN i click on an observation in the list, that has a relative schedule
| THEN the observatin dialog opens and shows the exact same data displayed inside the list for the schedule preview. | 21.11.2023: ✅ | - |
+| Check schedule data inside the 'Manage relative Schedule' dialog of observation in observation list, that has a relative schedule | Observation list does have already an item inside the list that has a relative schedule. |
WHEN I click on an observation in the list, that has a relative schedule
AND click on the 'EDIT relative schedule' button on the observation dialog
| THEN the 'Manage relative schedule' dialog opens and shows the exact same data displayed inside the observation list for the scheduler values. |21.11.2023: ✅ | - |
+| Cancel start and end from 'Manage relative Schedule' dialog. | Manage relative schedule dialog is open. No schedule was saved for that specific observation yet. |
WHEN I set 'Starts on' 'Date' to 'Day 2'
AND the 'Starts on' 'Time' to '09:00',
AND the 'Ends on' to 'Day 3'
AND the 'Ends on' 'Time' to '18:00',
AND click the 'Cancel' Button,
| THEN the 'Manage relative schedule' dialog should close and and the observation dialog should display no preview for the scheduled time. The default information text is displayed underneath of the Schedule title. | 21.11.2023: ✅ | - |
+| Update relative schedule and add repetition. | Observation dialog is open and has already a relative schedule (initial values: 'Starst on': Day 2, 10:30; 'Ends on': Day 2, 18:30). |
WHEN I click on "Edit relative schedule'
AND check 'repeat event'
AND set repeat every to 2
AND set end after to 9
AND click on save
| THEN the observation dialog should list the individual event with Starts on Day 2, 10:30 and Ends on Day 2, 18:30, and the repeat event with Every 2 day(s) and ends on Day 9. | 21.11.2023: ✅ | - |
+| Updating calculations when editing 'repeat event' | Manage relative schedule dialog is open. Initial values entered: 'Starts on': 2 day, 10:30; 'Ends on': 2 day, 18:30 |
WHEN I click the 'repeat event checkbox'
and enter 2 into the field next to 'Repeat every'
AND select I select 9 into the input field next to 'End after'
| THEN the information displayed right to the repetition values show Repeated: 5 times, End's 10 days after individual study start. | 21.11.2023: ✅ | - |
+| Updating calculations when editing 'repeat event', when changing the unit value. | Manage relative schedule dialog is open and for starts on and ends on are already inital values entered ('Starst on': Day 2, 9:00; 'Ends on': Day 3, 18:00). |
WHEN I select a different unit in the dropdown for either repeat every and/or end after
| THEN the information on the right side is calculated anew based on the new values. | 21.11.2023: ✅ | - |
+| Remove relative scheduler from observation dialog. | Observation dialog is open and has already an realtive schedule entered in. |
WHEN I click the button 'Remove scheduler'
| THEN the scheduler values should have been deleted from the observation, the preview is gone and the default information text is displayed again. | 21.11.2023: ✅ | - |
+| Save the observation with no preentered schedule. | Observation dialog is open and the required fields are filled in, except a defined scheduler. |
WHEN I click the save button on the observation dialog
| THEN the observation dialog closes and saves the observation with the planned start and planned end of the study as absolute schedule for the observation. The observation list shows the created observation with the Schedule Type Event and the planned start and planned end as start and end of the observation. | 21.11.2023: ✅ | - |
+
+
+## ICal Export / More App
+
+### Background:
+- Study was crated with a study duration of 10 days.
+
+### Observaion Background:
+| Observation | Schedule Type | Start | End | Repetition: Every | Repetition: days | Repetition: ends | **Result Ical Output** | **Note** |
+|-----------------------------------------------------------------------|---------------|-------------------|--------------------------------|-------------------|---------------------|----------------------|----------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Simple Question: Absolute (no repetition) | Absolute | current day, 8:00 | 26.11.2023, 18:00 | - | - | - | 21.11.2023: ✅ | |
+| Simple Question: 'Absolute: daily for 10 days' | Absolute | 23.11.2023, 8:00 | 14:00 (Individual Observation) | daily | - | after 10 days | 21.11.2023: ✅ | |
+| Simple Question: 'Absolute: weekly (Mo, Fr) for 20 weeks' | Absolute | 23.11.2023, 16:00 | 18:00 (Individual Observation | Weekly | Mo, Fr | 20 weeks (40 times) | 21.11.2023: Bugreport
22.11.2023: ✅ | 21.11.2023 BUG: If absolute schedule repetition goes beyond the study duration, the observation schedule is sshown inside the ICal until repetition ends, ignoring the study end date
22.11.2023: Bug was fixed. |
+| Simple Question: 'Absolute (repetition: weekly, until end of study)' | Absolute | 21.11.2023, 08:00 | 12:00 (Individual Observation | MO, WE, FR | Until end of study | | 21.11.2023: ✅ | |
+| Simple Question: 'Relative (no repetition)' | Relative | Day 2, 12:00 | Day 4, 13:00 | - | - | - | 21.11.2023: Time Bug
22.11.2023: ✅ | TIME BUG: Time is set one hour after sceduled time -> 13:00, 14:00
22.11.2023: Bug was fixed |
+| Simple Question: 'Relative (repetition: 3 days, after 12 times)' | Relative | Day 3, 6:00 | Day 3, 18:00 | 3 days | - | 35 day(s) (12 times) | 21.11.2023: It stops after study duration ended ✅
21.11.2023: Time Bug
22.11.2023: ✅ | same as above |
+| Simple Question: 'Relative (repetition: 1 hour, after 32 times)' | Relative | Day 4, 6:15 | Day 4, 6:30 | 1 hour | - | 32 hours (32 times) | 21:11.2023: It repeates 32 times ✅
21.11.2023: Time Bug
22.11.2023: ✅ | same as above |
+| Simple Question: 'Relative (repetition: 1 min, after 1 hour)' | Relative | Day 1, 7:00 | Day 1, 7:01 | 1 min |- | 1 hour | 21:11.2023: It repeates 60 times ✅
21.11.2023: Time Bug
22.11.2023: ✅ | same as above |
+
+### Testing Scenarios / Results
+| **Scenario** | **Given** | **Steps** | **Expected Result** | **Result** | **Note** |
+|--------------------------------------------------------------------------|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Check ICal export after creating several observations | see background info |
WHEN I have configered all in background listed observations
AND click on the Ical export of the study
| THEN a Ical export data is downloaded, that shows (after import into outlook) all the observations in correct order. | 21.11.2023: BUG
22.11.2023: ✅ | 21.11.2023:
BUG: Absolute Scheduler shows in Observation List End, the start time
BUG: Time of relative schedule has a offset of 1 hour
2022.11.2023: Bug was fixed. |
+| Check if App Observations are scheduled the same way as the ICal export. | see background info Ical was already exported |
WHEN I have configered all in background listed observations
AND have checked the ICal exprt
AND have logged into the study as participant
| THEN the active observations are scheduled and shown based on the observation settings. The scheduled observations on the app have the same dates and times as the Ical export. | 22.11.2023: BUG
23.11.2023: ✅ | 21.11.2023: BUG If you log in for the first time the schedule is empty. After study is paused and resumed on the study manager the schedules are shown.
23.11.2023: Bug was fixed |
+
+Download ical without button: https://data.platform-test.more.redlink.io/api/v1/calendar/studies/[STUDY-ID]/calendar.ics
+
+Studymanager App Backend-Test - Study-Endpoint: https://data.platform-test.more.redlink.io/api/v1
+
+### More App: Additional Observation examples
+
+ Just some more examples for observation settings - use if needed - initial test is
+
+### Background SMF Configuration
+- Study planned start: before 21:11.2023
+- Study planned end: 31.12.2023
+
+|Observation|Schedule Type| Start | End | Repetition: Every |Repetition: days| Repetition: ends |
+|---|---|--------------------|---------------|-------------------|---|------------------|
+|Simple Question|Absolute| current day, 8:00 | 25.11.2023, 18:00 | - |-| - |
+|Simple Question|Absolute| current day, 9:00 | current day, 10:00 | daily |-| after 10 days |
+|Simple Question|Absolute| current day, 12:00 | current day, 13:00 | weekly |MO, TUE| after 3 weeks |
+|Simple Question|Relative| Day 1, 15:00 | Day 2, 19:00 | - |-| - |
+|Simple Question|Relative| Day 2, 7:00 |Day 2,7:15| 1 hour |-| 12 hours |
+|Simple Question|Relative| Day 4, 8:00 |Day 5,10:00|3 day|-|20 days|
+
+## App: Study Ends automatically for relative study duration
+
+ | **Scenario** | **Given** | **Steps** | **Expected Result** | **Result** | **Note** |
+|--------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------|
+| Check if study ends automatically for relative scheduled study & observations. | Study was configured with duration: 1 minute and some participants were created. Current app was installed on a mobile device. |
WHEN I log in as a participant into the configured study with duration of 1 minute
| THEN the study closes after 1 minute and sends a message to the participant that the study is over now. The More-App should show only the end message on the schedule overview screen. | 22.11.2023: ✅ | |
+|Check if data is collected and study ends automatically. | Study was configured with a duration of 10 minutes and some participants were created. Study has a Question observation with start: current day & time and end: current day & time + 30 minutes. Current app was installed on a mobile device. |
WHEN i log in as a participant into the study
AND answer the question observation
AND wait for 10+ minutes
|THEN the study has recieved my answer data in the backend AND has closed after 10 minutes on the app.| 22.11.2023: ✅ ||
+
+
+## SMF Compatibility
+| **Scenario** | **Given** | **Steps** | **Expected Result** | **Result** | **Note** |
+|----------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Check if the backend works with the original frontend without the feature. | A study was created with participants, 1-2 study grousp, and 1-2 observations each for absolute and relative schedule (see examples above). |
AFTER the study was created as described
AND I check out the former development status from the Main branch
AND run it locally with the current SMB
| THEN the Study Manager frontend should run without errors on study overview, study group list, observations (+scheduler) or interventions. | 22.11.2023: FAILED | Error:
"JSON parse error: Could not resolve subtype of [simple type, class io.redlink.more.studymanager.api.v1.model.ObservationScheduleDTO]: missing type id property 'type' (for POJO property 'schedule')"
All Branches need to be deployed together for the feature. ||
+|
+
diff --git a/openapi/Event.yaml b/openapi/Event.yaml
index 8f9ba706..33b0dc87 100644
--- a/openapi/Event.yaml
+++ b/openapi/Event.yaml
@@ -9,6 +9,9 @@ components:
Event:
type: object
properties:
+ type:
+ type: string
+ default: Event
dtstart:
type: string
format: date-time
diff --git a/openapi/RelativeEvent.yaml b/openapi/RelativeEvent.yaml
new file mode 100644
index 00000000..2e6833f1
--- /dev/null
+++ b/openapi/RelativeEvent.yaml
@@ -0,0 +1,62 @@
+openapi: "3.0.3"
+info:
+ title: TimeRange Model for Relative Events
+ version: "1.0"
+
+components:
+ schemas:
+ Duration:
+ type: object
+ description: A duration of time
+ properties:
+ value:
+ type: integer
+ description: number of units
+ unit:
+ type: string
+ description: unit of time
+ enum:
+ - MINUTE
+ - HOUR
+ - DAY
+ RelativeDate:
+ type: object
+ description: A date relative to a specific base date (e.g study start)
+ properties:
+ offset:
+ $ref: '#/components/schemas/Duration'
+ time:
+ type: string
+ format: time
+ description: Follows ISO 8601 format for time
+ RelativeRecurrenceRule:
+ type: object
+ description: A recurrence rule relative to dtstart
+ properties:
+ frequency:
+ $ref: '#/components/schemas/Duration'
+ description: How often to repeat
+ endAfter:
+ $ref: '#/components/schemas/Duration'
+ description: How long to repeat
+
+ RelativeEvent:
+ type: object
+ description: An event that occurs at a relative time
+ required:
+ - type
+ - dtstart
+ - dtend
+ properties:
+ type:
+ type: string
+ default: RelativeEvent
+ dtstart:
+ $ref: '#/components/schemas/RelativeDate'
+ description: When the event starts
+ dtend:
+ $ref: '#/components/schemas/RelativeDate'
+ description: When the event ends
+ rrrule:
+ $ref: '#/components/schemas/RelativeRecurrenceRule'
+ description: How to repeat the event
diff --git a/openapi/StudyManagerAPI.yaml b/openapi/StudyManagerAPI.yaml
index d36dbb8e..40fb4c95 100644
--- a/openapi/StudyManagerAPI.yaml
+++ b/openapi/StudyManagerAPI.yaml
@@ -1277,6 +1277,8 @@ components:
type: string
consentInfo:
type: string
+ duration:
+ $ref: '#/components/schemas/StudyDuration'
finishText:
type: string
status:
@@ -1354,6 +1356,8 @@ components:
type: string
purpose:
type: string
+ duration:
+ $ref: '#/components/schemas/StudyDuration'
numberOfParticipants:
type: integer
readOnly: true
@@ -1365,7 +1369,18 @@ components:
type: string
format: date-time
readOnly: true
-
+ StudyDuration:
+ type: object
+ properties:
+ value:
+ type: integer
+ unit:
+ type: string
+ description: unit of time
+ enum:
+ - MINUTE
+ - HOUR
+ - DAY
Participant:
type: object
properties:
@@ -1422,7 +1437,16 @@ components:
type: object
additionalProperties: true
schedule:
- $ref: './Event.yaml/#/components/schemas/Event'
+ oneOf:
+ - $ref: './Event.yaml/#/components/schemas/Event'
+ - $ref: './RelativeEvent.yaml/#/components/schemas/RelativeEvent'
+ discriminator:
+ propertyName: type
+ # mapping:
+ # event:
+ # $ref: './Event.yaml/#/components/schemas/Event'
+ # relativeEvent:
+ # $ref: './RelativeEvent.yaml/#/components/schemas/RelativeEvent'
created:
type: string
format: date-time
@@ -1514,7 +1538,11 @@ components:
purpose:
type: string
schedule:
- $ref: './Event.yaml/#/components/schemas/Event'
+ oneOf:
+ - $ref: './Event.yaml/#/components/schemas/Event'
+ - $ref: './RelativeEvent.yaml/#/components/schemas/RelativeEvent'
+ discriminator:
+ propertyName: type
trigger:
$ref: '#/components/schemas/Trigger'
actions:
diff --git a/src/components/ObservationList.vue b/src/components/ObservationList.vue
index c6fda644..81f80ed4 100644
--- a/src/components/ObservationList.vue
+++ b/src/components/ObservationList.vue
@@ -8,7 +8,10 @@ Licensed under the Elastic License 2.0. */
import { useComponentsApi, useObservationsApi } from '../composable/useApi';
import {
ComponentFactory,
+ Event,
Observation,
+ ObservationSchedule,
+ RelativeEvent,
StudyGroup,
StudyRole,
StudyStatus,
@@ -32,6 +35,8 @@ Licensed under the Elastic License 2.0. */
import { useI18n } from 'vue-i18n';
import { useErrorHandling } from '../composable/useErrorHandling';
import DeleteMoreTableRowDialog from './dialog/DeleteMoreTableRowDialog.vue';
+ import dayjs from 'dayjs';
+ import { ZTimeStringToOffsetTimeString } from '../utils/dateUtils';
const loader = useLoader();
const { observationsApi } = useObservationsApi();
@@ -122,19 +127,30 @@ Licensed under the Elastic License 2.0. */
editable: true,
},
{
- field: 'schedule.dtstart',
+ field: 'scheduleType',
+ header: t('global.labels.scheduleType'),
+ columnWidth: '3vw',
+ sortable: true,
+ },
+ {
+ field: 'scheduleStart',
header: t('global.labels.start'),
- type: MoreTableFieldType.nestedDatetime,
columnWidth: '3vw',
sortable: true,
},
{
- field: 'schedule.dtend',
+ field: 'scheduleEnd',
header: t('global.labels.end'),
- type: MoreTableFieldType.nestedDatetime,
columnWidth: '3vw',
sortable: true,
},
+ {
+ field: 'hasRepetition',
+ header: t('scheduler.labels.repeat'),
+ type: MoreTableFieldType.binaryIcon,
+ columnWidth: '2vw',
+ sortable: true,
+ },
];
const tableActions: MoreTableAction[] = [
@@ -230,10 +246,16 @@ Licensed under the Elastic License 2.0. */
typeLabel: getObservationTypeString(item.type as string),
properties: item.properties,
schedule: item.schedule,
+ scheduleType: item.schedule?.type
+ ? t(`scheduler.type.${item.schedule?.type}`)
+ : '',
+ scheduleStart: getScheduleDate(item.schedule, 'dtstart'),
+ scheduleEnd: getScheduleDate(item.schedule, 'dtend'),
created: item.created,
modified: item.modified,
hidden: item.hidden,
noSchedule: item.noSchedule,
+ hasRepetition: getScheduleHasRepetition(item.schedule),
};
});
})
@@ -242,6 +264,75 @@ Licensed under the Elastic License 2.0. */
);
}
+ function getScheduleHasRepetition(
+ schedule: ObservationSchedule | undefined
+ ): boolean {
+ if (schedule) {
+ switch (schedule.type) {
+ case 'Event': {
+ const s = schedule as Event;
+ return !!s.rrule;
+ }
+ case 'RelativeEvent': {
+ const s = schedule as RelativeEvent;
+ return !!s.rrrule;
+ }
+ }
+ }
+ return false;
+ }
+
+ function getScheduleDate(
+ scheduler: ObservationSchedule | undefined,
+ prop: string
+ ) {
+ switch (scheduler?.type) {
+ case 'Event': {
+ const schedule = scheduler as Event;
+ switch (prop) {
+ case 'dtstart':
+ return schedule.dtstart
+ ? `${dayjs(schedule.dtstart).format('DD/MM/YYYY')}, ${dayjs(
+ schedule.dtstart
+ ).format('HH:mm')}`
+ : undefined;
+ case 'dtend':
+ return schedule.dtend
+ ? `${dayjs(schedule.dtend).format('DD/MM/YYYY')}, ${dayjs(
+ schedule.dtend
+ ).format('HH:mm')}`
+ : undefined;
+ default:
+ return undefined;
+ }
+ }
+ case 'RelativeEvent': {
+ const schedule = scheduler as RelativeEvent;
+ switch (prop) {
+ case 'dtstart':
+ return schedule.dtstart.offset?.value &&
+ schedule.dtstart.offset?.unit
+ ? `${t(
+ `scheduler.preview.unit.${schedule.dtstart.offset.unit}`
+ )} ${
+ schedule.dtstart.offset.value
+ }, ${ZTimeStringToOffsetTimeString(schedule.dtstart.time)}`
+ : undefined;
+ case 'dtend':
+ return schedule.dtend.offset?.value && schedule.dtend.offset?.unit
+ ? `${t(`scheduler.preview.unit.${schedule.dtend.offset.unit}`)} ${
+ schedule.dtend.offset.value
+ }, ${ZTimeStringToOffsetTimeString(schedule.dtend.time)} `
+ : undefined;
+ default:
+ return undefined;
+ }
+ }
+ }
+
+ return '';
+ }
+
function execute(action: any) {
switch (action.id) {
case 'delete':
@@ -372,7 +463,6 @@ Licensed under the Elastic License 2.0. */
openObservationDialog(dialogTitle, observation);
}
}
-
listObservations();
diff --git a/src/components/StudyCollaboratorList.vue b/src/components/StudyCollaboratorList.vue
index 2f5b22ce..f4ec1d6a 100644
--- a/src/components/StudyCollaboratorList.vue
+++ b/src/components/StudyCollaboratorList.vue
@@ -336,6 +336,7 @@ Licensed under the Elastic License 2.0. */
@@ -231,6 +256,14 @@ Licensed under the Elastic License 2.0. */
+
diff --git a/src/components/shared/Scheduler.vue b/src/components/shared/Scheduler.vue
index 2ee23bcd..bab49c4d 100644
--- a/src/components/shared/Scheduler.vue
+++ b/src/components/shared/Scheduler.vue
@@ -4,18 +4,15 @@ Prevention -- A research institute of the Ludwig Boltzmann Gesellschaft,
Oesterreichische Vereinigung zur Foerderung der wissenschaftlichen Forschung).
Licensed under the Elastic License 2.0. */
-
+
diff --git a/src/i18n/de.json b/src/i18n/de.json
index 8e36b22f..528483d5 100644
--- a/src/i18n/de.json
+++ b/src/i18n/de.json
@@ -34,7 +34,8 @@
"to": "zu",
"message": "Nachricht",
"option": "Option",
- "data": "Daten"
+ "data": "Daten",
+ "scheduleType": "Zeitplan-Typ"
},
"placeholder": {
"entireStudy": "Gesamte Studie",
@@ -84,6 +85,7 @@
"purpose": "Zielsetzung",
"status": "Status",
"roles": "Rolle(n)",
+ "duration":"Studiendauer",
"plannedStart": "Geplanter Start",
"actualStart": "Aktueller Start",
"plannedEnd": "Geplantes Ende",
@@ -94,6 +96,11 @@
"studyGroup": "Studiengruppe",
"finishText": "Information nach Studienabschluss"
},
+ "ical": {
+ "copyMsg": "Link für das Kallender Abbonement ('{title} (Id: {studyId})') wurde kopiert.",
+ "title": "Kalender link für Abbonnements",
+ "copyTitle": "Link kopieren"
+ },
"roles": {
"admin": "Studien-Administrator",
"operator": "Studien-Operator",
@@ -107,7 +114,7 @@
"changeMsg": {
"toActive":{
"intro": "Sie sind im Begtriff den Studienstatus auf 'AKTIV' zu setzen.",
- "warning": "Eine auf 'AKTIV' gesetzte Studie setzt alle Datenerhebungsmodule, Interventionen und Zeitplaneinstellungen auf aktiv und ermöglicht so das aktive Aufzeichnen von Daten. Die Teilnehmer:innen können sich ab diesem Zeitpunkt in der App anmelden und aktiv teilnehmen. Eine auf aktiv gesetzte Studie kann pausiert werden, um Änderungen an den Einstellungen und Konfigurationen vorzunehmen.",
+ "warning": "Eine auf 'AKTIV' gesetzte Studie setzt alle Datenerhebungsmodule, Interventionen und Zeitplaneinstellungen auf aktiv und ermöglicht so das aktive Aufzeichnen von Daten. Die Teilnehmer:innen können sich ab diesem Zeitpunkt in der App anmelden und aktiv teilnehmen. Eine auf aktiv gesetzte Studie kann pausiert werden, um Änderungen an den Einstellungen und Konfigurationen vorzunehmen. Ist der geplante Start nach dem heutigen Datum, wird dieser mit der Statusänderung auf das aktuelle Startdatum gesetzt.",
"confirm": "Diese Statusänderung kann nicht wieder zurückgesetzt werden. Möchten Sie den Studienstatus wirklich auf 'AKTIV' setzen?"
},
"toPaused":{
@@ -142,6 +149,7 @@
},
"error": {
"addTitle": "Der Studientitel ist ein erforderliches Feld. Bitte fügen Sie einen Titel hinzu.",
+ "addDuration": "Bitte fügen Sie einen Wert und eine Einhait im Feld hinzu.",
"addConsentInfo": "Die Berechtigungsinformation ist ein erforderliches Feld. Bitte fügen Sie eine Beschreibung hinzu.",
"addParticipantInfo": "Die Teilnehmerinformation ist ein erforderliches Feld. Bitte fügen Sie eine Beschreibung hinzu.",
"addContactInfo": "Bitte fügen Sie eine Kontaktperson und eine Emailadresse ein.",
@@ -151,6 +159,7 @@
"placeholder": {
"titleInput": "Bitte geben Sie einen kurzen Titel ein.",
"purposeInput": "Stellen Sie eine kurze Beschreibung Ihres Forschungszwecks für Ihre Studien-Mitarbeiter bereit.",
+ "durationInput": "Bitte geben Sie eine Studiendauer ein.",
"participantInfoInput": "Stellen Sie Informationen für Ihre Studienteilnehmer bereit. Dies Beschreibung wird den Teilnehmern:innen auf der App angezeigt.",
"consentInfoInput": "Stellen Sie Informationen über die zu sammelnden Daten bereit. Dies wird den Teilnehmern:innen als Beschreibungstext der generellen Studienberechtigungen in der App angezeigt.",
"selectLanguage": "Sprache auswählen",
@@ -174,6 +183,7 @@
},
"label": {
"studyTitle": "Studientitel",
+ "durationExample": "Beispiel der Studiendauer",
"studyStart": "Studienstart",
"studyEnd": "Studienende",
"contactInfo": "Kontaktinformationen",
@@ -193,6 +203,8 @@
},
"description": {
"study": "Fügen Sie eine Beschreibung der Studie hinzu, die Ihren Studienmitarbeitern als Erkärung angezeigt wird.",
+ "duration": "Die Studiendauer ist der Zeitraum, in dem die Teilnehmer aktiv zur Datenerhebung beitragen. Dies ist wichtig, wenn relative Beobachtungen verwendet werden. Wenn keine Studiendauer angegeben ist, wird die gesamte Zeit vom Studienbeginn bis zum Ende der Studie als Sudiendauer betrachtet",
+ "durationExample": "Studienbeginn; 01.07.2023 - Studienende: 31.12.2023 (5 Monate) - Studiendauer: 4 Wochen\nDie aktive Teilnahmezeit des Teilnehmers an der Studie ist auf 4 Wochen begrenzt. Dies wird durch das Login-Datum bestimmt.",
"purpose": "Die Zielsetzung gibt Informationen über die Studie. Diese Information ist nur den Studien-Mitarbeitern zugänglich.",
"participantInfo": "Die Teilnehmerinformation wird in der App den Teilnehmer:innen angezeigt. Sie soll eine kurze Beschreibung über die Studie und ihren Aufgaben enthalten.",
"consentInfo": "Die Berechtigungsinformation wird in der App den Teilnehmer:innen angezeigt. Sie muss von diesen akzeptiert werden, um über die App Daten aufzeichnen zu dürfen.",
@@ -240,7 +252,10 @@
"placeholder": {
"title": "Stellen Sie einen Titel bereit",
"purpose": "Beschreiben Sie die Zielsetzung für diese Gruppe",
- "emptyGroupList": "Fügen Sie Gruppen zu Ihrer Studie hinzu, um die Gruppenfunktionalitäten nutzen zu können. Ihre Studiengruppen werden hier aufgelistet."
+ "emptyGroupList": "Fügen Sie Gruppen zu Ihrer Studie hinzu, um die Gruppenfunktionalitäten nutzen zu können. Ihre Studiengruppen werden hier aufgelistet.",
+ "duration": "Gib die Studiendauer ein",
+ "durationUnit": "Einheit der Studiendauer",
+ "durationValue": "Wert der Studiendauer"
},
"action": {
"create": "Studiengruppe erstellen"
@@ -708,10 +723,45 @@
"scheduler": {
"singular": "Planer",
- "dialogTitle": "Zeitplan verwalten",
+ "type":{
+ "Event": "Absoluter Zeitplan",
+ "RelativeEvent": "Relativer Zeitplan"
+ },
+ "dialogTitle": "Absoluten Zeitplan verwalten",
+ "relativeDialogTitle": "Relativen Zeitplan verwalten",
+ "preview": {
+ "title": {
+ "individualEvent": "Individuelles Event",
+ "repeatEvent": "Event wiederholen",
+ "startsOn": "Startet am",
+ "endsOn": "Endet am",
+ "timeframe": "Timeframe",
+ "every": "Jeden",
+ "ends": "Endet",
+ "on": "am",
+ "in": "in",
+ "selectedDays": "Ausgewählte Tages"
+ },
+ "unit": {
+ "MINUTE": "Minute",
+ "PL-MINUTE": "Minuten",
+ "HOUR": "Stunde",
+ "PL-HOUR": "Stunden",
+ "DAY": "Tag",
+ "PL-DAY": "Tage",
+ "DAILY": "täglich",
+ "WEEKLY": "Wochen",
+ "date": "Datum",
+ "time": "Zeit"
+ }
+ },
"frequency": {
+ "minute": "Minute",
+ "hour": "Stunde",
"hours": "Stunde(n)",
"days": "Tag(e)",
+ "day": "Tag",
+ "week": "Woche",
"weeks": "Woche(n)",
"months": "Monat(e)",
"years": "Jahr(e)",
@@ -742,6 +792,15 @@
"friday": "FR",
"saturday": "SA",
"sunday": "SO"
+ },
+ "props": {
+ "MO": "Mo",
+ "TU": "Di",
+ "WE": "Mi",
+ "TH": "Do",
+ "FR": "Fr",
+ "SA": "Sa",
+ "SO": "So"
}
},
"months":{
@@ -783,7 +842,10 @@
"after": "Nach",
"on": "Am",
"every": "Jede(s)",
- "openScheduler": "Zeitplaner öffnen",
+ "openScheduler": "Absoluten Zeitplaner hinzufügen",
+ "editScheduler": "Absoluten Zeitplaner bearbeiten",
+ "openRelativeScheduler": "Relativen Zeitplaner hinzfügen",
+ "editRelativeScheduler": "Relativen Zeitplaner bearbeiten",
"removeScheduler": "Zeitplaner entfernen",
"frequency": "Frequenz",
"repetitionEnd": "Wiederholungsende",
@@ -804,7 +866,7 @@
"setDatesDesc": "Mit Start- und Endzeit können Sie eine Zeitspanne für eine Datenerhebung an einem Tag festlegen. Die Datenerhebung kann auch ganztags gesetzt werden. Durch die Angaben von Wiederholdungen könenn Sie eine Serie von Datenerhebungen definieren. Alternativ dazu können Sie einen gesamten Zeitraum definieren.",
"repeat": "Wiederhole die oben definierte Zeitspanne",
"repeatDesc": "Um die gesetzte Zeitspanne zu wiederholen, können Sie dies bis zu einer bestimmten Anzahl an Tagen oder Wochen tun. Beachte, dass die gesamte oben angegebene Zeitspanne weiderholt wird.",
- "oneDayObservation": "Einmalige Datenerhebung",
+ "oneDayObservation": "Mehrfache Datenerhebung",
"repetitionEnd": {
"studyEnd": "Bis Studienende",
"after": "Nach"
@@ -839,6 +901,60 @@
"startDateNotWithinRange": "Das Startdatum war nicht innerhalb der Studiendauer. Bitte stellen Sie sicher, dass die Datenerhebung innerhalb der Studiendauer geplant wird.",
"endDateNotWithinRange": "Das Enddatum war nicht innerhalb der Studiendauer. Bitte stellen Sie sicher, dass die Datenerhebung innerhalb der Studiendauer geplant wird.",
"timeOutsideStudyRange": "Bitte stellen Sie sicher, dass das Start- und Enddatum sich innerhalb der Studiendauer befindet."
+ },
+ "dialog": {
+ "description": "Ein relativer Zeitplan richtet sich nach dem individuellen Studienstart jedes Teilnehmers, basierend auf das App-Login Datum. Die Teilnehmer können jederzeit zwischen Beginn und Ende der Studie starten, und die Studiendauer umfasst den Zeitraum, indem aktiv Daten erhoben werden.",
+ "noSetScheduleDesc": "Wenn kein Schedule gesetzt wird, wird die gesamte Studienzeit als Standard-Zeitraum als absoluter Zeitplan verwendet.",
+ "repeatEvent": "Event wiederholen",
+ "singleEventTitle": "Einzelnes Datenerhebungs-Event",
+ "repeatEventTitle": "Datenerhebungs-Event wiederholen",
+ "repeatEventDescription": "Das oben gezeigte Event wird wiederholt, sobald die aktuelle abgeschlossen ist.",
+ "repeatEvery": "Wiederholen: Jede",
+ "endAfter": "Ende nach",
+ "dayExplanation": "Der Begriff 'Tag' zeigt an, wie der Start einer individuellen Studie eines Teilnehmers mit dem entsprechenden Tageswert verknüpft ist. Beispiel: (Ein Teilnehmer meldet sich am 1.12.2023 an, der Studienstart ist auf Tag 2 festgelegt. Das bedeutet, dass die Studie am 2.12.2023 beginnt.)",
+ "absoluteSchedule": {
+ "description": "Eine absolute Zeitplanung umfasst absolute Datum und Zeit Angaben. Beobachtungen können durch absolute Daten und Zeitfenster zeitlich festgelegt werden."
+ },
+ "relativeSchedule": {
+ "dialogTitle":"Relativen Zeitplan verwalten",
+ "description": "Ein relativer Zeitplan richtet sich nach dem individuellen Studienstart jedes Teilnehmers, basierend auf das App-Login Datum. Die Teilnehmer können jederzeit zwischen Beginn und Ende der Studie starten, und die Studiendauer umfasst den Zeitraum, indem aktiv Daten erhoben werden.",
+ "startValue": "Startet am",
+ "endValue": "Endet am",
+ "interventionWarning": "Beachten Sie, dass das Festlegen eines absoluten Datums (Einstellen von Tag oder Monat) über den Cron-Zeitplan möglicherweise nicht besonders effektiv ist, wenn Sie mit relativen Beobachtungsplänen arbeiten. Relative Beobachtungspläne werden auf Grundlage des individuellen Studienbeginns der Teilnehmer (Anmeldung) berechnet.",
+ "dayExplanation": "Der Begriff 'Tag' bezeichnet die Korrelation zwischen dem Beginn der Studie eines einzelnen Teilnehmers und dem entsprechenden Tageswert. (Beispiel: Ein Teilnehmer meldet sich am 1.12.2023 an, der Studienbeginn ist auf Tag 2 festgelegt. Sie beginnen am 2.12.2023.)",
+ "rrrule": {
+ "ends": "Endet",
+ "endsAfter": "Tage nach dem individuellen Studienstart.",
+ "repeated": "Wiederholung",
+ "times": "Mal"
+ },
+ "placeholder": {
+ "dtstartOffset": "Offset in Tage(n)",
+ "dtstartTime": "Strat Zeit",
+ "dtendOffset": "Offset in Tage(n)",
+ "dtendTime": "End Zeit",
+ "enterNumber": "Nummer eingeben"
+ },
+ "error": {
+ "dtstart":{
+ "addOffset": "Befülle den Offset des relativen Startzeitraum."
+ },
+ "dtend": {
+ "addOffset": "Befülle den Offset des relativen Endzeitraum."
+ },
+ "rrrule": {
+ "frequency": "Fülle die Widerholungsrate ein.",
+ "endAfter": "Fulle den Offset zum Enddatum ein.",
+ "notValid": "Die eingegebenen Werte sind ungültig."
+ }
+ }
+ }
+ },
+ "warningsAndErrors": {
+ "endWasChangedWithStartValue": "End Wert wurde mit dem Start Wert geändert.",
+ "rruleFreqIsEmpty": "Bitte legen Sie die Häufigkeit für Ihre Wiederholung fest.",
+ "rruleWeeklyIsMissingByDay": "Bitte legen Sie die Wochentage für Ihre Wiederholung fest.",
+ "rruleEndIsEmpty": "Bitte legen Sie einen Endpunkt für Ihren Wiederholungszeitraum fest."
}
},
@@ -874,3 +990,4 @@
"title": "Titel",
"message": "Nachricht"
}
+
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 78d5f9bb..7fb26d9d 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -34,7 +34,8 @@
"to": "to",
"message": "Message",
"option": "Option",
- "data": "Data"
+ "data": "Data",
+ "scheduleType": "Schedule Type"
},
"placeholder": {
"entireStudy": "Entire study",
@@ -84,7 +85,8 @@
"purpose": "Purpose",
"status": "Status",
"roles": "Role(s)",
- "plannedStart": "Planned start",
+ "duration":"Study duration",
+ "plannedStart": "Planned Start",
"actualStart": "Actual start",
"plannedEnd": "Planned end",
"actualEnd": "Actual end",
@@ -94,6 +96,11 @@
"studyGroup": "Study group",
"finishText": "Study end message"
},
+ "ical": {
+ "copyMsg": "Link for ICalendar subscription ('{title} (Id: {studyId})') was copied to clipboard.",
+ "title": "Calendar Link for subscription",
+ "copyTitle": "Copy Link"
+ },
"roles": {
"admin": "Study Administrator",
"operator": "Study Operator",
@@ -107,7 +114,7 @@
"changeMsg": {
"toActive":{
"intro": "You are about to change your study status to 'ACTIVE'.",
- "warning": "Changing your study status to 'ACTIVE', will make the study available to your participants in the app and set all your interventions and observations into data capture mode, based on their set schedule. Participants will be able to log in and participate in the research.",
+ "warning": "Changing your study status to 'ACTIVE', will make the study available to your participants in the app and set all your interventions and observations into data capture mode, based on their set schedule. Participants will be able to log in and participate in the research. If the planned start date is after today's date, it will be set to the actual start date with this status change.",
"confirm": "This study status change cannot be reversed, but there is the possibility to pause the study to make changes to your settings. Are you sure you want to set your Study Status to 'ACTIVE'?"
},
"toPaused":{
@@ -141,6 +148,7 @@
},
"error": {
"addTitle": "The study title is required. Please enter a study title.",
+ "addDuration": "Please enter both a duration and a unit.",
"addConsentInfo": "The consent information is required. Please enter a description.",
"addParticipantInfo": "The participant information is required. Please enter a description.",
"addContactInfo": "Please add a contact person and email address, which participants can use to contact your institute when they encounter problems.",
@@ -149,6 +157,7 @@
},
"placeholder": {
"titleInput": "Please provide a short title.",
+ "durationInput": "Please provide the duration of the study",
"purposeInput": "Please provide a short description of your research purpose for your collaborators.",
"participantInfoInput": "Please provide information for your studies participants. This description will be visible on the participant's app.",
"consentInfoInput": "Please provide information on the data that will be collected. This description will be shown on the participant's app.",
@@ -173,6 +182,7 @@
},
"label": {
"studyTitle": "Study title",
+ "durationExample": "Study Duration Example",
"studyStart": "Study start",
"studyEnd": "Study end",
"contactInfo": "Contact information",
@@ -192,6 +202,8 @@
},
"description": {
"study": "Enter the base information of your study to provide basic information for collaborators and participants.",
+ "duration": "The study duration is the period when participants are actively contributing to data collection. This is important when using relative observations. If no study duration is specified, the entire time from study start to end of the study is considered.",
+ "durationExample": "Study Start; 01.07.2023 - Study End: 31.12.2023 (5 months) - Study Duration: 4 weeks\nThe participant's active participation time for the study is limited to 4 weeks, determined by their login date.",
"purpose": "The purpose property describes the general purpose of the study. This information will only be shown to study collaborators on the study configurator.",
"participantInfo": "The participant information will be displayed on the app as the studies description. It should give a short information about the study and its purpose.",
"consentInfo": "The consent information will be displayed in the app and has to be approved by the participants.",
@@ -207,7 +219,8 @@
"emptyListMsg": "No studies yet",
"labels": {
"exportStudyConfig": "Export study config",
- "exportStudyData": "Export study data"
+ "exportStudyData": "Export study data",
+ "exportStudyCalendar": "Export study calendar"
},
"action": {
"addStudy": "Add new study",
@@ -239,7 +252,10 @@
"placeholder": {
"title": "Set a title",
"purpose": "Describe the purpose of the group.",
- "emptyGroupList": "Add groups to your study to use group functionalities"
+ "emptyGroupList": "Add groups to your study to use group functionalities",
+ "duration": "Set the individual study duration",
+ "durationUnit": "Individual study duration unit",
+ "durationValue": "Ind. study duration value"
},
"action": {
"create": "Create group"
@@ -706,11 +722,48 @@
"scheduler": {
"singular": "Scheduler",
- "dialogTitle": "Manage schedule",
+ "type": {
+ "Event": "Absolut Event",
+ "RelativeEvent": "Relative Event"
+ },
+ "dialogTitle": "Manage absolute schedule",
+ "relativeDialogTitle": "Manage relative schedule",
+ "preview": {
+ "title": {
+ "individualEvent": "Individual Event",
+ "repeatEvent": "Repeat Event",
+ "startsOn": "Starts on",
+ "endsOn": "Ends on",
+ "timeframe": "Timeframe",
+ "every": "Every",
+ "ends": "Ends",
+ "on": "on",
+ "in": "in",
+ "selectedDays": "Selected days"
+ },
+ "unit": {
+ "MINUTE": "Minute",
+ "PL-MINUTE": "minute(s)",
+ "HOUR": "Hour",
+ "PL-HOUR": "hour(s)",
+ "DAY": "Day",
+ "PL-DAY": "day(s)",
+ "DAILY": "day(s)",
+ "WEEKLY": "week(s)",
+ "date": "Date",
+ "time": "Time"
+ }
+ },
"frequency": {
+ "minute": "minute",
+ "minutes": "minute(s)",
+ "hour": "hour",
"hours": "hour(s)",
+ "day": "day",
"days": "day(s)",
+ "week": "week",
"weeks": "week(s)",
+ "month": "month",
"months": "month(s)",
"years": "year(s)",
"labels": {
@@ -740,6 +793,15 @@
"friday": "FR",
"saturday": "SA",
"sunday": "SU"
+ },
+ "props": {
+ "MO": "Mo",
+ "TU": "Tue",
+ "WE": "We",
+ "TH": "Thur",
+ "FR": "Fr",
+ "SA": "Sa",
+ "SO": "So"
}
},
"months":{
@@ -781,13 +843,18 @@
"after": "After",
"on": "On",
"every": "Every",
- "openScheduler": "Open scheduler",
+ "openScheduler": "Add absolute schedule",
+ "editScheduler": "Edit absolute schedule",
+ "openRelativeScheduler": "Add relative Schedule",
+ "editRelativeScheduler": "Edit relative Schdule",
"removeScheduler": "Remove scheduler",
"frequency": "Frequency",
"repetitionEnd": "Repetition ends",
"repeat": "Repeat",
"date": "Date",
"timeframe": "Timeframe",
+ "days": "Days",
+ "time": "Time",
"selection":{
"specificDay": "On a specific day",
"allDaysInWeek": "All days in week",
@@ -802,7 +869,7 @@
"setDatesDesc": "You can define a timeframe for your observation with start and end date for one day. The timeframe can be set to 'Entire day'. A series of data collection can be defined through the repetition definition below. Alternatively you can set a full time span over more days.",
"repeat": "Repeat set duration above",
"repeatDesc": "To repeat the set duration above, you can schedule it up to a specific amount of days or weeks. Consider, that the whole timeframe above will be repeated.",
- "oneDayObservation": "Individual Observation",
+ "oneDayObservation": "Multiple observation events",
"repetitionEnd": {
"studyEnd": "Until end of study",
"after": "After"
@@ -838,6 +905,59 @@
"startDateNotWithinRange": "Start date was not inside the study range. Please be sure to set the dates inside the study ranges.",
"endDateNotWithinRange": "End date was not inside the study range. Please be sure to set the dates inside the study ranges.",
"timeOutsideStudyRange": "Please be sure to set start and end time within the study range."
+ },
+ "dialog": {
+ "description": "An absolute Schedule includes absolute date times. A relativ schedule collects data based on participant login and individual study starts.",
+ "noSetScheduleDesc": "If there is no schedule set, the whole schedule time will be set als default time as absolute Schedule.",
+ "repeatEvent": "Repeat event",
+ "singleEventTitle": "Single observation event",
+ "repeatEventTitle": "Repeat observation event",
+ "repeatEventDescription": "The event above will be repeated after the runtime of the current event has finished.",
+ "repeatEvery": "Repeat every",
+ "endAfter": "End after",
+ "absoluteSchedule": {
+ "description": "An absolute Schedule includes absolute date times. Observations can be timed by absolute dates and timeframes."
+ },
+ "relativeSchedule": {
+ "dialogTitle":"Manage relative schedule",
+ "description": "A relative schedule is determined by each participant's actual log-in time. They can start anytime between the study's beginning and end, and the set duration covers their active participation period.",
+ "startValue": "Starts on",
+ "endValue": "Ends on",
+ "interventionWarning": "Note that setting an absolute date (setting day or month) via cron scheduler might not be that effective when working with relative observation schedules. Relative observation schedules will be calculated based on the individual study start of participants (log in).",
+ "dayExplanation": "The term 'Day' signifies the correlation between the start of an individual participant's study and the corresponding day value. (Example: Participant logs in on 1.12.2023, study start is set to Day 2. They start on 2.12.2023.)",
+ "rrrule": {
+ "ends": "Ends",
+ "endsAfter": "days after individual study start.",
+ "repeated": "Repeated",
+ "times": "times"
+ },
+ "placeholder": {
+ "dtstartOffset": "Enter offset in day(s)",
+ "dtstartTime": "Enter start time",
+ "dtendOffset": "Enter offset in day(s)",
+ "dtendTime": "Enter end time",
+ "enterNumber": "Enter number"
+ },
+ "error": {
+ "dtstart":{
+ "addOffset": "Fill in the offset of the relative start period."
+ },
+ "dtend": {
+ "addOffset": "Fill in the offset of the relative end period."
+ },
+ "rrrule": {
+ "frequency": "Fill in the repetition rate.",
+ "endAfter": "Fill in the offset to the end date.",
+ "notValid": "Values entered are not valid"
+ }
+ }
+ }
+ },
+ "warningsAndErrors": {
+ "endWasChangedWithStartValue": "End value was changed with start value.",
+ "rruleFreqIsEmpty": "Please set the frequency for your repetition.",
+ "rruleWeeklyIsMissingByDay": "Please set the weekdays for your repetition.",
+ "rruleEndIsEmpty": "Please set and end point for your repetition period."
}
},
diff --git a/src/models/MoreTableModel.ts b/src/models/MoreTableModel.ts
index e1cad902..70de413a 100644
--- a/src/models/MoreTableModel.ts
+++ b/src/models/MoreTableModel.ts
@@ -110,6 +110,7 @@ export interface MoreTableActionConfirmDialog {
export enum MoreTableFieldType {
string,
+ number,
choice,
calendar,
multiselect,
@@ -120,6 +121,7 @@ export enum MoreTableFieldType {
showIcon,
nested,
nestedDatetime,
+ binaryIcon,
}
export enum FileUploadModeType {
@@ -181,3 +183,15 @@ export interface MoreInterventionTableMap {
cronTime?: string;
cronRepetition?: string;
}
+
+export interface MoreStudyGroupTableMap {
+ studyId?: number;
+ studyGroupId?: number;
+ title?: string;
+ purpose?: string;
+ durationValue?: number;
+ durationUnit?: string;
+ numberOfParticipants?: number;
+ created?: string;
+ modified?: string;
+}
diff --git a/src/stores/studyGroupStore.ts b/src/stores/studyGroupStore.ts
index eac528ae..391eed46 100644
--- a/src/stores/studyGroupStore.ts
+++ b/src/stores/studyGroupStore.ts
@@ -6,13 +6,14 @@
Foerderung der wissenschaftlichen Forschung).
Licensed under the Elastic License 2.0.
*/
-import { ref, Ref } from 'vue';
+import { computed, ComputedRef, ref, Ref } from 'vue';
import { defineStore } from 'pinia';
-import { StudyGroup } from '../generated-sources/openapi';
+import { Duration, StudyGroup } from '../generated-sources/openapi';
import { useStudyGroupsApi } from '../composable/useApi';
import i18n from '../i18n/i18n';
import { useErrorHandling } from '../composable/useErrorHandling';
import { AxiosError } from 'axios';
+import { MoreStudyGroupTableMap } from '../models/MoreTableModel';
export const useStudyGroupStore = defineStore('studyGroup', () => {
const { studyGroupsApi } = useStudyGroupsApi();
@@ -89,11 +90,56 @@ export const useStudyGroupStore = defineStore('studyGroup', () => {
);
}
}
+
+ function toStudyGroupMap() {
+ return studyGroups.value.map((item: StudyGroup) => {
+ return {
+ studyId: item.studyId,
+ studyGroupId: item.studyGroupId,
+ title: item.title,
+ purpose: item.purpose,
+ durationValue: item.duration?.value,
+ durationUnit: item.duration?.unit,
+ numberOfParticipants: item.numberOfParticipants,
+ created: item.created,
+ modified: item.modified,
+ } as MoreStudyGroupTableMap;
+ });
+ }
+
+ function toStudyGroup(row: MoreStudyGroupTableMap): StudyGroup {
+ let d: Duration | undefined = undefined;
+
+ if (row.durationValue && row.durationUnit) {
+ d = {
+ value: row.durationValue,
+ unit: row.durationUnit,
+ } as Duration;
+ }
+
+ return {
+ studyId: row.studyId,
+ studyGroupId: row.studyGroupId,
+ title: row.title,
+ purpose: row.purpose,
+ duration: d,
+ numberOfParticipants: row.numberOfParticipants,
+ created: row.created,
+ modiefied: row.modified,
+ } as StudyGroup;
+ }
+
+ const studyGroupMap: ComputedRef> = computed(
+ () => toStudyGroupMap()
+ );
+
return {
studyGroups,
+ studyGroupMap,
getStudyGroups,
createStudyGroup,
deleteStudyGroup,
updateStudyGroup,
+ toStudyGroup,
};
});
diff --git a/src/stores/studyStore.ts b/src/stores/studyStore.ts
index 4d6997c6..ed2f94cb 100644
--- a/src/stores/studyStore.ts
+++ b/src/stores/studyStore.ts
@@ -48,18 +48,45 @@ export const useStudyStore = defineStore('study', () => {
async function updateStudyStatus(status: StudyStatus) {
if (study.value.studyId) {
- await studiesApi
- .setStatus(study.value.studyId, { status })
- .then(() => {
- study.value.status = status;
- })
- .catch((e: AxiosError) => {
- alert('Could not update study status');
- handleIndividualError(
- e,
- 'Could not update study status' + study.value.studyId
- );
- });
+ if (
+ status === 'active' &&
+ !study.value.start &&
+ study.value.plannedStart &&
+ new Date(study.value.plannedStart) > new Date()
+ ) {
+ study.value.plannedStart = new Date().toISOString();
+ study.value.status = status;
+ await studiesApi
+ .updateStudy(study.value.studyId, study.value)
+ .then(() => {
+ studiesApi
+ .setStatus(study.value.studyId as number, { status })
+ .then(() => {
+ study.value.status = status;
+ study.value.start = new Date().toISOString();
+ });
+ })
+ .catch((e: AxiosError) => {
+ alert('Could not update study status');
+ handleIndividualError(
+ e,
+ 'Could not update study status' + study.value.studyId
+ );
+ });
+ } else {
+ await studiesApi
+ .setStatus(study.value.studyId, { status })
+ .then(() => {
+ study.value.status = status;
+ })
+ .catch((e: AxiosError) => {
+ alert('Could not update study status');
+ handleIndividualError(
+ e,
+ 'Could not update study status' + study.value.studyId
+ );
+ });
+ }
}
}
@@ -158,6 +185,10 @@ export const useStudyStore = defineStore('study', () => {
});
}
+ async function exportStudyCalendar(studyId: number): Promise {
+ await window.open(`api/v1/studies/${studyId}/calendar.ics`);
+ }
+
function downloadJSON(filename: string, file: File): void {
const fileJSON = JSON.stringify(file);
const link = document.createElement('a');
@@ -196,6 +227,7 @@ export const useStudyStore = defineStore('study', () => {
importStudy,
exportStudyConfig,
exportStudyData,
+ exportStudyCalendar,
studyUserRoles,
studyStatus,
studyId,
diff --git a/src/styles/layout.pcss b/src/styles/layout.pcss
index 0894f78e..602c05d1 100644
--- a/src/styles/layout.pcss
+++ b/src/styles/layout.pcss
@@ -12,6 +12,10 @@ body {
.error {
color: #D57575;
}
+.warning {
+ color: var(--yellow-600);
+}
+
a {
color: var(--primary-color);
diff --git a/src/utils/dateUtils.ts b/src/utils/dateUtils.ts
index 6785e197..3c14d57e 100644
--- a/src/utils/dateUtils.ts
+++ b/src/utils/dateUtils.ts
@@ -30,3 +30,25 @@ export function dateTimeStringToDate(dateTimeString: string): Date | undefined {
return undefined;
}
}
+
+export function ZTimeToOffsetTime(date: Date): Date {
+ const offset = date.getTimezoneOffset() / 60;
+ const newTime = date;
+ newTime.setHours(date.getHours() - offset);
+ return newTime;
+}
+
+export function ZTimeStringToOffsetTimeString(
+ time: string | undefined
+): string | undefined {
+ let newTime = time ? new Date() : undefined;
+ if (newTime && time) {
+ newTime.setHours(
+ parseInt(time.substring(0, 2)),
+ parseInt(time?.substring(3, 5), 0)
+ );
+ newTime = ZTimeToOffsetTime(newTime);
+ return newTime.toString().substring(16, 21);
+ }
+ return undefined;
+}
diff --git a/tsconfig.json b/tsconfig.json
index 6f4054bc..22d77c8c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -16,8 +16,8 @@
"lib": ["esnext", "dom",
"dom.iterable",
"scripthost"],
- "types": ["vite/client"],
- "plugins": [{ "name": "@vuedx/typescript-plugin-vue" }]
+ "types": ["vite/client", "node"],
+ "plugins": [{ "name": "@vuedx/typescript-plugin-vue" }],
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"exclude": [