-
Notifications
You must be signed in to change notification settings - Fork 20
Vmo 3944 allow moving multiple blocks #101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
638be23
8c3afe9
0e4b558
38bce20
1f9b7e2
222de04
32f6617
dd637a7
eb9ab7e
4184d2d
2e39f47
23dc57c
bd06cc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| import {filter, flatMap, get, isEqual, keyBy, map, mapValues, union} from 'lodash' | ||
| import { | ||
| flatMap, isEqual, keyBy, map, mapValues, get, filter, union, includes, clone, forEach, minBy, | ||
| } from 'lodash' | ||
| import Vue from 'vue' | ||
| import {ActionTree, GetterTree, Module, MutationTree} from 'vuex' | ||
| import {IRootState} from '@/store' | ||
|
|
@@ -55,7 +57,9 @@ export interface IBuilderState { | |
| [OperationKind.CONNECTION_CREATE]: IConnectionCreateOperation, | ||
| [OperationKind.BLOCK_RELOCATE]: null, | ||
| }, | ||
| draggableForExitsByUuid: object, | ||
| toolbarHeight: number, | ||
| draggableForExitsByUuid: {[key: string]: object}, | ||
| draggableForBlocksByUuid: {[key: string]: object}, | ||
| } | ||
|
|
||
| export const stateFactory = (): IBuilderState => ({ | ||
|
|
@@ -73,7 +77,9 @@ export const stateFactory = (): IBuilderState => ({ | |
| }, | ||
| [OperationKind.BLOCK_RELOCATE]: null, | ||
| }, | ||
| toolbarHeight: 60, | ||
| draggableForExitsByUuid: {}, | ||
| draggableForBlocksByUuid: {}, | ||
| }) | ||
|
|
||
| export const getters: GetterTree<IBuilderState, IRootState> = { | ||
|
|
@@ -89,6 +95,26 @@ export const getters: GetterTree<IBuilderState, IRootState> = { | |
| exitLabelsById: (_state, _getters, {flow: {flows}}) => mapValues(keyBy(flatMap(flows[0].blocks, 'exits'), 'uuid'), 'label'), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Do not use property shorthand syntax (lodash/prop-shorthand)
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Do not use property shorthand syntax (lodash/prop-shorthand)
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Do not use property shorthand syntax (lodash/prop-shorthand)
|
||
|
|
||
| isEditable: (state) => state.isEditable, | ||
|
|
||
| selectedBlocks(_state, _getters, _rootState, rootGetters) { | ||
| return rootGetters['flow/selectedBlocks'] | ||
| }, | ||
|
|
||
| selectedBlockAtTheTopPosition(_state, getters) { | ||
| return minBy(getters.selectedBlocks, 'vendor_metadata.io_viamo.uiData.yPosition') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Do not use property shorthand syntax (lodash/prop-shorthand)
|
||
| }, | ||
|
|
||
| selectedBlockAtTheFurthestLeftPosition(_state, getters) { | ||
| return minBy(getters.selectedBlocks, 'vendor_metadata.io_viamo.uiData.xPosition') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Do not use property shorthand syntax (lodash/prop-shorthand)
|
||
| }, | ||
|
|
||
| isAnyLeftSpaceAvailable(_state, getters) { | ||
| return getters.selectedBlockAtTheFurthestLeftPosition.vendor_metadata.io_viamo.uiData.xPosition > 0 | ||
| }, | ||
|
|
||
| isAnyTopSpaceAvailable(state, getters) { | ||
| return getters.selectedBlockAtTheTopPosition.vendor_metadata.io_viamo.uiData.yPosition - state.toolbarHeight > 0 | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bzabos , your comment about separating pixel computation is still relevant here. I tried your proposal
... but I cannot resolve the challenge of removing this formula |
||
| }, | ||
| } | ||
|
|
||
| export const mutations: MutationTree<IBuilderState> = { | ||
|
|
@@ -119,8 +145,14 @@ export const mutations: MutationTree<IBuilderState> = { | |
| // Vue.observable(block.vendor_metadata.io_viamo.uiData) | ||
| // } | ||
|
|
||
| block.vendor_metadata.io_viamo.uiData.xPosition = x | ||
| block.vendor_metadata.io_viamo.uiData.yPosition = y | ||
| if (x !== undefined) { | ||
| // eslint-disable-next-line no-param-reassign | ||
| block.vendor_metadata.io_viamo.uiData.xPosition = x | ||
| } | ||
| if (y !== undefined) { | ||
| // eslint-disable-next-line no-param-reassign | ||
| block.vendor_metadata.io_viamo.uiData.yPosition = y | ||
| } | ||
| }, | ||
|
|
||
| setIsEditable(state, value) { | ||
|
|
@@ -130,9 +162,96 @@ export const mutations: MutationTree<IBuilderState> = { | |
| initDraggableForExitsByUuid(state) { | ||
| state.draggableForExitsByUuid = {} | ||
| }, | ||
|
|
||
| updateBlockDraggablePosition(state, {uuid, position}: { uuid: IBlock['uuid'], position: IPosition }) { | ||
| console.debug('Builder', 'updateBlockDraggablePosition for ', state.draggableForBlocksByUuid[uuid], 'to ', position) | ||
| Object.assign(state.draggableForBlocksByUuid[uuid], {left: position.x, top: position.y}) | ||
| }, | ||
|
|
||
| updateToolBarHeight(state, height) { | ||
| state.toolbarHeight = height | ||
| }, | ||
| } | ||
|
|
||
| export const actions: ActionTree<IBuilderState, IRootState> = { | ||
| changeBlockPositionTo({commit, getters, dispatch, rootState}, {position: {x, y}, block}) { | ||
| if (!includes(rootState.flow.selectedBlockUuids, block.uuid)) { | ||
| commit('setBlockPositionTo', {position: {x, y}, block}) | ||
| return | ||
| } | ||
|
|
||
| // The block is selected | ||
| // Store UI Position | ||
| const initialPosition = { | ||
| x: clone(block.vendor_metadata.io_viamo.uiData.xPosition), | ||
| y: clone(block.vendor_metadata.io_viamo.uiData.yPosition), | ||
| } as IPosition | ||
|
|
||
| // Prepare translation | ||
| const translationDelta: IPosition = { | ||
| x: x - initialPosition.x, | ||
| y: y - initialPosition.y, | ||
| } | ||
|
|
||
| let shouldReversePosition = false | ||
| const isMovingToTheRight = translationDelta.x > 0 | ||
| if (isMovingToTheRight || getters.isAnyLeftSpaceAvailable) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)
|
||
| commit('setBlockPositionTo', {position: {x}, block}) | ||
| } else { | ||
| translationDelta.x = 0 | ||
| commit('setBlockPositionTo', {position: {x: initialPosition.x}, block}) | ||
| shouldReversePosition = true | ||
| } | ||
|
|
||
| const isMovingToTheTop = translationDelta.y > 0 | ||
| if (isMovingToTheTop || getters.isAnyTopSpaceAvailable) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)
|
||
| commit('setBlockPositionTo', {position: {y}, block}) | ||
| } else { | ||
| translationDelta.y = 0 | ||
| commit('setBlockPositionTo', {position: {y: initialPosition.y}, block}) | ||
| shouldReversePosition = true | ||
| } | ||
|
|
||
| // Reverse the draggable position | ||
| if (shouldReversePosition) { | ||
| commit('updateBlockDraggablePosition', { | ||
| uuid: block.uuid, | ||
| position: { | ||
| x: block.vendor_metadata.io_viamo.uiData.xPosition, | ||
| y: block.vendor_metadata.io_viamo.uiData.yPosition, | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| // Translate other selected blocks | ||
| forEach(getters.selectedBlocks, (currentBlock: IBlock) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Prefer _.filter or _.some over an if statement inside a _.forEach (lodash/prefer-filter)
|
||
| if (currentBlock.uuid !== block.uuid) { | ||
| dispatch('setBlockAndSyncDraggablePositionFromDelta', {delta: translationDelta, block: currentBlock}) | ||
| } | ||
| }) | ||
| }, | ||
|
|
||
| setBlockAndSyncDraggablePositionFromDelta({commit}, {delta: {x, y}, block}) { | ||
| const { | ||
| vendor_metadata: { | ||
| io_viamo: { | ||
| uiData: { | ||
| xPosition: initialXPosition, | ||
| yPosition: initialYPosition, | ||
| }, | ||
| }, | ||
| }, | ||
| } = block | ||
|
|
||
| const newPosition: IPosition = { | ||
| x: initialXPosition + x, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Operands of '+' operation must either be both strings or both numbers. (@typescript-eslint/restrict-plus-operands)
|
||
| y: initialYPosition + y, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Operands of '+' operation must either be both strings or both numbers. (@typescript-eslint/restrict-plus-operands)
|
||
| } | ||
|
|
||
| commit('setBlockPositionTo', {position: newPosition, block}) | ||
| commit('updateBlockDraggablePosition', {uuid: block.uuid, position: newPosition}) | ||
| }, | ||
|
|
||
| removeConnectionFrom({commit}, {block: {uuid: blockId}, exit: {uuid: exitId}}) { | ||
| commit('flow/block_setBlockExitDestinationBlockId', { | ||
| blockId, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,7 @@ import {IdGeneratorUuidV4} from '@floip/flow-runner/dist/domain/IdGeneratorUuidV | |
| import moment from 'moment' | ||
| import {ActionTree, GetterTree, MutationTree} from 'vuex' | ||
| import {IRootState} from '@/store' | ||
| import {cloneDeep, defaults, every, forEach, get, has, includes, omit} from 'lodash' | ||
| import {cloneDeep, defaults, every, forEach, filter, get, has, includes, minBy, omit} from 'lodash' | ||
| import {discoverContentTypesFor} from '@/store/flow/resource' | ||
| import {computeBlockUiData} from '@/store/builder' | ||
| import {IFlowsState} from '.' | ||
|
|
@@ -63,6 +63,7 @@ export const getters: GetterTree<IFlowsState, IRootState> = { | |
| hasVoiceMode: (state, getters) => includes(getters.activeFlow.supported_modes || [], SupportedMode.IVR), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)
|
||
| hasOfflineMode: (state, getters) => includes(getters.activeFlow.supported_modes || [], SupportedMode.OFFLINE), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter: ESLint Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)
|
||
| currentFlowsState: (state) => state, | ||
| selectedBlocks: (state, getters) => filter(getters.activeFlow.blocks, (block) => includes(state.selectedBlockUuids, block.uuid)), | ||
| } | ||
|
|
||
| export const mutations: MutationTree<IFlowsState> = { | ||
|
|
@@ -363,26 +364,26 @@ export const actions: ActionTree<IFlowsState, IRootState> = { | |
| }, | ||
|
|
||
| async flow_clearMultiSelection({state, dispatch}) { | ||
| forEach(state.selectedBlocks, (blockId: IBlock['uuid']) => { | ||
| forEach(state.selectedBlockUuids, (blockId: IBlock['uuid']) => { | ||
| dispatch('block_deselect', {blockId}) | ||
| }) | ||
| }, | ||
|
|
||
| async flow_removeAllSelectedBlocks({state, dispatch}) { | ||
| forEach(state.selectedBlocks, (blockId: IBlock['uuid']) => { | ||
| forEach(state.selectedBlockUuids, (blockId: IBlock['uuid']) => { | ||
| dispatch('flow_removeBlock', {blockId}) | ||
| }) | ||
|
|
||
| state.selectedBlocks = [] | ||
| state.selectedBlockUuids = [] | ||
| }, | ||
|
|
||
| async flow_duplicateAllSelectedBlocks({state, dispatch}) { | ||
| const newBlocksUuid: string[] = [] | ||
| forEach(state.selectedBlocks, async (blockId: IBlock['uuid']) => { | ||
| const newBlocksUuids: string[] = [] | ||
| forEach(state.selectedBlockUuids, async (blockId: IBlock['uuid']) => { | ||
| const duplicatedBlock: IBlock = await dispatch('flow_duplicateBlock', {blockId}) | ||
| newBlocksUuid.push(duplicatedBlock.uuid) | ||
| newBlocksUuids.push(duplicatedBlock.uuid) | ||
| }) | ||
| state.selectedBlocks = newBlocksUuid | ||
| state.selectedBlockUuids = newBlocksUuids | ||
| }, | ||
| } | ||
|
|
||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reporter: ESLint
Rule: eslint.rules.vue/order-in-components
Severity: WARN
File: src/components/interaction-designer/Block.vue L260
The "computed" property should be above the "watch" property on line 242. (vue/order-in-components)