Skip to content

Commit

Permalink
Allow to disable auto saving for layout configs (#3620)
Browse files Browse the repository at this point in the history
* allow to disable auto saving for layout configs

* tweak layout of layout menu

* improve tooltip handling in layout menu
  • Loading branch information
philippotto authored Jan 15, 2019
1 parent fe2e690 commit 20c755a
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 59 deletions.
2 changes: 2 additions & 0 deletions app/assets/javascripts/oxalis/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ export type UserConfiguration = {|
+sphericalCapRadius: number,
+tdViewDisplayPlanes: boolean,
+hideTreeRemovalWarning: boolean,
+autoSaveLayouts: boolean,
|};

export type Mapping = { [key: number]: number };
Expand Down Expand Up @@ -433,6 +434,7 @@ export const defaultState: OxalisState = {
sphericalCapRadius: 140,
tdViewDisplayPlanes: true,
hideTreeRemovalWarning: false,
autoSaveLayouts: true,
},
temporaryConfiguration: {
viewMode: Constants.MODE_PLANE_TRACING,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { Button, Dropdown, Icon, Menu, Modal, Tooltip } from "antd";
import { connect } from "react-redux";
import React, { PureComponent } from "react";
import * as React from "react";

import type { APIUser, APITracingType } from "admin/api_flow_types";
import { AsyncButton } from "components/async_clickables";
Expand Down Expand Up @@ -31,13 +31,7 @@ type StateProps = {
};

type Props = StateProps & {
storedLayoutNamesForView: Array<string>,
layoutKey: string,
activeLayout: string,
onResetLayout: () => void,
onSelectLayout: string => void,
onDeleteLayout: string => void,
addNewLayout: () => void,
layoutMenu: React.Node,
};

type State = {
Expand All @@ -46,17 +40,20 @@ type State = {
isUserScriptsModalOpen: boolean,
};

type ResetLayoutItemProps = {
type LayoutMenuProps = {
storedLayoutNamesForView: Array<string>,
layoutKey: string,
activeLayout: string,
onResetLayout: () => void,
onSelectLayout: string => void,
onDeleteLayout: string => void,
addNewLayout: () => void,
autoSaveLayouts: boolean,
setAutoSaveLayouts: boolean => void,
saveCurrentLayout: () => void,
};

export const ResetLayoutItem = (props: ResetLayoutItemProps) => {
export const LayoutMenu = (props: LayoutMenuProps) => {
const {
storedLayoutNamesForView,
layoutKey,
Expand All @@ -65,6 +62,9 @@ export const ResetLayoutItem = (props: ResetLayoutItemProps) => {
onSelectLayout,
onDeleteLayout,
addNewLayout,
autoSaveLayouts,
setAutoSaveLayouts,
saveCurrentLayout,
...others
} = props;
const layoutMissingHelpTitle = (
Expand Down Expand Up @@ -117,8 +117,32 @@ export const ResetLayoutItem = (props: ResetLayoutItemProps) => {
</span>
}
>
<Menu.Item onClick={onResetLayout}>Reset Layout</Menu.Item>
<Menu.Item onClick={addNewLayout}>Add a new Layout</Menu.Item>
<Menu.Item
style={{ display: "inline-block" }}
onClick={addNewLayout}
title="Add a new Layout"
>
<Icon type="plus" />
</Menu.Item>
<Menu.Item style={{ display: "inline-block" }} onClick={onResetLayout} title="Reset Layout">
<Icon type="rollback" />
</Menu.Item>
<Menu.Item
style={{ display: "inline-block" }}
onClick={() => setAutoSaveLayouts(!autoSaveLayouts)}
title={`${autoSaveLayouts ? "Disable" : "Enable"} auto-saving of current layout`}
>
<Icon type={autoSaveLayouts ? "disconnect" : "link"} />
</Menu.Item>
{autoSaveLayouts ? null : (
<Menu.Item
style={{ display: "inline-block" }}
onClick={saveCurrentLayout}
title="Save current layout"
>
<Icon type="save" />
</Menu.Item>
)}
<Menu.Divider />
<Menu.ItemGroup
className="available-layout-list"
Expand All @@ -134,7 +158,7 @@ export const ResetLayoutItem = (props: ResetLayoutItemProps) => {
);
};

class TracingActionsView extends PureComponent<Props, State> {
class TracingActionsView extends React.PureComponent<Props, State> {
state = {
isShareModalOpen: false,
isMergeModalOpen: false,
Expand Down Expand Up @@ -225,10 +249,10 @@ class TracingActionsView extends PureComponent<Props, State> {
};

render() {
const viewMode = Store.getState().temporaryConfiguration.viewMode;
const { viewMode } = Store.getState().temporaryConfiguration;
const isSkeletonMode = Constants.MODES_SKELETON.includes(viewMode);
const archiveButtonText = this.props.task ? "Finish" : "Archive";
const restrictions = this.props.restrictions;
const { restrictions } = this.props;

const saveButton = restrictions.allowUpdate
? [
Expand Down Expand Up @@ -334,18 +358,7 @@ class TracingActionsView extends PureComponent<Props, State> {
);
}

elements.push(
<ResetLayoutItem
storedLayoutNamesForView={this.props.storedLayoutNamesForView}
layoutKey={this.props.layoutKey}
activeLayout={this.props.activeLayout}
onResetLayout={this.props.onResetLayout}
onSelectLayout={this.props.onSelectLayout}
onDeleteLayout={this.props.onDeleteLayout}
addNewLayout={this.props.addNewLayout}
key="layout"
/>,
);
elements.push(this.props.layoutMenu);

const menu = <Menu>{elements}</Menu>;

Expand Down
59 changes: 36 additions & 23 deletions app/assets/javascripts/oxalis/view/action_bar_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import ButtonComponent from "oxalis/view/components/button_component";
import Constants, { type ControlMode, ControlModeEnum, type Mode } from "oxalis/constants";
import DatasetPositionView from "oxalis/view/action-bar/dataset_position_view";
import Store, { type OxalisState } from "oxalis/store";
import TracingActionsView, { ResetLayoutItem } from "oxalis/view/action-bar/tracing_actions_view";
import TracingActionsView, { LayoutMenu } from "oxalis/view/action-bar/tracing_actions_view";
import ViewModesView from "oxalis/view/action-bar/view_modes_view";
import VolumeActionsView from "oxalis/view/action-bar/volume_actions_view";

Expand All @@ -37,10 +37,15 @@ type StateProps = {
};

type Props = StateProps & {
storedLayoutNamesForView: Array<string>,
activeLayout: string,
layoutKey: LayoutKeys,
setCurrentLayout: string => void,
layoutProps: {
storedLayoutNamesForView: Array<string>,
activeLayout: string,
layoutKey: LayoutKeys,
autoSaveLayouts: boolean,
setAutoSaveLayouts: boolean => void,
setCurrentLayout: string => void,
saveCurrentLayout: () => void,
},
};

type State = {
Expand All @@ -55,37 +60,45 @@ class ActionBarView extends React.PureComponent<Props, State> {

handleResetLayout = () => {
Store.dispatch(updateUserSettingAction("layoutScaleValue", 1));
layoutEmitter.emit("resetLayout", this.props.layoutKey, this.props.activeLayout);
layoutEmitter.emit(
"resetLayout",
this.props.layoutProps.layoutKey,
this.props.layoutProps.activeLayout,
);
};

handleLayoutDeleted = (layoutName: string) => {
deleteLayout(this.props.layoutKey, layoutName);
deleteLayout(this.props.layoutProps.layoutKey, layoutName);
};

addNewLayout = (layoutName: string) => {
this.setState({ isNewLayoutModalVisible: false });
const configForLayout = getLayoutConfig(this.props.layoutKey, this.props.activeLayout);
if (addNewLayout(this.props.layoutKey, layoutName, configForLayout)) {
this.props.setCurrentLayout(layoutName);
const configForLayout = getLayoutConfig(
this.props.layoutProps.layoutKey,
this.props.layoutProps.activeLayout,
);
if (addNewLayout(this.props.layoutProps.layoutKey, layoutName, configForLayout)) {
this.props.layoutProps.setCurrentLayout(layoutName);
}
};

render() {
const isTraceMode = this.props.controlMode === ControlModeEnum.TRACE;
const isVolumeSupported = !Constants.MODES_ARBITRARY.includes(this.props.viewMode);
const resetItemProps = {
storedLayoutNamesForView: this.props.storedLayoutNamesForView,
layoutKey: this.props.layoutKey,
activeLayout: this.props.activeLayout,
onResetLayout: this.handleResetLayout,
onSelectLayout: this.props.setCurrentLayout,
onDeleteLayout: this.handleLayoutDeleted,
addNewLayout: () => {
this.setState({ isNewLayoutModalVisible: true });
},
};
const layoutMenu = (
<LayoutMenu
{...this.props.layoutProps}
addNewLayout={() => {
this.setState({ isNewLayoutModalVisible: true });
}}
onResetLayout={this.handleResetLayout}
onSelectLayout={this.props.layoutProps.setCurrentLayout}
onDeleteLayout={this.handleLayoutDeleted}
/>
);

const readonlyDropdown = (
<Dropdown overlay={<Menu>{<ResetLayoutItem {...resetItemProps} />}</Menu>}>
<Dropdown overlay={<Menu>{layoutMenu}</Menu>}>
<ButtonComponent>
<Icon type="down" />
</ButtonComponent>
Expand All @@ -96,7 +109,7 @@ class ActionBarView extends React.PureComponent<Props, State> {
<React.Fragment>
<div className="action-bar">
{isTraceMode && !this.props.showVersionRestore ? (
<TracingActionsView {...resetItemProps} />
<TracingActionsView layoutMenu={layoutMenu} />
) : (
readonlyDropdown
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import { Layout, Icon } from "antd";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import classNames from "classnames";
import * as React from "react";
import classNames from "classnames";
import type { Dispatch } from "redux";

import { ArbitraryViewport, type Mode, OrthoViews } from "oxalis/constants";
import type { OxalisState, TracingTypeTracing, TraceOrViewCommand } from "oxalis/store";
import { updateUserSettingAction } from "oxalis/model/actions/settings_actions";
import AbstractTreeTabView from "oxalis/view/right-menu/abstract_tree_tab_view";
import ActionBarView from "oxalis/view/action_bar_view";
import ButtonComponent from "oxalis/view/components/button_component";
Expand Down Expand Up @@ -44,11 +46,13 @@ type StateProps = {
showVersionRestore: boolean,
storedLayouts: Object,
isDatasetOnScratchVolume: boolean,
autoSaveLayouts: boolean,
};

type Props = StateProps & {
initialTracingType: TracingTypeTracing,
initialCommandType: TraceOrViewCommand,
setAutoSaveLayouts: boolean => void,
};

type State = {
Expand All @@ -67,6 +71,9 @@ const GOLDEN_LAYOUT_ADAPTER_STYLE = {
};

class TracingLayoutView extends React.PureComponent<Props, State> {
currentLayoutConfig: Object;
currentLayoutName: string;

constructor(props: Props) {
super(props);
const layoutType = determineLayout(this.props.initialCommandType.type, this.props.viewMode);
Expand Down Expand Up @@ -106,8 +113,19 @@ class TracingLayoutView extends React.PureComponent<Props, State> {
onLayoutChange = (layoutConfig, layoutName) => {
recalculateInputCatcherSizes();
window.needsRerender = true;
this.currentLayoutConfig = layoutConfig;
this.currentLayoutName = layoutName;
if (this.props.autoSaveLayouts) {
this.saveCurrentLayout();
}
};

saveCurrentLayout = () => {
if (this.currentLayoutConfig == null || this.currentLayoutName == null) {
return;
}
const layoutKey = determineLayout(this.props.initialCommandType.type, this.props.viewMode);
storeLayoutConfig(layoutConfig, layoutKey, layoutName);
storeLayoutConfig(this.currentLayoutConfig, layoutKey, this.currentLayoutName);
};

getLayoutNamesFromCurrentView = (layoutKey): Array<string> =>
Expand Down Expand Up @@ -136,12 +154,17 @@ class TracingLayoutView extends React.PureComponent<Props, State> {
<span className="hide-on-small-screen">Settings</span>
</ButtonComponent>
<ActionBarView
storedLayoutNamesForView={currentLayoutNames}
activeLayout={this.state.activeLayout}
layoutKey={layoutType}
setCurrentLayout={layoutName => {
this.setState({ activeLayout: layoutName });
setActiveLayout(layoutType, layoutName);
layoutProps={{
storedLayoutNamesForView: currentLayoutNames,
activeLayout: this.state.activeLayout,
layoutKey: layoutType,
setCurrentLayout: layoutName => {
this.setState({ activeLayout: layoutName });
setActiveLayout(layoutType, layoutName);
},
saveCurrentLayout: this.saveCurrentLayout,
setAutoSaveLayouts: this.props.setAutoSaveLayouts,
autoSaveLayouts: this.props.autoSaveLayouts,
}}
/>
</Header>
Expand Down Expand Up @@ -221,15 +244,25 @@ class TracingLayoutView extends React.PureComponent<Props, State> {
}
}

const mapDispatchToProps = (dispatch: Dispatch<*>) => ({
setAutoSaveLayouts(value: boolean) {
dispatch(updateUserSettingAction("autoSaveLayouts", value));
},
});

function mapStateToProps(state: OxalisState): StateProps {
return {
viewMode: state.temporaryConfiguration.viewMode,
displayScalebars: state.userConfiguration.displayScalebars,
autoSaveLayouts: state.userConfiguration.autoSaveLayouts,
isUpdateTracingAllowed: state.tracing.restrictions.allowUpdate,
showVersionRestore: state.uiInformation.showVersionRestore,
storedLayouts: state.uiInformation.storedLayouts,
isDatasetOnScratchVolume: state.dataset.dataStore.isScratch,
};
}

export default connect(mapStateToProps)(withRouter(TracingLayoutView));
export default connect(
mapStateToProps,
mapDispatchToProps,
)(withRouter(TracingLayoutView));

0 comments on commit 20c755a

Please sign in to comment.