Skip to content

Commit ced591b

Browse files
JackWilbjaykim1213dependabot[bot]CopilotCopilot
authored
v.2.4.3 (#1226)
* Refine startup error handling * Handle startup storage fallback and resume alerts * Inline Shell startup helpers * Guard Shell startup participant lookup fallback * Fix typo in library calvi question description * Fix UI break when user rejects audio recording * Add aria-disabled and tab index -1 to mic error icon * Revert record screen field in library-screen-recording * Add screen recording icon to timeline * Address PR comment * Fix mic icon bug if mic permission is disabled * Fix back button enabled in the study replay * Fix replay task bug * Bump the npm_and_yarn group across 1 directory with 2 updates Bumps the npm_and_yarn group with 2 updates in the / directory: [uuid](https://github.com/uuidjs/uuid) and [postcss](https://github.com/postcss/postcss). Updates `uuid` from 11.1.0 to 14.0.0 - [Release notes](https://github.com/uuidjs/uuid/releases) - [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md) - [Commits](uuidjs/uuid@v11.1.0...v14.0.0) Updates `postcss` from 8.5.6 to 8.5.12 - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.6...8.5.12) --- updated-dependencies: - dependency-name: uuid dependency-version: 14.0.0 dependency-type: direct:production dependency-group: npm_and_yarn - dependency-name: postcss dependency-version: 8.5.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> * Speed up first load by clearing the hot path from un-necessary awaits Co-authored-by: Copilot <copilot@github.com> * Prevent metadata writes in demo mode * Fix showing app header warning * Address PR comments * Refactor GlobalConfigParser to reduce config fetches * Enhance Shell component with loading overlay and completion check logic * Add error handling and user feedback for participant completion check in Shell component * Refactor Shell component to improve loading state handling and simplify rendering logic * Refactor AuthProvider to enhance loading state handling and conditionally render children based on route match * Eliminate unnecessary await * Handle transient completion-status lookup failures to allow study entry * Fix small issue with operators * Refactor isStorageStartupFailure function to simplify logic and remove unused parameter * Fix microphone permission handling in AppHeader component tests * Fix replay previous-step navigation * Fix replay bug and remove test fixture * Remove currentTrial query param plumbing * Fix dynamic backward navigation * Refactor tests to preserve dynamic child routes from pathname and improve navigation assertions * Initial plan * feat: add component auto-advance timeout options Agent-Logs-Url: https://github.com/revisit-studies/study/sessions/85bdb0ee-0034-45cf-9535-f19f250395ff * test: refine timeout warning messaging Agent-Logs-Url: https://github.com/revisit-studies/study/sessions/85bdb0ee-0034-45cf-9535-f19f250395ff * fix: handle auto-advance warning placeholders consistently Agent-Logs-Url: https://github.com/revisit-studies/study/sessions/85bdb0ee-0034-45cf-9535-f19f250395ff * refactor: simplify NextButton and useNextStep hooks - Remove unnecessary useMemo calls for trivial config value reads in NextButton (nextButtonDisableTime, nextButtonEnableTime, nextOnEnter, previousButtonText) - Remove unnecessary useMemo for modes.dataCollectionEnabled destructuring in useNextStep - Fix consistent-return lint error by unconditionally returning cleanup function in nextOnEnter useEffect - Fix prefer-destructuring lint warning in useNextStep * fix: correct E2E test setup for timeout component study - Use correct tab name 'Tests' instead of 'Test Studies' - Activate the Tests tab before opening the study - Handle custom studyEndMsg instead of relying on default message - Simplify study card locator to avoid strict mode violation * Address feedback from review * Separating provenance data from answers (#1230) * moving provenance * ensuring fallback works * Persist provenance as separate assets * Add provenance bulk download export * Ignore coverage output * Fix type error in test --------- Co-authored-by: Jack Wilburn <jackwilburn@tutanota.com> * Fix useNextStep skip evaluation typing * Fix Shell completion check error visibility * Fix test --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Jay Kim <76601570+yeonkim1213@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Copilot <copilot@github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ZachCutler04 <zach.t.cutler@gmail.com>
1 parent 1342408 commit ced591b

57 files changed

Lines changed: 3108 additions & 500 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,5 @@ supabase/volumes/*
3737
!supabase/volumes/db/
3838
supabase/volumes/db/data
3939
!supabase/volumes/api/
40+
41+
coverage/

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
"typedoc": "^0.28.13",
8383
"typedoc-plugin-markdown": "^4.9.0",
8484
"use-deep-compare-effect": "^1.8.1",
85-
"uuid": "^11.0.5",
85+
"uuid": "^14.0.0",
8686
"vega": "^6.2.0",
8787
"vega-lite": "^5.23.0",
8888
"vite": "^7.3.2",
@@ -113,6 +113,7 @@
113113
"eslint-plugin-react-hooks": "^5.2.0",
114114
"globals": "^16.4.0",
115115
"husky": "^9.1.7",
116+
"jsdom": "^29.1.1",
116117
"lint-staged": "^16.1.6",
117118
"typescript": "^5.9.2",
118119
"vitest": "^3.2.4",

public/global.json

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@
4949
"test-device-restriction",
5050
"test-library",
5151
"test-likert-matrix",
52-
"test-parser-errors",
53-
"test-randomization",
54-
"test-skip-logic",
55-
"test-step-logic"
52+
"test-parser-errors",
53+
"test-randomization",
54+
"test-component-timeout",
55+
"test-skip-logic",
56+
"test-step-logic"
5657
],
5758
"configs": {
5859
"tutorial": {
@@ -210,13 +211,17 @@
210211
"path": "test-parser-errors/config.json",
211212
"test": true
212213
},
213-
"test-randomization": {
214-
"path": "test-randomization/config.json",
215-
"test": true
216-
},
217-
"test-skip-logic": {
218-
"path": "test-skip-logic/config.json",
219-
"test": true
214+
"test-randomization": {
215+
"path": "test-randomization/config.json",
216+
"test": true
217+
},
218+
"test-component-timeout": {
219+
"path": "test-component-timeout/config.json",
220+
"test": true
221+
},
222+
"test-skip-logic": {
223+
"path": "test-skip-logic/config.json",
224+
"test": true
220225
},
221226
"test-step-logic": {
222227
"path": "test-step-logic/config.json",
@@ -239,4 +244,4 @@
239244
"test": true
240245
}
241246
}
242-
}
247+
}

public/libraries/calvi/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"reference": "Lily W. Ge, Yuan Cui, and Matthew Kay. 2023. CALVI: Critical Thinking Assessment for Literacy in Visualizations. In Proceedings of the 2023 CHI Conference on Human Factors in Computing Systems (CHI '23). Association for Computing Machinery, New York, NY, USA, Article 815, 1-18.",
66
"components": {
77
"N1": {
8-
"description": "Audio test",
8+
"description": "Visitors at Movie Theaters in 2001",
99
"type": "image",
1010
"path": "libraries/calvi/assets/questions/normal/N1.jpg",
1111
"nextButtonLocation": "sidebar",

public/libraries/mic-check/config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"path": "libraries/mic-check/assets/AudioTest.tsx",
99
"nextButtonLocation": "belowStimulus",
1010
"nextButtonText": "Continue",
11+
"recordAudio": true,
1112
"response": [
1213
{
1314
"id": "audioTest",

public/libraries/screen-recording/config.json

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@
88
"path": "libraries/screen-recording/assets/ScreenRecording.tsx",
99
"nextButtonLocation": "belowStimulus",
1010
"nextButtonText": "Continue",
11-
"recordAudio": false,
12-
"response": [{
13-
"hidden": true,
14-
"type": "reactive",
15-
"id": "screenRecordingPermission",
16-
"prompt": "Screen recording enabled"
17-
}]
11+
"recordScreen": true,
12+
"response": [
13+
{
14+
"hidden": true,
15+
"type": "reactive",
16+
"id": "screenRecordingPermission",
17+
"prompt": "Screen recording enabled"
18+
}
19+
]
1820
}
1921
},
2022
"sequences": {}
21-
}
23+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/revisit-studies/study/v2.4.2/src/parser/StudyConfigSchema.json",
3+
"studyMetadata": {
4+
"title": "Component Timeout Auto-Advance Test",
5+
"version": "pilot",
6+
"authors": [
7+
"The reVISit Team"
8+
],
9+
"date": "2026-05-14",
10+
"description": "A test study for component-level auto-advance timeouts.",
11+
"organizations": [
12+
"The reVISit Team"
13+
]
14+
},
15+
"uiConfig": {
16+
"contactEmail": "contact@revisit.dev",
17+
"logoPath": "revisitAssets/revisitLogoSquare.svg",
18+
"withProgressBar": true,
19+
"autoDownloadStudy": false,
20+
"withSidebar": true,
21+
"studyEndMsg": "Timeout auto-advance test complete."
22+
},
23+
"baseComponents": {
24+
"timed-question": {
25+
"type": "questionnaire",
26+
"instruction": "Do not answer this question. It should automatically advance.",
27+
"response": [
28+
{
29+
"id": "timeout-response",
30+
"prompt": "Optional answer",
31+
"location": "belowStimulus",
32+
"type": "shortText",
33+
"required": false
34+
}
35+
],
36+
"nextButtonAutoAdvanceTime": 2500,
37+
"nextButtonAutoAdvanceWarningTime": 1500,
38+
"nextButtonAutoAdvanceWarningMessage": "Custom timeout warning: advancing in {seconds} {unit} without saving this component."
39+
}
40+
},
41+
"components": {
42+
"introduction": {
43+
"type": "questionnaire",
44+
"instruction": "Press next to begin the timeout auto-advance test.",
45+
"response": []
46+
},
47+
"timeout-question": {
48+
"baseComponent": "timed-question"
49+
}
50+
},
51+
"sequence": {
52+
"order": "fixed",
53+
"components": [
54+
"introduction",
55+
"timeout-question"
56+
]
57+
}
58+
}

src/GlobalConfigParser.tsx

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,37 +28,72 @@ async function fetchGlobalConfigArray() {
2828
return parseGlobalConfig(configs);
2929
}
3030

31-
export function GlobalConfigParser() {
32-
const [globalConfig, setGlobalConfig] = useState<Nullable<GlobalConfig>>(null);
31+
function HomeRoute({ globalConfig }: { globalConfig: GlobalConfig }) {
3332
const [studyConfigs, setStudyConfigs] = useState<Record<string, ParsedConfig<StudyConfig> | null>>({});
3433

3534
useEffect(() => {
36-
async function fetchData() {
37-
if (globalConfig) {
38-
setStudyConfigs(await fetchStudyConfigs(globalConfig));
35+
let cancelled = false;
36+
37+
async function fetchData(currentGlobalConfig: GlobalConfig) {
38+
const configs = await fetchStudyConfigs(currentGlobalConfig);
39+
if (!cancelled) {
40+
setStudyConfigs(configs);
3941
}
4042
}
41-
fetchData();
43+
44+
fetchData(globalConfig);
45+
46+
return () => {
47+
cancelled = true;
48+
};
4249
}, [globalConfig]);
4350

51+
return (
52+
<>
53+
<PageTitle title="ReVISit | Home" />
54+
<AppShell
55+
padding="md"
56+
header={{ height: 70 }}
57+
>
58+
<AppHeader studyIds={globalConfig.configsList} />
59+
<ConfigSwitcher
60+
globalConfig={globalConfig}
61+
studyConfigs={studyConfigs}
62+
/>
63+
</AppShell>
64+
</>
65+
);
66+
}
67+
68+
export function GlobalConfigParser() {
69+
const [globalConfig, setGlobalConfig] = useState<Nullable<GlobalConfig>>(null);
70+
4471
useEffect(() => {
45-
if (globalConfig) return;
72+
if (globalConfig) {
73+
return undefined;
74+
}
4675

4776
fetchGlobalConfigArray().then((gc) => {
4877
setGlobalConfig(gc);
4978
});
79+
80+
return undefined;
5081
}, [globalConfig]);
5182

5283
// Initialize storage engine
5384
const { storageEngine, setStorageEngine } = useStorageEngine();
5485
useEffect(() => {
55-
if (storageEngine !== undefined) return;
86+
if (storageEngine !== undefined) {
87+
return undefined;
88+
}
5689

5790
async function fn() {
5891
const _storageEngine = await initializeStorageEngine();
5992
setStorageEngine(_storageEngine);
6093
}
6194
fn();
95+
96+
return undefined;
6297
}, [setStorageEngine, storageEngine]);
6398

6499
const analysisProtectedCallback = async (studyId: string) => {
@@ -76,21 +111,7 @@ export function GlobalConfigParser() {
76111
<Routes>
77112
<Route
78113
path="/"
79-
element={(
80-
<>
81-
<PageTitle title="ReVISit | Home" />
82-
<AppShell
83-
padding="md"
84-
header={{ height: 70 }}
85-
>
86-
<AppHeader studyIds={globalConfig.configsList} />
87-
<ConfigSwitcher
88-
globalConfig={globalConfig}
89-
studyConfigs={studyConfigs}
90-
/>
91-
</AppShell>
92-
</>
93-
)}
114+
element={<HomeRoute globalConfig={globalConfig} />}
94115
/>
95116
<Route
96117
path="/:studyId/*"

src/analysis/individualStudy/replay/AllTasksTimeline.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export function AllTasksTimeline({
119119
const isCorrect = componentAnswersAreCorrect(answer.answer, answer.correctAnswer, resolvedComponent?.response);
120120
const hasCorrect = !!((resolvedComponent && resolvedComponent.correctAnswer) || answer.correctAnswer.length > 0);
121121
const hasAudio = resolvedComponent?.recordAudio ?? studyConfig?.uiConfig?.recordAudio ?? false;
122+
const hasScreenRecording = resolvedComponent?.recordScreen ?? studyConfig?.uiConfig?.recordScreen ?? false;
122123

123124
return {
124125
line: <SingleTaskLabelLines key={name} labelHeight={currentHeight * LABEL_GAP} height={maxHeight} xScale={scale} scaleStart={scaleStart} />,
@@ -147,7 +148,7 @@ export function AllTasksTimeline({
147148
)}
148149
>
149150
<g>
150-
<SingleTask incomplete={answer.startTime === 0} isCorrect={isCorrect} hasCorrect={hasCorrect} hasAudio={hasAudio} key={name} labelHeight={currentHeight * LABEL_GAP} height={maxHeight} name={name} xScale={scale} scaleStart={scaleStart} scaleEnd={scaleEnd} trialOrder={answer.trialOrder} participantId={participantData.participantId} studyId={studyId} condition={conditionParam} />
151+
<SingleTask incomplete={answer.startTime === 0} isCorrect={isCorrect} hasCorrect={hasCorrect} hasAudio={hasAudio} hasScreenRecording={hasScreenRecording} key={name} labelHeight={currentHeight * LABEL_GAP} height={maxHeight} name={name} xScale={scale} scaleStart={scaleStart} scaleEnd={scaleEnd} trialOrder={answer.trialOrder} participantId={participantData.participantId} studyId={studyId} condition={conditionParam} />
151152
</g>
152153
</Tooltip>),
153154
};

src/analysis/individualStudy/replay/SingleTask.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as d3 from 'd3';
44

55
import { useResizeObserver } from '@mantine/hooks';
66
import {
7-
IconCheck, IconMicrophone, IconProgress, IconX,
7+
IconCheck, IconDeviceDesktop, IconMicrophone, IconProgress, IconX,
88
} from '@tabler/icons-react';
99
import { useNavigateToTrial } from '../../../utils/useNavigateToTrial';
1010

@@ -24,6 +24,7 @@ export function SingleTask({
2424
isCorrect,
2525
hasCorrect,
2626
hasAudio,
27+
hasScreenRecording,
2728
scaleStart,
2829
scaleEnd,
2930
incomplete,
@@ -39,6 +40,7 @@ export function SingleTask({
3940
isCorrect: boolean,
4041
hasCorrect: boolean,
4142
hasAudio: boolean,
43+
hasScreenRecording: boolean,
4244
scaleStart: number,
4345
scaleEnd: number,
4446
incomplete: boolean,
@@ -52,7 +54,7 @@ export function SingleTask({
5254
const [ref, { width: labelWidth }] = useResizeObserver();
5355

5456
const navigateToTrial = useNavigateToTrial();
55-
const iconCount = (incomplete || hasCorrect ? 1 : 0) + (hasAudio ? 1 : 0);
57+
const iconCount = (incomplete || hasCorrect ? 1 : 0) + (hasAudio ? 1 : 0) + (hasScreenRecording ? 1 : 0);
5658
const iconsWidth = iconCount * (ICON_SIZE + ICON_GAP);
5759

5860
return (
@@ -93,6 +95,12 @@ export function SingleTask({
9395
<Text lineClamp={1} ref={ref} mx={0} style={{ width: 'fit-content', fontWeight: 600 }} size="12px">
9496
{name}
9597
</Text>
98+
{hasScreenRecording && (
99+
<IconDeviceDesktop
100+
color="orange"
101+
size="14"
102+
/>
103+
)}
96104
{hasAudio && (
97105
<IconMicrophone
98106
color="orange"

0 commit comments

Comments
 (0)