Skip to content

Commit

Permalink
Merge pull request #151 from concord-consortium/187852896-disable-inp…
Browse files Browse the repository at this point in the history
…uts-during-data-collection

feat: Disable inputs during timeseries collection [PT-187852896]
  • Loading branch information
dougmartin authored Jun 26, 2024
2 parents 6ddc5b8 + 259b595 commit cede052
Show file tree
Hide file tree
Showing 16 changed files with 131 additions and 52 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
"ace-builds": "^1.4.8",
"ajv": "5.5.2",
"aws-sdk": "^2.454.0",
"classnames": "^2.5.1",
"client-oauth2": "^4.2.5",
"eventemitter3": "^4.0.0",
"firebase": "^7.6.1",
Expand Down
7 changes: 6 additions & 1 deletion src/mobile-app/components/experiment-wrapper.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
padding: 2px 4px;
width: 100%;

@include add-disabled-class();

input{
padding: 0;
width: 100%;
Expand All @@ -43,7 +45,10 @@
.headerBackIcon {
margin: 5px 15px 0 15px;
padding: 0;
&:hover {

@include add-disabled-class();

&:hover:not(.disabled) {
cursor: pointer;
}
svg {
Expand Down
25 changes: 17 additions & 8 deletions src/mobile-app/components/experiment-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState } from "react";
import classNames from "classnames";
import { IExperiment, IExperimentConfig, IExperimentData } from "../../shared/experiment-types";
import { Experiment } from "../../shared/components/experiment";
import { Initials } from "../../shared/components/initials";
Expand Down Expand Up @@ -29,6 +30,7 @@ const experimentConfig: IExperimentConfig = {

export const ExperimentWrapper: React.FC<IProps> = ({ experiment, experimentIdx, data, onDataChange, onBackBtnClick, onUpload, embeddedPreview }) => {
const [editing, isEditing ] = useState(false);
const [inputDisabled, setInputDisabled] = useState(false);
const { metadata } = experiment;
const workSpaceClass = embeddedPreview ? `${css.workspace} ${css.embeddedPreview}`: css.workspace;

Expand Down Expand Up @@ -68,27 +70,34 @@ export const ExperimentWrapper: React.FC<IProps> = ({ experiment, experimentIdx,
return (
<div>
<div className={css.header}>
<div className={css.headerBackIcon} onClick={onBackBtnClick}><Icon name="arrow_back"/></div>
<div className={classNames(css.headerBackIcon, {[css.disabled]: inputDisabled})} onClick={inputDisabled ? undefined : onBackBtnClick}><Icon name="arrow_back"/></div>
<Initials metadata={metadata} active={true}/>
<div className={css.headerTitle}>
<div className={css.name}>
<div className={classNames(css.name, {[css.disabled]: inputDisabled})}>
{editing
? <input defaultValue={`${name}`} onChange={saveExperimentName} onBlur={handleRename} onKeyDown={handleEnter} autoFocus={true} />
: <div onClick={handleRename}>{name}</div>
? <input defaultValue={`${name}`} onChange={inputDisabled ? undefined : saveExperimentName} onBlur={inputDisabled ? undefined : handleRename} onKeyDown={inputDisabled ? undefined : handleEnter} autoFocus={true} />
: <div onClick={inputDisabled ? undefined : handleRename}>{name}</div>
}
</div>
<div>{title}</div>
</div>
<div className={css.headerMenu}>
<MenuComponent>
<MenuItemComponent icon={"label"} onClick={handleSave}>Save</MenuItemComponent>
<MenuItemComponent icon={"upload"} onClick={onUpload}>Upload</MenuItemComponent>
<MenuItemComponent icon={"create"} onClick={handleRename}>Rename</MenuItemComponent>
<MenuItemComponent icon={"label"} disabled={inputDisabled} onClick={handleSave}>Save</MenuItemComponent>
<MenuItemComponent icon={"upload"} disabled={inputDisabled} onClick={onUpload}>Upload</MenuItemComponent>
<MenuItemComponent icon={"create"} disabled={inputDisabled} onClick={handleRename}>Rename</MenuItemComponent>
</MenuComponent>
</div>
</div>
<div className={workSpaceClass}>
<Experiment experiment={experiment} config={experimentConfig} data={data} onDataChange={onDataChange} />
<Experiment
experiment={experiment}
config={experimentConfig}
data={data}
onDataChange={onDataChange}
inputDisabled={inputDisabled}
setInputDisabled={setInputDisabled}
/>
</div>
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions src/mobile-app/components/sensor.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
align-items: center;
flex-grow: 1; /* to allow the label to take up as much room as possible */

@include add-disabled-class();

// for selectable sensor
select {
margin-left: 7px;
Expand Down
33 changes: 19 additions & 14 deletions src/mobile-app/components/sensor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState, useRef, useMemo, useEffect } from "react";
import classNames from "classnames";
import { SensorValue } from "./sensor-value";
import { Sensor, IConnectDevice, SelectDeviceFn, ITimeSeriesCapabilities, MaxNumberOfTimeSeriesValues, ISensorValues } from "../../sensors/sensor";
import { useSensor } from "../hooks/use-sensor";
Expand All @@ -15,25 +16,26 @@ interface ISensorSelectorProps {
devices: IConnectDevice[];
selectDevice: SelectDeviceFn;
cancel: () => void;
inputDisabled?: boolean;
}

const maxTime = 3;

export const SensorSelectorComponent: React.FC<ISensorSelectorProps> = ({devices, selectDevice, cancel}) => {
export const SensorSelectorComponent: React.FC<ISensorSelectorProps> = ({devices, selectDevice, cancel, inputDisabled}) => {
const sortedDevices = devices.sort((a, b) => a.id.localeCompare(b.id));
const handleCancel = () => cancel();
return (
<div className={css.sensorSelector}>
<div className={css.sensorSelectorHeader}>
<div className={css.sensorSelectorHeaderTitle}>Choose a sensor...</div>
<div className={css.sensorSelectorHeaderButtons}>
<div className={css.sensorSelectorHeaderButton} onClick={handleCancel}>Cancel</div>
<div className={css.sensorSelectorHeaderButton} onClick={inputDisabled ? undefined : handleCancel}>Cancel</div>
</div>
</div>
{sortedDevices.map((device, index) => {
const handleSelectDevice = () => selectDevice(device);
return (
<div key={index} className={css.sensorSelectorItem} onClick={handleSelectDevice}>
<div key={index} className={css.sensorSelectorItem} onClick={inputDisabled ? undefined : handleSelectDevice}>
<div className={css.sensorSelectorItemName}>{device.name}</div>
<div className={css.sensorSelectorItemRssi}>
<SensorStrength rssi={device.adData.rssi} />
Expand All @@ -54,6 +56,7 @@ interface ISensorComponentProps {
selectableSensorId?: any;
setTimeSeriesMeasurementPeriod?: (measurementPeriod: number) => void;
setSelectableSensorId?: (id: any) => void;
inputDisabled?: boolean;
}

const iconClass = {
Expand All @@ -68,7 +71,7 @@ const iconClassHi = {
error: css.errorIcon
};

export const SensorComponent: React.FC<ISensorComponentProps> = ({sensor, manualEntryMode, setManualEntryMode, isTimeSeries, timeSeriesCapabilities, selectableSensorId, setTimeSeriesMeasurementPeriod, setSelectableSensorId}) => {
export const SensorComponent: React.FC<ISensorComponentProps> = ({sensor, manualEntryMode, setManualEntryMode, isTimeSeries, timeSeriesCapabilities, selectableSensorId, setTimeSeriesMeasurementPeriod, setSelectableSensorId, inputDisabled}) => {
const {connected, connecting, deviceName, values, error} = useSensor(sensor);

const [devicesFound, setDevicesFound] = useState<IConnectDevice[]>([]);
Expand Down Expand Up @@ -159,22 +162,24 @@ export const SensorComponent: React.FC<ISensorComponentProps> = ({sensor, manual
</div>
);

const connectionLabelClassName = classNames(css.connectionLabel, {[css.disabled]: inputDisabled});

const renderError = () => (
<div className={css.connectionLabel}>
<div className={connectionLabelClassName}>
{renderIcon("error")}
{error.toString()}
</div>
);

const renderDisconnected = () => (
<div className={css.connectionLabel} onClick={connect}>
<div className={connectionLabelClassName} onClick={inputDisabled ? undefined : connect}>
{renderIcon("disconnected")}
No Sensor Connected
</div>
);

const renderConnecting = () => (
<div className={css.connectionLabel}>
<div className={connectionLabelClassName}>
{renderIcon("connected")}
{inCordova ? "Searching..." : "Connecting..."}
</div>
Expand All @@ -186,14 +191,14 @@ export const SensorComponent: React.FC<ISensorComponentProps> = ({sensor, manual
}

return (
<select onChange={handleSelectSelectableSensor}>
<select onChange={handleSelectSelectableSensor} disabled={inputDisabled}>
{sensor.selectableSensors.map(s => <option key={s.internalId} value={s.internalId}>{s.name}</option>)}
</select>
);
};

const renderConnected = () => (
<div className={css.connectionLabel}>
<div className={connectionLabelClassName}>
{renderIcon("connected")}
Connected: {renderDeviceName()}
</div>
Expand All @@ -207,10 +212,10 @@ export const SensorComponent: React.FC<ISensorComponentProps> = ({sensor, manual
return (
<MenuComponent>
{manualEntryMode && canSwitchModes
? <MenuItemComponent onClick={setSensorMode} icon="sensor">Sensor Mode</MenuItemComponent>
? <MenuItemComponent disabled={inputDisabled} onClick={setSensorMode} icon="sensor">Sensor Mode</MenuItemComponent>
: <>
{connected ? <MenuItemComponent onClick={disconnect}>Disconnect</MenuItemComponent> : <MenuItemComponent icon="settings_input_antenna" onClick={connect}>Connect</MenuItemComponent>}
{canSwitchModes ? <MenuItemComponent onClick={setEditMode} icon="create">Edit Mode</MenuItemComponent> : undefined}
{connected ? <MenuItemComponent disabled={inputDisabled} onClick={disconnect}>Disconnect</MenuItemComponent> : <MenuItemComponent icon="settings_input_antenna" disabled={inputDisabled} onClick={connect}>Connect</MenuItemComponent>}
{canSwitchModes ? <MenuItemComponent disabled={inputDisabled} onClick={setEditMode} icon="create">Edit Mode</MenuItemComponent> : undefined}
</>}
</MenuComponent>
);
Expand Down Expand Up @@ -256,7 +261,7 @@ export const SensorComponent: React.FC<ISensorComponentProps> = ({sensor, manual
<div className={css.tsvInfoRow}>
<div>Samples:</div>
<div>
<select className={css.tsvSampleRate} value={measurementPeriod} onChange={handleMeasurementPeriodChange}>
<select className={css.tsvSampleRate} value={measurementPeriod} onChange={handleMeasurementPeriodChange} disabled={inputDisabled}>
{timeSeriesPeriods.map(p => <option key={p} value={p}>{`${(1000 / p)}/sec`}</option>)}
</select>
</div>
Expand Down Expand Up @@ -330,7 +335,7 @@ export const SensorComponent: React.FC<ISensorComponentProps> = ({sensor, manual
{error ? renderError() : (connected ? renderConnected() : (connecting ? renderConnecting() : renderDisconnected()))}
{renderMenu()}
</div>
{showDeviceSelect ? <SensorSelectorComponent devices={devicesFound} selectDevice={handleSelectDevice} cancel={handleCancelSelectDevice} /> : undefined}
{showDeviceSelect ? <SensorSelectorComponent devices={devicesFound} selectDevice={handleSelectDevice} cancel={handleCancelSelectDevice} inputDisabled={inputDisabled} /> : undefined}
{isTimeSeries ? renderTimeSeries() : renderValues()}
</div>
);
Expand Down
5 changes: 4 additions & 1 deletion src/shared/components/data-table-field.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ $headerBorder: #fff;
display: flex;
justify-content: center;
align-items: center;

@include add-disabled-class($opacity: 0.35);

&.active {
background-color: $sensorGreenLight1;
&.refresh {
Expand All @@ -171,7 +174,7 @@ $headerBorder: #fff;
&.record {
background-color: $sensorGreenLight1;
}
&:hover {
&:hover:not(.disabled) {
cursor: pointer;
}
}
Expand Down
Loading

0 comments on commit cede052

Please sign in to comment.