misc fixes and updates
parent
6f4e6b7af6
commit
feb7b07a6f
|
@ -4,7 +4,7 @@ describe("fetchLabFeatures", () => {
|
|||
Object.defineProperty(window.location, "reload", { value: jest.fn() });
|
||||
it("basically just initializes stuff", () => {
|
||||
const val = fetchLabFeatures(jest.fn());
|
||||
expect(val.length).toBe(10);
|
||||
expect(val.length).toBe(9);
|
||||
expect(val[0].value).toBeFalsy();
|
||||
const { callback } = val[0];
|
||||
if (callback) {
|
||||
|
|
|
@ -38,18 +38,6 @@ export const fetchLabFeatures =
|
|||
storageKey: BooleanSetting.hide_webcam_widget,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Dynamic map size"),
|
||||
description: t(Content.DYNAMIC_MAP_SIZE),
|
||||
storageKey: BooleanSetting.dynamic_map,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Double default map dimensions"),
|
||||
description: t(Content.DOUBLE_MAP_DIMENSIONS),
|
||||
storageKey: BooleanSetting.map_xl,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Display plant animations"),
|
||||
description: t(Content.PLANT_ANIMATIONS),
|
||||
|
@ -91,6 +79,12 @@ export const fetchLabFeatures =
|
|||
value: false,
|
||||
displayInvert: true,
|
||||
},
|
||||
{
|
||||
name: t("Dynamic map size"),
|
||||
description: t(Content.DYNAMIC_MAP_SIZE),
|
||||
storageKey: BooleanSetting.dynamic_map,
|
||||
value: false
|
||||
},
|
||||
].map(fetchSettingValue(getConfigValue)));
|
||||
|
||||
/** Always allow toggling from true => false (deactivate).
|
||||
|
|
|
@ -72,7 +72,7 @@ describe("<Move />", () => {
|
|||
it("changes step size", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = mount(<Move {...p} />);
|
||||
clickButton(wrapper, 1, "1");
|
||||
clickButton(wrapper, 0, "1");
|
||||
expect(p.dispatch).toHaveBeenCalledWith({
|
||||
type: Actions.CHANGE_STEP_SIZE,
|
||||
payload: 1
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { Widget, WidgetBody, WidgetHeader } from "../../ui";
|
||||
import { EStopButton } from "../../devices/components/e_stop_btn";
|
||||
import { MustBeOnline } from "../../devices/must_be_online";
|
||||
import { validBotLocationData } from "../../util";
|
||||
import { toggleWebAppBool } from "../../config_storage/actions";
|
||||
|
@ -37,10 +35,6 @@ export class Move extends React.Component<MoveProps, {}> {
|
|||
toggle={this.toggle}
|
||||
getValue={this.getValue} />
|
||||
</Popover>
|
||||
<EStopButton
|
||||
bot={this.props.bot}
|
||||
forceUnlock={this.getValue(
|
||||
BooleanSetting.disable_emergency_unlock_confirmation)} />
|
||||
</WidgetHeader>
|
||||
<WidgetBody>
|
||||
<MustBeOnline
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { PeripheralForm } from "../peripheral_form";
|
||||
import { TaggedPeripheral, SpecialStatus } from "farmbot";
|
||||
import { PeripheralFormProps } from "../interfaces";
|
||||
import { Actions } from "../../../constants";
|
||||
|
||||
describe("<PeripheralForm/>", function () {
|
||||
describe("<PeripheralForm/>", () => {
|
||||
const dispatch = jest.fn();
|
||||
const peripherals: TaggedPeripheral[] = [
|
||||
{
|
||||
|
@ -27,22 +29,45 @@ describe("<PeripheralForm/>", function () {
|
|||
}
|
||||
},
|
||||
];
|
||||
const fakeProps = (): PeripheralFormProps => ({ dispatch, peripherals });
|
||||
|
||||
it("renders a list of editable peripherals, in sorted order", function () {
|
||||
const expectedPayload = (update: Object) =>
|
||||
expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
update
|
||||
}),
|
||||
type: Actions.EDIT_RESOURCE
|
||||
});
|
||||
|
||||
it("renders a list of editable peripherals, in sorted order", () => {
|
||||
const form = mount(<PeripheralForm dispatch={dispatch}
|
||||
peripherals={peripherals} />);
|
||||
const inputs = form.find("input");
|
||||
const buttons = form.find("button");
|
||||
expect(inputs.at(0).props().value).toEqual("GPIO 2");
|
||||
inputs.at(0).simulate("change");
|
||||
expect(inputs.at(1).props().value).toEqual("2");
|
||||
inputs.at(1).simulate("change");
|
||||
expect(inputs.at(1).props().value).toEqual("GPIO 13 - LED");
|
||||
});
|
||||
|
||||
it("updates label", () => {
|
||||
const p = fakeProps();
|
||||
const form = shallow(<PeripheralForm {...p} />);
|
||||
const inputs = form.find("input");
|
||||
inputs.at(0).simulate("change", { currentTarget: { value: "GPIO 3" } });
|
||||
expect(p.dispatch).toHaveBeenCalledWith(
|
||||
expectedPayload({ label: "GPIO 3" }));
|
||||
});
|
||||
|
||||
it("updates pin", () => {
|
||||
const p = fakeProps();
|
||||
const form = shallow(<PeripheralForm {...p} />);
|
||||
form.find("FBSelect").at(0).simulate("change", { value: 3 });
|
||||
expect(p.dispatch).toHaveBeenCalledWith(expectedPayload({ pin: 3 }));
|
||||
});
|
||||
|
||||
it("deletes peripheral", () => {
|
||||
const p = fakeProps();
|
||||
const form = shallow(<PeripheralForm {...p} />);
|
||||
const buttons = form.find("button");
|
||||
buttons.at(0).simulate("click");
|
||||
expect(inputs.at(2).props().value).toEqual("GPIO 13 - LED");
|
||||
inputs.at(2).simulate("change");
|
||||
expect(inputs.at(3).props().value).toEqual("13");
|
||||
inputs.at(3).simulate("change");
|
||||
buttons.at(1).simulate("click");
|
||||
expect(dispatch).toHaveBeenCalledTimes(6);
|
||||
expect(p.dispatch).toHaveBeenCalledWith(expect.any(Function));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,35 +1,44 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { destroy, edit } from "../../api/crud";
|
||||
import { PeripheralFormProps } from "./interfaces";
|
||||
import { sortResourcesById } from "../../util";
|
||||
import { KeyValEditRow } from "../key_val_edit_row";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { Row, Col, FBSelect } from "../../ui";
|
||||
import {
|
||||
pinDropdowns
|
||||
} from "../../sequences/step_tiles/pin_and_peripheral_support";
|
||||
|
||||
export function PeripheralForm(props: PeripheralFormProps) {
|
||||
const { dispatch, peripherals } = props;
|
||||
|
||||
return <div>
|
||||
{sortResourcesById(peripherals).map(p => {
|
||||
|
||||
return <KeyValEditRow
|
||||
key={p.uuid}
|
||||
label={p.body.label}
|
||||
onLabelChange={(e) => {
|
||||
const { value } = e.currentTarget;
|
||||
dispatch(edit(p, { label: value }));
|
||||
return <Row key={p.uuid + p.body.id}>
|
||||
<Col xs={6}>
|
||||
<input type="text"
|
||||
placeholder={t("Name")}
|
||||
value={p.body.label}
|
||||
onChange={e =>
|
||||
dispatch(edit(p, { label: e.currentTarget.value }))} />
|
||||
</Col>
|
||||
<Col xs={4}>
|
||||
<FBSelect
|
||||
selectedItem={{
|
||||
label: t("Pin ") + `${p.body.pin}`,
|
||||
value: p.body.pin || ""
|
||||
}}
|
||||
labelPlaceholder="Name"
|
||||
value={(p.body.pin || "").toString()}
|
||||
valuePlaceholder={t("Pin #")}
|
||||
onValueChange={(e) => {
|
||||
const { value } = e.currentTarget;
|
||||
const update: Partial<typeof p.body> = { pin: parseInt(value, 10) };
|
||||
dispatch(edit(p, update));
|
||||
}}
|
||||
onClick={() => { dispatch(destroy(p.uuid)); }}
|
||||
disabled={false}
|
||||
valueType="number" />;
|
||||
onChange={d =>
|
||||
dispatch(edit(p, { pin: parseInt(d.value.toString(), 10) }))}
|
||||
list={pinDropdowns(n => n)} />
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<button
|
||||
className="red fb-button"
|
||||
onClick={() => dispatch(destroy(p.uuid))}>
|
||||
<i className="fa fa-minus" />
|
||||
</button>
|
||||
</Col>
|
||||
</Row>;
|
||||
})}
|
||||
</div>;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { error } from "farmbot-toastr";
|
||||
import { SensorList } from "./sensor_list";
|
||||
import { SensorForm } from "./sensor_form";
|
||||
|
@ -85,7 +84,7 @@ export class Sensors extends React.Component<SensorsProps, SensorState> {
|
|||
className="fb-button green"
|
||||
type="button"
|
||||
onClick={this.stockSensors}>
|
||||
<i className="fa fa-plus" />
|
||||
<i className="fa fa-plus" style={{ marginRight: "0.5rem" }} />
|
||||
{t("Stock sensors")}
|
||||
</button>
|
||||
</WidgetHeader>
|
||||
|
|
|
@ -286,6 +286,9 @@
|
|||
.save-btn {
|
||||
margin: 1rem;
|
||||
}
|
||||
.location-form {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.add-farm-event-panel button.red,
|
||||
|
|
|
@ -280,7 +280,8 @@ a {
|
|||
.drag-drop-area {
|
||||
&.visible {
|
||||
margin: 0.75rem 0;
|
||||
margin-right: 15px;
|
||||
margin-right: 25px;
|
||||
margin-left: 10px;
|
||||
border-style: dashed;
|
||||
border-width: 2px;
|
||||
border-color: $light_gray;
|
||||
|
@ -984,6 +985,10 @@ ul {
|
|||
}
|
||||
}
|
||||
|
||||
.map-size-inputs {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.release-notes-button {
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
|
@ -1048,9 +1053,6 @@ ul {
|
|||
p {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
.fa-plus {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.sensor-reading-display {
|
||||
&.moisture-sensor {
|
||||
background: linear-gradient(to right, rgba($blue, 0) 20%, $blue 80%, rgba($blue, 0) 85%);
|
||||
|
|
|
@ -70,6 +70,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.sequence-editor-content {
|
||||
hr {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.sequence-editor-tools,
|
||||
.regimen-editor-tools {
|
||||
margin-right: 15px;
|
||||
|
@ -129,7 +135,8 @@
|
|||
}
|
||||
|
||||
.sequence-steps {
|
||||
margin-right: 15px;
|
||||
margin-right: 25px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.step-button-cluster,
|
||||
|
|
|
@ -6,36 +6,22 @@ describe("getDefaultAxisLength()", () => {
|
|||
const axes = getDefaultAxisLength(() => false);
|
||||
expect(axes).toEqual({ x: 2900, y: 1400 });
|
||||
});
|
||||
|
||||
it("returns XL axis lengths", () => {
|
||||
const axes = getDefaultAxisLength(() => true);
|
||||
expect(axes).toEqual({ x: 5900, y: 2900 });
|
||||
});
|
||||
});
|
||||
|
||||
describe("getGridSize()", () => {
|
||||
it("returns default grid size", () => {
|
||||
const grid = getGridSize(
|
||||
k => ({ dynamic_map: false, map_xl: false } as WebAppConfig)[k], {
|
||||
k => ({ dynamic_map: false } as WebAppConfig)[k], {
|
||||
x: { value: 100, isDefault: false },
|
||||
y: { value: 200, isDefault: false }
|
||||
});
|
||||
expect(grid).toEqual({ x: 2900, y: 1400 });
|
||||
});
|
||||
|
||||
it("returns XL grid size", () => {
|
||||
const grid = getGridSize(
|
||||
k => ({ dynamic_map: false, map_xl: true } as WebAppConfig)[k], {
|
||||
x: { value: 100, isDefault: false },
|
||||
y: { value: 200, isDefault: false }
|
||||
});
|
||||
expect(grid).toEqual({ x: 5900, y: 2900 });
|
||||
});
|
||||
|
||||
it("returns custom grid size", () => {
|
||||
const grid = getGridSize(
|
||||
k => ({
|
||||
dynamic_map: false, map_xl: true, map_size_x: 300, map_size_y: 400
|
||||
dynamic_map: false, map_size_x: 300, map_size_y: 400
|
||||
} as WebAppConfig)[k], {
|
||||
x: { value: 100, isDefault: false },
|
||||
y: { value: 200, isDefault: false }
|
||||
|
@ -45,7 +31,7 @@ describe("getGridSize()", () => {
|
|||
|
||||
it("returns grid size using bot size", () => {
|
||||
const grid = getGridSize(
|
||||
k => ({ dynamic_map: true, map_xl: false } as WebAppConfig)[k], {
|
||||
k => ({ dynamic_map: true } as WebAppConfig)[k], {
|
||||
x: { value: 100, isDefault: false },
|
||||
y: { value: 200, isDefault: false }
|
||||
});
|
||||
|
|
|
@ -26,11 +26,7 @@ export const getDefaultAxisLength =
|
|||
if (isFinite(mapSizeX) && isFinite(mapSizeY)) {
|
||||
return { x: mapSizeX, y: mapSizeY };
|
||||
}
|
||||
if (getConfigValue(BooleanSetting.map_xl)) {
|
||||
return { x: 5900, y: 2900 };
|
||||
} else {
|
||||
return { x: 2900, y: 1400 };
|
||||
}
|
||||
};
|
||||
|
||||
export const getGridSize =
|
||||
|
|
|
@ -147,7 +147,7 @@ export function PlantPanel(props: PlantPanelProps) {
|
|||
const {
|
||||
info, onDestroy, updatePlant, dispatch, inSavedGarden, timeSettings
|
||||
} = props;
|
||||
const { name, slug, plantedAt, daysOld, uuid, plantStatus } = info;
|
||||
const { slug, plantedAt, daysOld, uuid, plantStatus } = info;
|
||||
let { x, y } = info;
|
||||
const isEditing = !!onDestroy;
|
||||
if (isEditing) { x = round(x); y = round(y); }
|
||||
|
@ -157,9 +157,6 @@ export function PlantPanel(props: PlantPanelProps) {
|
|||
{t("Plant Info")}
|
||||
</label>
|
||||
<ul>
|
||||
<ListItem name={t("Full Name")}>
|
||||
{startCase(name)}
|
||||
</ListItem>
|
||||
<ListItem name={t("Plant Type")}>
|
||||
<Link
|
||||
title={t("View crop info")}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { AccountMenuProps } from "./interfaces";
|
||||
import { docLink } from "../ui/doc_link";
|
||||
import { Link } from "../link";
|
||||
|
@ -21,11 +20,10 @@ export const AdditionalMenu = (props: AccountMenuProps) => {
|
|||
{t("Logs")}
|
||||
</Link>
|
||||
</div>
|
||||
{DevSettings.futureFeaturesEnabled() &&
|
||||
<Link to="/app/help" onClick={props.close("accountMenuOpen")}>
|
||||
<i className="fa fa-question-circle"></i>
|
||||
{t("Help")}
|
||||
</Link>}
|
||||
</Link>
|
||||
{!DevSettings.futureFeaturesEnabled() &&
|
||||
<div>
|
||||
<a href={docLink("the-farmbot-web-app")}
|
||||
|
|
|
@ -15,6 +15,15 @@ import { VariableDeclaration } from "farmbot";
|
|||
import { clickButton } from "../../../__test_support__/helpers";
|
||||
import { Actions } from "../../../constants";
|
||||
|
||||
const testVariable: VariableDeclaration = {
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "label", data_value: {
|
||||
kind: "identifier", args: { label: "new_var" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
describe("<ActiveEditor />", () => {
|
||||
const fakeProps = (): ActiveEditorProps => ({
|
||||
dispatch: jest.fn(),
|
||||
|
@ -64,22 +73,55 @@ describe("<ActiveEditor />", () => {
|
|||
type: Actions.SET_SCHEDULER_STATE, payload: true
|
||||
});
|
||||
});
|
||||
|
||||
it("has correct height without variable form", () => {
|
||||
const p = fakeProps();
|
||||
p.regimen.body.body = [];
|
||||
p.shouldDisplay = () => true;
|
||||
const wrapper = mount(<ActiveEditor {...p} />);
|
||||
expect(wrapper.find(".regimen").props().style).toEqual({
|
||||
height: "calc(100vh - 200px)"
|
||||
});
|
||||
});
|
||||
|
||||
it("has correct height with variable form", () => {
|
||||
const p = fakeProps();
|
||||
p.regimen.body.body = [testVariable];
|
||||
p.shouldDisplay = () => true;
|
||||
const wrapper = mount(<ActiveEditor {...p} />);
|
||||
expect(wrapper.find(".regimen").props().style)
|
||||
.toEqual({ height: "calc(100vh - 500px)" });
|
||||
});
|
||||
|
||||
it("has correct height with variable form collapsed", () => {
|
||||
const p = fakeProps();
|
||||
p.regimen.body.body = [testVariable];
|
||||
p.shouldDisplay = () => true;
|
||||
const wrapper = mount(<ActiveEditor {...p} />);
|
||||
wrapper.setState({ variablesCollapsed: true });
|
||||
expect(wrapper.find(".regimen").props().style)
|
||||
.toEqual({ height: "calc(100vh - 300px)" });
|
||||
});
|
||||
|
||||
it("automatically calculates height", () => {
|
||||
document.getElementById = () => ({ offsetHeight: 101 } as HTMLElement);
|
||||
const wrapper = mount(<ActiveEditor {...fakeProps()} />);
|
||||
expect(wrapper.find(".regimen").props().style)
|
||||
.toEqual({ height: "calc(100vh - 301px)" });
|
||||
});
|
||||
|
||||
it("toggles variable form state", () => {
|
||||
const wrapper = mount<ActiveEditor>(<ActiveEditor {...fakeProps()} />);
|
||||
wrapper.instance().toggleVarShow();
|
||||
expect(wrapper.state()).toEqual({ variablesCollapsed: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe("editRegimenVariables()", () => {
|
||||
const variables: VariableDeclaration = {
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "label", data_value: {
|
||||
kind: "identifier", args: { label: "new_var" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
it("updates bodyVariables", () => {
|
||||
const regimen = fakeRegimen();
|
||||
editRegimenVariables({ dispatch: jest.fn(), regimen })([])(variables);
|
||||
editRegimenVariables({ dispatch: jest.fn(), regimen })([])(testVariable);
|
||||
expect(overwrite).toHaveBeenCalledWith(regimen,
|
||||
expect.objectContaining({ body: [variables] }));
|
||||
expect.objectContaining({ body: [testVariable] }));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
import { RegimenNameInput } from "./regimen_name_input";
|
||||
import { ActiveEditorProps } from "./interfaces";
|
||||
import { ActiveEditorProps, ActiveEditorState } from "./interfaces";
|
||||
import { push } from "../../history";
|
||||
import {
|
||||
RegimenItem, CalendarRow, RegimenItemCalendarRow, RegimenProps
|
||||
|
@ -22,26 +22,47 @@ import { Actions } from "../../constants";
|
|||
* The bottom half of the regimen editor panel (when there's something to
|
||||
* actually edit).
|
||||
*/
|
||||
export function ActiveEditor(props: ActiveEditorProps) {
|
||||
const regimenProps = { regimen: props.regimen, dispatch: props.dispatch };
|
||||
export class ActiveEditor
|
||||
extends React.Component<ActiveEditorProps, ActiveEditorState> {
|
||||
state: ActiveEditorState = { variablesCollapsed: false };
|
||||
|
||||
get regimenProps() {
|
||||
return { regimen: this.props.regimen, dispatch: this.props.dispatch };
|
||||
}
|
||||
|
||||
toggleVarShow = () =>
|
||||
this.setState({ variablesCollapsed: !this.state.variablesCollapsed });
|
||||
|
||||
LocalsList = () => {
|
||||
const { regimen } = this.props;
|
||||
return <LocalsList
|
||||
locationDropdownKey={JSON.stringify(regimen)}
|
||||
bodyVariables={regimen.body.body}
|
||||
variableData={this.props.variableData}
|
||||
sequenceUuid={regimen.uuid}
|
||||
resources={this.props.resources}
|
||||
onChange={editRegimenVariables(this.regimenProps)(regimen.body.body)}
|
||||
collapsible={true}
|
||||
collapsed={this.state.variablesCollapsed}
|
||||
toggleVarShow={this.toggleVarShow}
|
||||
allowedVariableNodes={AllowedVariableNodes.parameter}
|
||||
shouldDisplay={this.props.shouldDisplay} />;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div className="regimen-editor-content">
|
||||
<div className="regimen-editor-tools">
|
||||
<RegimenButtonGroup {...regimenProps} />
|
||||
<RegimenNameInput {...regimenProps} />
|
||||
<LocalsList
|
||||
locationDropdownKey={JSON.stringify(props.regimen)}
|
||||
bodyVariables={props.regimen.body.body}
|
||||
variableData={props.variableData}
|
||||
sequenceUuid={props.regimen.uuid}
|
||||
resources={props.resources}
|
||||
onChange={editRegimenVariables(regimenProps)(props.regimen.body.body)}
|
||||
allowedVariableNodes={AllowedVariableNodes.parameter}
|
||||
shouldDisplay={props.shouldDisplay} />
|
||||
<RegimenButtonGroup {...this.regimenProps} />
|
||||
<RegimenNameInput {...this.regimenProps} />
|
||||
<this.LocalsList />
|
||||
<hr />
|
||||
</div>
|
||||
<OpenSchedulerButton dispatch={props.dispatch} />
|
||||
<RegimenRows calendar={props.calendar} dispatch={props.dispatch} />
|
||||
<OpenSchedulerButton dispatch={this.props.dispatch} />
|
||||
<RegimenRows {...this.regimenProps}
|
||||
calendar={this.props.calendar}
|
||||
varsCollapsed={this.state.variablesCollapsed} />
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export const OpenSchedulerButton = (props: { dispatch: Function }) =>
|
||||
|
@ -73,13 +94,29 @@ const RegimenButtonGroup = (props: RegimenProps) =>
|
|||
</button>
|
||||
</div>;
|
||||
|
||||
/** Make room for the regimen header variable form when necessary. */
|
||||
const regimenSectionHeight =
|
||||
(regimen: TaggedRegimen, varsCollapsed: boolean) => {
|
||||
let subHeight = 200;
|
||||
const variables = regimen.body.body.length > 0;
|
||||
if (variables) { subHeight = 500; }
|
||||
if (varsCollapsed) { subHeight = 300; }
|
||||
const variablesDiv = document.getElementById("regimen-editor-tools");
|
||||
if (variablesDiv) { subHeight = 200 + variablesDiv.offsetHeight; }
|
||||
return `calc(100vh - ${subHeight}px)`;
|
||||
};
|
||||
|
||||
interface RegimenRowsProps {
|
||||
regimen: TaggedRegimen;
|
||||
calendar: CalendarRow[];
|
||||
dispatch: Function;
|
||||
varsCollapsed: boolean;
|
||||
}
|
||||
|
||||
const RegimenRows = (props: RegimenRowsProps) =>
|
||||
<div className="regimen">
|
||||
<div className="regimen" style={{
|
||||
height: regimenSectionHeight(props.regimen, props.varsCollapsed)
|
||||
}}>
|
||||
{props.calendar.map(regimenDay(props.dispatch))}
|
||||
</div>;
|
||||
|
||||
|
|
|
@ -17,6 +17,10 @@ export interface ActiveEditorProps {
|
|||
variableData: VariableNameSet;
|
||||
}
|
||||
|
||||
export interface ActiveEditorState {
|
||||
variablesCollapsed: boolean;
|
||||
}
|
||||
|
||||
export interface RegimenItemListProps {
|
||||
calendar: RegimenItemCalendarRow[];
|
||||
dispatch: Function;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import * as React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
import { FilterSearch } from "../filter_search";
|
||||
import { DropDownItem } from "../fb_select";
|
||||
|
||||
describe("<FilterSearch />", () => {
|
||||
const fakeItem = (extra?: Partial<DropDownItem>): DropDownItem =>
|
||||
Object.assign({ label: "label", value: "value" }, extra);
|
||||
|
||||
const fakeProps = () => ({
|
||||
items: [],
|
||||
selectedItem: fakeItem(),
|
||||
onChange: jest.fn(),
|
||||
nullChoice: fakeItem(),
|
||||
});
|
||||
|
||||
it("selects item", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = shallow(<FilterSearch {...p} />);
|
||||
const item = fakeItem();
|
||||
wrapper.simulate("ItemSelect", item);
|
||||
expect(p.onChange).toHaveBeenCalledWith(item);
|
||||
});
|
||||
|
||||
it("doesn't select header", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = shallow(<FilterSearch {...p} />);
|
||||
const item = fakeItem({ heading: true });
|
||||
wrapper.simulate("ItemSelect", item);
|
||||
expect(p.onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -75,7 +75,7 @@ export class FilterSearch extends React.Component<Props, Partial<State>> {
|
|||
}
|
||||
|
||||
private handleValueChange = (item: DropDownItem | undefined) => {
|
||||
if (item) {
|
||||
if (item && !item.heading) {
|
||||
this.props.onChange(item);
|
||||
this.setState({ item });
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue