variable form styling
parent
c17d22e07a
commit
b6eff330ab
|
@ -68,12 +68,38 @@
|
|||
}
|
||||
.locals-list {
|
||||
margin-top: 1rem;
|
||||
max-height: 14rem;
|
||||
max-height: 25rem;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.locals-list {
|
||||
>.location-form {
|
||||
margin: auto;
|
||||
margin-top: 1rem;
|
||||
width: 80%;
|
||||
max-width: 40rem;
|
||||
background: $off_white;
|
||||
label {
|
||||
margin-top: 0;
|
||||
}
|
||||
>.location-form-header {
|
||||
width: 100%;
|
||||
background: darken($off_white, 5%);
|
||||
padding: 1rem;
|
||||
i {
|
||||
float: right;
|
||||
font-size: 2rem;
|
||||
color: $dark_gray;
|
||||
}
|
||||
}
|
||||
>.location-form-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sequence,
|
||||
.regimen {
|
||||
width: 100%;
|
||||
|
|
|
@ -29,7 +29,7 @@ import {
|
|||
SequenceEditorMiddleActive, onDrop, SequenceNameAndColor
|
||||
} from "../sequence_editor_middle_active";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { ActiveMiddleProps } from "../interfaces";
|
||||
import { ActiveMiddleProps, SequenceHeaderProps } from "../interfaces";
|
||||
import {
|
||||
FAKE_RESOURCES, buildResourceIndex
|
||||
} from "../../__test_support__/resource_index_builder";
|
||||
|
@ -44,6 +44,7 @@ import { copySequence, editCurrentSequence } from "../actions";
|
|||
import { execSequence } from "../../devices/actions";
|
||||
import { clickButton } from "../../__test_support__/helpers";
|
||||
import { fakeVariableNameSet } from "../../__test_support__/fake_variables";
|
||||
import { DropAreaProps } from "../../draggable/interfaces";
|
||||
|
||||
describe("<SequenceEditorMiddleActive/>", () => {
|
||||
const fakeProps = (): ActiveMiddleProps => {
|
||||
|
@ -103,10 +104,25 @@ describe("<SequenceEditorMiddleActive/>", () => {
|
|||
expect(wrapper.find(".drag-drop-area").text()).toEqual("DRAG COMMAND HERE");
|
||||
});
|
||||
|
||||
it("calls DropArea callback", () => {
|
||||
const p = fakeProps();
|
||||
const dispatch = jest.fn();
|
||||
p.dispatch = dispatch;
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...p} />);
|
||||
const props = wrapper.find("DropArea").props() as DropAreaProps;
|
||||
props.callback && props.callback("key");
|
||||
dispatch.mock.calls[0][0](() =>
|
||||
({ value: 1, intent: "step_splice", draggerId: 2 }));
|
||||
expect(splice).toHaveBeenCalledWith(expect.objectContaining({
|
||||
step: 1,
|
||||
index: Infinity
|
||||
}));
|
||||
});
|
||||
|
||||
it("has correct height", () => {
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...fakeProps()} />);
|
||||
expect(wrapper.find(".sequence").props().style).toEqual({
|
||||
height: "calc(100vh - 25rem)"
|
||||
height: "calc(100vh - 200px)"
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -116,7 +132,7 @@ describe("<SequenceEditorMiddleActive/>", () => {
|
|||
p.shouldDisplay = () => true;
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...p} />);
|
||||
expect(wrapper.find(".sequence").props().style).toEqual({
|
||||
height: "calc(100vh - 25rem)"
|
||||
height: "calc(100vh - 200px)"
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -126,7 +142,31 @@ describe("<SequenceEditorMiddleActive/>", () => {
|
|||
p.shouldDisplay = () => true;
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...p} />);
|
||||
expect(wrapper.find(".sequence").props().style)
|
||||
.toEqual({ height: "calc(100vh - 38rem)" });
|
||||
.toEqual({ height: "calc(100vh - 500px)" });
|
||||
});
|
||||
|
||||
it("has correct height with variable form collapsed", () => {
|
||||
const p = fakeProps();
|
||||
p.resources.sequenceMetas = { [p.sequence.uuid]: fakeVariableNameSet() };
|
||||
p.shouldDisplay = () => true;
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...p} />);
|
||||
wrapper.setState({ variablesCollapsed: true });
|
||||
expect(wrapper.find(".sequence").props().style)
|
||||
.toEqual({ height: "calc(100vh - 300px)" });
|
||||
});
|
||||
|
||||
it("automatically calculates height", () => {
|
||||
document.getElementById = () => ({ offsetHeight: 101 } as HTMLElement);
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...fakeProps()} />);
|
||||
expect(wrapper.find(".sequence").props().style)
|
||||
.toEqual({ height: "calc(100vh - 301px)" });
|
||||
});
|
||||
|
||||
it("toggles variable form state", () => {
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...fakeProps()} />);
|
||||
const props = wrapper.find("SequenceHeader").props() as SequenceHeaderProps;
|
||||
props.toggleVarShow();
|
||||
expect(wrapper.state()).toEqual({ variablesCollapsed: true });
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -134,9 +174,8 @@ describe("onDrop()", () => {
|
|||
it("step_splice", () => {
|
||||
const dispatch = jest.fn();
|
||||
onDrop(dispatch, fakeSequence())(0, "fakeUuid");
|
||||
dispatch.mock.calls[0][0](() => {
|
||||
return { value: 1, intent: "step_splice", draggerId: 2 };
|
||||
});
|
||||
dispatch.mock.calls[0][0](() =>
|
||||
({ value: 1, intent: "step_splice", draggerId: 2 }));
|
||||
expect(splice).toHaveBeenCalledWith(expect.objectContaining({
|
||||
step: 1,
|
||||
index: 0
|
||||
|
@ -146,9 +185,8 @@ describe("onDrop()", () => {
|
|||
it("step_move", () => {
|
||||
const dispatch = jest.fn();
|
||||
onDrop(dispatch, fakeSequence())(3, "fakeUuid");
|
||||
dispatch.mock.calls[0][0](() => {
|
||||
return { value: 4, intent: "step_move", draggerId: 5 };
|
||||
});
|
||||
dispatch.mock.calls[0][0](() =>
|
||||
({ value: 4, intent: "step_move", draggerId: 5 }));
|
||||
expect(move).toHaveBeenCalledWith(expect.objectContaining({
|
||||
step: 4,
|
||||
to: 3,
|
||||
|
|
|
@ -71,6 +71,8 @@ export interface SequenceHeaderProps {
|
|||
resources: ResourceIndex;
|
||||
shouldDisplay: ShouldDisplay;
|
||||
menuOpen: boolean;
|
||||
variablesCollapsed: boolean;
|
||||
toggleVarShow: () => void;
|
||||
}
|
||||
|
||||
export type ChannelName = ALLOWED_CHANNEL_NAMES;
|
||||
|
|
|
@ -94,4 +94,20 @@ describe("<LocationForm/>", () => {
|
|||
expect(wrapper.find(FBSelect).first().props().list)
|
||||
.toContainEqual(everyPointDDI("Tool"));
|
||||
});
|
||||
|
||||
it("renders collapse icon: open", () => {
|
||||
const p = fakeProps();
|
||||
p.collapsible = true;
|
||||
p.collapsed = false;
|
||||
const wrapper = shallow(<LocationForm {...p} />);
|
||||
expect(wrapper.html()).toContain("fa-caret-up");
|
||||
});
|
||||
|
||||
it("renders collapse icon: closed", () => {
|
||||
const p = fakeProps();
|
||||
p.collapsible = true;
|
||||
p.collapsed = true;
|
||||
const wrapper = shallow(<LocationForm {...p} />);
|
||||
expect(wrapper.html()).toContain("fa-caret-down");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -57,6 +57,9 @@ export const LocalsList = (props: LocalsListProps) => {
|
|||
shouldDisplay={props.shouldDisplay}
|
||||
hideVariableLabel={Object.values(props.variableData || {}).length < 2}
|
||||
allowedVariableNodes={props.allowedVariableNodes}
|
||||
collapsible={props.collapsible}
|
||||
collapsed={props.collapsed}
|
||||
toggleVarShow={props.toggleVarShow}
|
||||
onChange={props.onChange} />)}
|
||||
</div>;
|
||||
};
|
||||
|
|
|
@ -49,6 +49,10 @@ interface CommonProps {
|
|||
allowedVariableNodes: AllowedVariableNodes;
|
||||
/** Don't display group dropdown items. */
|
||||
disallowGroups?: boolean;
|
||||
/** Add ability to collapse the form content. */
|
||||
collapsible?: boolean;
|
||||
collapsed?: boolean;
|
||||
toggleVarShow?: () => void;
|
||||
}
|
||||
|
||||
export interface LocalsListProps extends CommonProps {
|
||||
|
|
|
@ -87,36 +87,44 @@ export const LocationForm =
|
|||
props.hideVariableLabel ? t("Location") : `${label} (${t("Location")})`;
|
||||
const formTitle = props.hideTypeLabel ? label : formTitleWithType;
|
||||
return <div className="location-form">
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<label>{formTitle}</label>
|
||||
<FBSelect
|
||||
key={locationDropdownKey}
|
||||
list={list}
|
||||
selectedItem={dropdown}
|
||||
customNullLabel={NO_VALUE_SELECTED_DDI().label}
|
||||
onChange={ddi => onChange(convertDDItoVariable({
|
||||
label, allowedVariableNodes
|
||||
})(ddi))} />
|
||||
</Col>
|
||||
</Row>
|
||||
{vector &&
|
||||
<Row>
|
||||
{["x", "y", "z"].map((axis: Xyz) =>
|
||||
<Col xs={props.width || 4} key={axis}>
|
||||
<label>
|
||||
{t("{{axis}} (mm)", { axis })}
|
||||
</label>
|
||||
<BlurableInput type="number"
|
||||
disabled={isDisabled}
|
||||
onCommit={manuallyEditAxis({ ...axisPartialProps, axis })}
|
||||
name={`location-${axis}`}
|
||||
value={"" + vector[axis]} />
|
||||
</Col>)}
|
||||
</Row>}
|
||||
<DefaultValueForm
|
||||
variableNode={celeryNode}
|
||||
resources={resources}
|
||||
onChange={onChange} />
|
||||
<div className="location-form-header">
|
||||
<label>{formTitle}</label>
|
||||
{props.collapsible &&
|
||||
<i className={`fa fa-caret-${props.collapsed ? "down" : "up"}`}
|
||||
onClick={props.toggleVarShow} />}
|
||||
</div>
|
||||
{!props.collapsed &&
|
||||
<div className="location-form-content">
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<FBSelect
|
||||
key={locationDropdownKey}
|
||||
list={list}
|
||||
selectedItem={dropdown}
|
||||
customNullLabel={NO_VALUE_SELECTED_DDI().label}
|
||||
onChange={ddi => onChange(convertDDItoVariable({
|
||||
label, allowedVariableNodes
|
||||
})(ddi))} />
|
||||
</Col>
|
||||
</Row>
|
||||
{vector &&
|
||||
<Row>
|
||||
{["x", "y", "z"].map((axis: Xyz) =>
|
||||
<Col xs={props.width || 4} key={axis}>
|
||||
<label>
|
||||
{t("{{axis}} (mm)", { axis })}
|
||||
</label>
|
||||
<BlurableInput type="number"
|
||||
disabled={isDisabled}
|
||||
onCommit={manuallyEditAxis({ ...axisPartialProps, axis })}
|
||||
name={`location-${axis}`}
|
||||
value={"" + vector[axis]} />
|
||||
</Col>)}
|
||||
</Row>}
|
||||
<DefaultValueForm
|
||||
variableNode={celeryNode}
|
||||
resources={resources}
|
||||
onChange={onChange} />
|
||||
</div>}
|
||||
</div>;
|
||||
};
|
||||
|
|
|
@ -103,7 +103,7 @@ const SequenceHeader = (props: SequenceHeaderProps) => {
|
|||
const declarations = betterCompact(Object.values(variableData)
|
||||
.map(v => v &&
|
||||
isScopeDeclarationBodyItem(v.celeryNode) ? v.celeryNode : undefined));
|
||||
return <div className="sequence-editor-tools">
|
||||
return <div id="sequence-editor-tools" className="sequence-editor-tools">
|
||||
<SequenceBtnGroup {...sequenceAndDispatch}
|
||||
syncStatus={props.syncStatus}
|
||||
resources={props.resources}
|
||||
|
@ -117,19 +117,32 @@ const SequenceHeader = (props: SequenceHeaderProps) => {
|
|||
onChange={localListCallback(props)(declarations)}
|
||||
locationDropdownKey={JSON.stringify(sequence)}
|
||||
allowedVariableNodes={AllowedVariableNodes.parameter}
|
||||
collapsible={true}
|
||||
collapsed={props.variablesCollapsed}
|
||||
toggleVarShow={props.toggleVarShow}
|
||||
shouldDisplay={props.shouldDisplay} />
|
||||
</div>;
|
||||
};
|
||||
|
||||
interface ActiveMiddleState {
|
||||
variablesCollapsed: boolean;
|
||||
}
|
||||
|
||||
export class SequenceEditorMiddleActive extends
|
||||
React.Component<ActiveMiddleProps, {}> {
|
||||
React.Component<ActiveMiddleProps, ActiveMiddleState> {
|
||||
state: ActiveMiddleState = { variablesCollapsed: false };
|
||||
|
||||
/** Make room for the sequence header variable form when necessary. */
|
||||
get stepSectionHeight() {
|
||||
const { resources, sequence } = this.props;
|
||||
let subHeight = 200;
|
||||
const variables =
|
||||
Object.keys(resources.sequenceMetas[sequence.uuid] || {}).length > 0;
|
||||
return `calc(100vh - ${variables ? "38" : "25"}rem)`;
|
||||
if (variables) { subHeight = 500; }
|
||||
if (this.state.variablesCollapsed) { subHeight = 300; }
|
||||
const variablesDiv = document.getElementById("sequence-editor-tools");
|
||||
if (variablesDiv) { subHeight = 200 + variablesDiv.offsetHeight; }
|
||||
return `calc(100vh - ${subHeight}px)`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -141,6 +154,9 @@ export class SequenceEditorMiddleActive extends
|
|||
resources={this.props.resources}
|
||||
syncStatus={this.props.syncStatus}
|
||||
shouldDisplay={this.props.shouldDisplay}
|
||||
variablesCollapsed={this.state.variablesCollapsed}
|
||||
toggleVarShow={() =>
|
||||
this.setState({ variablesCollapsed: !this.state.variablesCollapsed })}
|
||||
menuOpen={this.props.menuOpen} />
|
||||
<hr />
|
||||
<div className="sequence" id="sequenceDiv"
|
||||
|
|
Loading…
Reference in New Issue