Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat v3.4.1 #511

Merged
merged 48 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c725d9b
wip: remove the type field from the login inputs
RobertGemmaJr Jun 12, 2024
30a36f0
wip: Hook up a loading state for the login button
RobertGemmaJr Jun 12, 2024
fceda31
ref: Remove disabled flag, use "required" so it works on the underlyi…
RobertGemmaJr Jun 12, 2024
e27dac4
ref: Change the error message since it doesnt always show up on inval…
RobertGemmaJr Jun 12, 2024
4a38f4d
chore: Add link to docs in the docstring
RobertGemmaJr Jun 12, 2024
788c6ea
refactor: change introduction trial's stimulus from h1 tags to p tags
YUUU23 Jun 13, 2024
0853288
Merge pull request #491 from brown-ccv/ref-login-cleanup
RobertGemmaJr Jun 13, 2024
ddaa8fa
refactor: add p tag to prompt and change back h1 tag for stimulus
YUUU23 Jun 13, 2024
0bb2bdb
Merge branch 'main' into feat-v3.4.1
YUUU23 Jun 18, 2024
953a75c
Merge branch 'feat-v3.4.1' into ref-intro-p-tag
YUUU23 Jun 18, 2024
b47d5cb
Merge pull request #493 from brown-ccv/ref-intro-p-tag
YUUU23 Jun 18, 2024
2101a4f
feat: add sample countdown trial that counts down before the start of…
YUUU23 Jun 19, 2024
9fd3dfb
build: upgrade deps
RobertGemmaJr Jun 24, 2024
01be0a0
build: Upgrade jsPsych survey dependency to latest version
RobertGemmaJr Jun 24, 2024
88c3fd6
Merge branch 'build-upgrade' into feat-v3.4.1
RobertGemmaJr Jun 24, 2024
474361f
build: upgrade Electron
RobertGemmaJr Jun 24, 2024
cbd7745
chore: lock
RobertGemmaJr Jun 24, 2024
5c1f847
refactor: change argument name of buildCountdownTrial, change to more…
YUUU23 Jun 25, 2024
642f183
refactor: move helper functions into utils.js, provide more details f…
YUUU23 Jun 26, 2024
890de74
Merge pull request #496 from brown-ccv/add-countdown-trial
YUUU23 Jun 26, 2024
94ba324
refactor: full screen trial with additional data from gearshift proje…
YUUU23 Jun 26, 2024
6c7c2cb
feat: add typedef.js in lib and update documentation in index.js to r…
YUUU23 Jul 6, 2024
e5cee24
feat: add getCurrentTrialData form gearshift into utils.js
YUUU23 Jul 6, 2024
9cb6585
feat: add getLastTrialData from gearshift into src/lib/utils.js
YUUU23 Jul 6, 2024
bfce4cb
feat: from gearshift, move in getRandomElement function into src/lib/…
YUUU23 Jul 6, 2024
c12885f
Merge pull request #507 from brown-ccv/add-getRandomElement
YUUU23 Jul 8, 2024
0c43906
Merge branch 'feat-v3.4.1' into add-getLastTrialDataUtility
YUUU23 Jul 8, 2024
a1ba0e1
Merge pull request #506 from brown-ccv/add-getLastTrialDataUtility
YUUU23 Jul 8, 2024
e9cda89
Merge branch 'feat-v3.4.1' into add-getCurrentTrialData
YUUU23 Jul 8, 2024
65462c5
Update utils.js (fix accidentally deleted comment starts)
YUUU23 Jul 8, 2024
0709aec
Merge pull request #505 from brown-ccv/add-getCurrentTrialData
YUUU23 Jul 8, 2024
89e2e3a
Merge pull request #502 from brown-ccv/add-additional-data-fs
YUUU23 Jul 8, 2024
44311a0
refactor: change Object general type to JsPsych
YUUU23 Jul 9, 2024
de2541b
refactor: import type correctly
YUUU23 Jul 9, 2024
7a3affa
fix: eslint path and types import
YUUU23 Jul 9, 2024
73ff259
Update startProcedure.js to use right JsPsych type
YUUU23 Jul 9, 2024
d6a05c6
object to jspsych
YUUU23 Jul 9, 2024
2d3b804
Merge branch 'add-typedef' of https://github.com/brown-ccv/honeycomb …
YUUU23 Jul 9, 2024
f2cb44b
Merge pull request #504 from brown-ccv/add-typedef
YUUU23 Jul 9, 2024
57f625b
chore: upgrade
RobertGemmaJr Jul 10, 2024
18fc6a0
Merge branch 'feat-v3.4.1' into build-upgrade
RobertGemmaJr Jul 11, 2024
889a825
chore: upgrade
RobertGemmaJr Jul 11, 2024
c7a43a7
add: set up mockbinding when CONTINUE_ANYWAY is true
YUUU23 Jul 12, 2024
366f014
change log.info text
YUUU23 Jul 12, 2024
32ed89b
delete: continue_anyway returning from function
YUUU23 Jul 12, 2024
211ecb2
Merge pull request #498 from brown-ccv/build-upgrade
RobertGemmaJr Jul 12, 2024
ef8e5ed
remove CONTINUE_ANYWAY variable
YUUU23 Jul 12, 2024
c008e64
Merge pull request #510 from brown-ccv/add-mockbind
YUUU23 Jul 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ module.exports = {
react: {
version: "detect",
},
jsdoc: {
tagNamePreference: {
typedef: {
definedInFiles: ["src/lib/typedef.js"],
},
},
},
"import/resolver": {
node: {
extensions: [".js", ".jsx"],
Expand Down
8,443 changes: 5,449 additions & 2,994 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@jspsych/plugin-initialize-camera": "^1.0.1",
"@jspsych/plugin-instructions": "^1.1.3",
"@jspsych/plugin-preload": "^1.1.2",
"@jspsych/plugin-survey": "^0.2.2",
"@jspsych/plugin-survey": "^1.0.1",
"bootstrap": "^5.2.0-beta1",
"electron-log": "^5.0.0",
"electron-squirrel-startup": "^1.0.0",
Expand Down Expand Up @@ -53,7 +53,7 @@
"cross-env": "^7.0.3",
"cz-conventional-changelog": "^3.2.0",
"dotenv-cli": "^7.0.0",
"electron": "^30.0.1",
"electron": "^31.0.2",
"eslint": "^8.54.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.29.0",
Expand Down
21 changes: 13 additions & 8 deletions public/electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const { app, BrowserWindow, ipcMain, dialog } = require("electron");
const log = require("electron-log");
const _ = require("lodash");

const { MockBinding } = require("@serialport/binding-mock");
const { SerialPortStream } = require("@serialport/stream");
const { getPort, sendToPort } = require("./serialPort");

// TODO @brown-ccv #460: Add serialport's MockBinding for the "Continue Anyway": https://serialport.io/docs/guide-testing
Expand All @@ -30,7 +32,6 @@ const GIT_VERSION = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../versi
const ELECTRON_START_URL = process.env.ELECTRON_START_URL;

let CONFIG; // Honeycomb configuration object
let CONTINUE_ANYWAY; // Whether to continue the experiment with no hardware connected (option is only available in dev mode)

let TEMP_FILE; // Path to the temporary output file
let OUT_PATH; // Path to the final output folder (on the Desktop)
Expand Down Expand Up @@ -364,7 +365,6 @@ async function setUpPort() {
app.exit();
} else {
// User selected "Continue Anyway", trigger port is not connected
CONTINUE_ANYWAY = true;
TRIGGER_PORT = undefined;
}
});
Expand All @@ -381,10 +381,7 @@ async function setUpPort() {
* @param code The code to send via USB
*/
function handleEventSend(code) {
log.info(`Sending USB event ${code} to port ${TRIGGER_PORT}`);

// Early return when running in development (no trigger port is expected)
if (CONTINUE_ANYWAY) return;
log.info(`Sending USB event: ${code}`);

if (TRIGGER_PORT !== undefined) {
sendToPort(TRIGGER_PORT, code);
Expand Down Expand Up @@ -415,8 +412,16 @@ function handleEventSend(code) {
setUpPort().then(() => handleEventSend(code));
break;
case 2:
// User selects "Continue Anyway", we must be in dev mode
CONTINUE_ANYWAY = true;
// set-up mockbinding and open port for communication if continue anyway is clicked
MockBinding.createPort("/dev/ROBOT", {
echo: true,
record: true,
});
TRIGGER_PORT = new SerialPortStream({
binding: MockBinding,
path: "/dev/ROBOT",
baudRate: 14400,
});
break;
}
}
Expand Down
32 changes: 18 additions & 14 deletions src/App/components/Login.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropTypes from "prop-types";
import React, { useEffect } from "react";
import React from "react";
import { Button, Form } from "react-bootstrap";

export default function Login({
Expand All @@ -11,23 +11,31 @@ export default function Login({
// State variables for login screen
const [participantID, setParticipantID] = React.useState(initialParticipantID);
const [studyID, setStudyID] = React.useState(initialStudyID);

// State variable for handling errors
const [isError, setIsError] = React.useState(false);

// State variable for handling loading states
const [isLoading, setIsLoading] = React.useState(false);

// Update local participantID if it changes upstream
useEffect(() => {
React.useEffect(() => {
setParticipantID(initialParticipantID);
}, [initialParticipantID]);

// Update local studyID if it changes upstream
useEffect(() => {
React.useEffect(() => {
setStudyID(initialStudyID);
}, [initialStudyID]);

// Function used to validate and log in participant
function handleSubmit(e) {
e.preventDefault();
setIsLoading(true);

// Logs user in if a valid participant/study id combination is given
validationFunction(studyID, participantID).then((isValid) => {
setIsLoading(false);
setIsError(!isValid);
if (isValid) handleLogin(studyID, participantID);
});
Expand All @@ -41,32 +49,28 @@ export default function Login({
<Form.Label>Participant ID</Form.Label>
<Form.Control
autoFocus
type="participantID"
name="participantID"
required={true}
value={participantID}
onChange={(e) => setParticipantID(e.target.value)}
/>
</Form.Group>
<Form.Group className="width-100" size="lg" controlId="studyID">
<Form.Label>Study ID</Form.Label>
<Form.Control
type="studyID"
name="studyID"
required={true}
value={studyID}
onChange={(e) => setStudyID(e.target.value)}
/>
</Form.Group>
<Button
style={{ width: "100%" }}
block
size="lg"
type="submit"
disabled={studyID.length === 0 || participantID.length === 0}
>
Log In
<Button style={{ width: "100%" }} block size="lg" type="submit">
{isLoading ? "Submitting..." : "Log In"}
</Button>
</Form>
{isError ? (
<div className="alert alert-danger" role="alert">
No matching experiment found for this participant and study
Unable to begin the study. Is your login information correct?
</div>
) : null}
</div>
Expand Down
9 changes: 7 additions & 2 deletions src/experiment/honeycomb.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { buildHoneycombProcedure } from "./procedures/honeycombProcedure";
import { buildStartProcedure } from "./procedures/startProcedure";

import { buildDebriefTrial, instructionsTrial, preloadTrial } from "./trials/honeycombTrials";
import { buildCountdownTrial } from "./trials/countdown";

/**
* ! This file should not be edited! Instead, create a new file with the name of your task
Expand Down Expand Up @@ -31,8 +32,8 @@ export const honeycombOptions = {
* Take a look at how the code here compares to the jsPsych documentation!
* See the jsPsych documentation for more: https://www.jspsych.org/7.3/tutorials/rt-task/
*
* @param {Object} jsPsych The jsPsych instance being used to run the task
* @returns {Object} A jsPsych timeline object
* @param {JsPsych} jsPsych The jsPsych instance being used to run the task
* @returns {object} A jsPsych timeline object
*/
export function buildHoneycombTimeline(jsPsych) {
// Build the trials that make up the start procedure
Expand All @@ -47,8 +48,12 @@ export function buildHoneycombTimeline(jsPsych) {
// Builds the trials that make up the end procedure
const endProcedure = buildEndProcedure(jsPsych);

// Builds a countdown trial that counts down for 3000ms
const countdownTrial = buildCountdownTrial(3000);

const timeline = [
startProcedure,
countdownTrial,
preloadTrial,
instructionsTrial,
honeycombProcedure,
Expand Down
6 changes: 3 additions & 3 deletions src/experiment/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* ! Your timeline and options should be built in a newly created file, not this one
* TODO @brown-ccv: Link "Quick Start" step once's it's built into the docs
* https://brown-ccv.github.io/honeycomb-docs/docs/quick_start#2-add-a-file-for-the-task
*/
import { buildHoneycombTimeline, honeycombOptions } from "./honeycomb";

Expand All @@ -20,7 +20,7 @@ export const jsPsychOptions = honeycombOptions;
/**
* Builds the experiment's timeline that jsPsych will run
* The instance of jsPsych passed in will include jsPsychOptions from above
* @param {Object} jsPsych The jsPsych instance that is running the experiment
* @param {JsPsych} jsPsych The jsPsych instance that is running the experiment
* @param {string} studyID The ID of the study that was just logged into
* @param {string} participantID The ID of the participant that was just logged in
* @returns The timeline for JsPsych to run
Expand All @@ -30,7 +30,7 @@ export function buildTimeline(jsPsych, studyID, participantID) {

/**
* ! Your timeline should be built in a newly created function, not this one
* TODO @brown-ccv: Link "Quick Start" step once's it's built into the docs
* https://brown-ccv.github.io/honeycomb-docs/docs/quick_start#2-add-a-file-for-the-task
*/
const timeline = buildHoneycombTimeline(jsPsych);
return timeline;
Expand Down
2 changes: 1 addition & 1 deletion src/experiment/procedures/endProcedure.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { exitFullscreenTrial } from "../trials/fullscreen";
* 1) Trial used to complete the user's camera recording is displayed
* 2) The experiment exits fullscreen
*
* @param {Object} jsPsych The jsPsych instance being used to run the task
* @param {JsPsych} jsPsych The jsPsych instance being used to run the task
* @returns {Object} A jsPsych (nested) timeline object
*/
export function buildEndProcedure(jsPsych) {
Expand Down
2 changes: 1 addition & 1 deletion src/experiment/procedures/honeycombProcedure.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { buildFixationTrial } from "../trials/fixation";
*
* Note that the block is conditionally rendered and repeated based on the task settings
*
* @param {Object} jsPsych The jsPsych instance being used to run the task
* @param {JsPsych} jsPsych The jsPsych instance being used to run the task
* @returns {Object} A jsPsych (nested) timeline object
*/
export function buildHoneycombProcedure(jsPsych) {
Expand Down
2 changes: 1 addition & 1 deletion src/experiment/procedures/startProcedure.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { introductionTrial } from "../trials/introduction";
* 4) Trials used to set up a photodiode and trigger box are displayed (if applicable)
* 5) Trials used to set up the user's camera are displayed (if applicable)
*
* @param {Object} jsPsych The jsPsych instance being used to run the task
* @param {JsPsych} jsPsych The jsPsych instance being used to run the task
* @returns {Object} A jsPsych (nested) timeline object
*/
export function buildStartProcedure(jsPsych) {
Expand Down
2 changes: 1 addition & 1 deletion src/experiment/trials/camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const WEBCAM_ID = "webcam";

/**
* A trial that begins recording the participant using their computer's default camera
* @param {Object} jsPsych The jsPsych instance being used to run the task
* @param {JsPsych} jsPsych The jsPsych instance being used to run the task
* @returns {Object} A jsPsych trial object
*/
// TODO @brown-ccv #301: Use jsPsych extension, deprecate this function
Expand Down
33 changes: 33 additions & 0 deletions src/experiment/trials/countdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";
import { h1 } from "../../lib/markup/tags";
import { getTimeString } from "../../lib/utils";

/**
* a sample countdown trial that counts down ms before another trial begins
*
* @param {number} ms - millisecond to countdown
* @returns a JS object as a trial
*/
export function buildCountdownTrial(waitTime) {
return {
type: htmlKeyboardResponse,
stimulus:
h1("The next part of the experiment will start in") +
h1(getTimeString(waitTime), {
id: "clock",
}),
choices: "NO_KEYS",
trial_duration: waitTime + 20,
on_load: function () {
const startTime = performance.now();
const interval = setInterval(function () {
const timeLeft = waitTime - (performance.now() - startTime);
document.querySelector("#clock").innerHTML = getTimeString(timeLeft);
if (timeLeft <= 0) {
document.querySelector("#clock").innerHTML = "0:00";
clearInterval(interval);
}
}, 250);
},
};
}
3 changes: 1 addition & 2 deletions src/experiment/trials/fixation.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";

import { SETTINGS, config } from "../../config/main";
import { eventCodes } from "../../config/trigger";
import { pdSpotEncode, photodiodeGhostBox } from "../../lib/markup/photodiode";
import { div } from "../../lib/markup/tags";

/**
* Builds a trial with a fixation dot and optional photodiode box.
* @param {Object} jsPsych The global jsPsych object used to build the trial
* @param {JsPsych} jsPsych The global jsPsych object used to build the trial
* @returns {Object} A jsPsych trial object
*/
export function buildFixationTrial(jsPsych) {
Expand Down
6 changes: 6 additions & 0 deletions src/experiment/trials/fullscreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import jsPsychFullscreen from "@jspsych/plugin-fullscreen";
export const enterFullscreenTrial = {
type: jsPsychFullscreen,
fullscreen_mode: true,
on_finish: (data) => {
// Record some additional information about the user's screen
data.screen_width = screen.width;
data.screen_height = screen.height;
data.screen_pixel_ratio = window.devicePixelRatio;
},
};

/**
Expand Down
4 changes: 2 additions & 2 deletions src/experiment/trials/introduction.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";

import { LANGUAGE } from "../../config/main";
import { div, h1 } from "../../lib/markup/tags";
import { div, p, h1 } from "../../lib/markup/tags";

/** Task that displays a introduction message with the photodiode ghost box */
export const introductionTrial = {
Expand All @@ -11,5 +11,5 @@ export const introductionTrial = {
const introductionMarkup = h1(LANGUAGE.trials.introduction);
return div(introductionMarkup);
},
prompt: LANGUAGE.prompts.continue.prompt,
prompt: p(LANGUAGE.prompts.continue.prompt),
};
1 change: 1 addition & 0 deletions src/lib/typedef.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** @typedef {import("jspsych").JsPsych} JsPsych */
Loading
Loading