From 3ee942581654222413bb72326c4bf871dd335186 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Tue, 15 Jan 2019 10:49:57 +0100 Subject: [PATCH] Allow to disable auto saving for layout configs (#3620) * allow to disable auto saving for layout configs * tweak layout of layout menu * improve tooltip handling in layout menu --- app/assets/javascripts/oxalis/store.js | 2 + .../view/action-bar/tracing_actions_view.js | 67 +++++++++++-------- .../oxalis/view/action_bar_view.js | 59 +++++++++------- .../view/layouting/tracing_layout_view.js | 51 +++++++++++--- 4 files changed, 120 insertions(+), 59 deletions(-) diff --git a/app/assets/javascripts/oxalis/store.js b/app/assets/javascripts/oxalis/store.js index 9e038d0a64..82f651908c 100644 --- a/app/assets/javascripts/oxalis/store.js +++ b/app/assets/javascripts/oxalis/store.js @@ -248,6 +248,7 @@ export type UserConfiguration = {| +sphericalCapRadius: number, +tdViewDisplayPlanes: boolean, +hideTreeRemovalWarning: boolean, + +autoSaveLayouts: boolean, |}; export type Mapping = { [key: number]: number }; @@ -433,6 +434,7 @@ export const defaultState: OxalisState = { sphericalCapRadius: 140, tdViewDisplayPlanes: true, hideTreeRemovalWarning: false, + autoSaveLayouts: true, }, temporaryConfiguration: { viewMode: Constants.MODE_PLANE_TRACING, diff --git a/app/assets/javascripts/oxalis/view/action-bar/tracing_actions_view.js b/app/assets/javascripts/oxalis/view/action-bar/tracing_actions_view.js index 2beaa675aa..4fee802958 100644 --- a/app/assets/javascripts/oxalis/view/action-bar/tracing_actions_view.js +++ b/app/assets/javascripts/oxalis/view/action-bar/tracing_actions_view.js @@ -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"; @@ -31,13 +31,7 @@ type StateProps = { }; type Props = StateProps & { - storedLayoutNamesForView: Array, - layoutKey: string, - activeLayout: string, - onResetLayout: () => void, - onSelectLayout: string => void, - onDeleteLayout: string => void, - addNewLayout: () => void, + layoutMenu: React.Node, }; type State = { @@ -46,7 +40,7 @@ type State = { isUserScriptsModalOpen: boolean, }; -type ResetLayoutItemProps = { +type LayoutMenuProps = { storedLayoutNamesForView: Array, layoutKey: string, activeLayout: string, @@ -54,9 +48,12 @@ type ResetLayoutItemProps = { 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, @@ -65,6 +62,9 @@ export const ResetLayoutItem = (props: ResetLayoutItemProps) => { onSelectLayout, onDeleteLayout, addNewLayout, + autoSaveLayouts, + setAutoSaveLayouts, + saveCurrentLayout, ...others } = props; const layoutMissingHelpTitle = ( @@ -117,8 +117,32 @@ export const ResetLayoutItem = (props: ResetLayoutItemProps) => { } > - Reset Layout - Add a new Layout + + + + + + + setAutoSaveLayouts(!autoSaveLayouts)} + title={`${autoSaveLayouts ? "Disable" : "Enable"} auto-saving of current layout`} + > + + + {autoSaveLayouts ? null : ( + + + + )} { ); }; -class TracingActionsView extends PureComponent { +class TracingActionsView extends React.PureComponent { state = { isShareModalOpen: false, isMergeModalOpen: false, @@ -225,10 +249,10 @@ class TracingActionsView extends PureComponent { }; 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 ? [ @@ -334,18 +358,7 @@ class TracingActionsView extends PureComponent { ); } - elements.push( - , - ); + elements.push(this.props.layoutMenu); const menu = {elements}; diff --git a/app/assets/javascripts/oxalis/view/action_bar_view.js b/app/assets/javascripts/oxalis/view/action_bar_view.js index bfa59d46c6..38280204a9 100644 --- a/app/assets/javascripts/oxalis/view/action_bar_view.js +++ b/app/assets/javascripts/oxalis/view/action_bar_view.js @@ -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"; @@ -37,10 +37,15 @@ type StateProps = { }; type Props = StateProps & { - storedLayoutNamesForView: Array, - activeLayout: string, - layoutKey: LayoutKeys, - setCurrentLayout: string => void, + layoutProps: { + storedLayoutNamesForView: Array, + activeLayout: string, + layoutKey: LayoutKeys, + autoSaveLayouts: boolean, + setAutoSaveLayouts: boolean => void, + setCurrentLayout: string => void, + saveCurrentLayout: () => void, + }, }; type State = { @@ -55,37 +60,45 @@ class ActionBarView extends React.PureComponent { 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 = ( + { + this.setState({ isNewLayoutModalVisible: true }); + }} + onResetLayout={this.handleResetLayout} + onSelectLayout={this.props.layoutProps.setCurrentLayout} + onDeleteLayout={this.handleLayoutDeleted} + /> + ); + const readonlyDropdown = ( - {}}> + {layoutMenu}}> @@ -96,7 +109,7 @@ class ActionBarView extends React.PureComponent {
{isTraceMode && !this.props.showVersionRestore ? ( - + ) : ( readonlyDropdown )} diff --git a/app/assets/javascripts/oxalis/view/layouting/tracing_layout_view.js b/app/assets/javascripts/oxalis/view/layouting/tracing_layout_view.js index b0c34b7ad3..b65624257e 100644 --- a/app/assets/javascripts/oxalis/view/layouting/tracing_layout_view.js +++ b/app/assets/javascripts/oxalis/view/layouting/tracing_layout_view.js @@ -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"; @@ -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 = { @@ -67,6 +71,9 @@ const GOLDEN_LAYOUT_ADAPTER_STYLE = { }; class TracingLayoutView extends React.PureComponent { + currentLayoutConfig: Object; + currentLayoutName: string; + constructor(props: Props) { super(props); const layoutType = determineLayout(this.props.initialCommandType.type, this.props.viewMode); @@ -106,8 +113,19 @@ class TracingLayoutView extends React.PureComponent { 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 => @@ -136,12 +154,17 @@ class TracingLayoutView extends React.PureComponent { Settings { - 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, }} /> @@ -221,10 +244,17 @@ class TracingLayoutView extends React.PureComponent { } } +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, @@ -232,4 +262,7 @@ function mapStateToProps(state: OxalisState): StateProps { }; } -export default connect(mapStateToProps)(withRouter(TracingLayoutView)); +export default connect( + mapStateToProps, + mapDispatchToProps, +)(withRouter(TracingLayoutView));