Skip to content

Conversation

@safydy-r
Copy link
Member

@safydy-r safydy-r commented Jun 15, 2021

Followed the last tech arch from miro (by Brett & Safidy) : https://miro.com/app/board/o9J_lXulmu4=/?moveToWidget=3074457360012269222&cot=14

operations[operation.kind] = operation
},

setBlockPositionTo(state, { position: { x, y }, block }) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved it as actions

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @safydy, can we try to separate our logic from our mutations? From what I understand, this mutation should remain in tact, and be dispatched to from the other action when we want to assign values; they can be named differently if that helps with readability, but the vuex state should be modified within mutations, and logic around those can be done in actions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh ... I see, thanks for requesting this. I think this makes sense because it would be dangerous to re-assign prop in actions. Even ESLint is saying Assignment to property of function parameter 'block'. (no-param-reassign)
Making a change here ... <3

@safydy-r safydy-r requested a review from bzabos June 15, 2021 02:18
Copy link
Member

@bzabos bzabos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @safydy ! I've left a couple notes on separation of concerns and hopefully reduce a bit of complexity. I'd love a demo sometime, let me know if you have any Qs. :)

operations[operation.kind] = operation
},

setBlockPositionTo(state, { position: { x, y }, block }) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @safydy, can we try to separate our logic from our mutations? From what I understand, this mutation should remain in tact, and be dispatched to from the other action when we want to assign values; they can be named differently if that helps with readability, but the vuex state should be modified within mutations, and logic around those can be done in actions.

if (!includes(rootState.flow.selectedBlockUuids, block.uuid)) {
block.vendor_metadata.io_viamo.uiData.xPosition = x
block.vendor_metadata.io_viamo.uiData.yPosition = y
} else { // the block is selected
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the if() {} above have a return statement after block.vendor_metadata.io_viamo.uiData.yPosition = y ? It seems like it's a special case that we can bail after to avoid having to take it into account later in this function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, let's make an early return

}

let shouldReversePosition = false;
if (translationDelta.x > 0 /* moving to the right */ ||
Copy link
Member

@bzabos bzabos Jun 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌 I agree with this eslint rule, I got burned trying to understand the second line of this if( as a statement within the if!


let shouldReversePosition = false;
if (translationDelta.x > 0 /* moving to the right */ ||
rootGetters['flow/selectedBlockAtTheFurthestLeftPosition'].vendor_metadata.io_viamo.uiData.xPosition > 0 /* left space still available */) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @safydy , thanks for putting the comments in, super helpful! One step further, can we extract some of these wordy lines into self-explaining variable names and then not need comments? The should help when reading the logic portions as English. eg.

const leftMostBlock = rootGetters['flow/selectedBlockAtTheFurthestLeftPosition']
const isMovingRight = translationDelta.x > 0
const hasMoreLeftSpaceAvailable = leftMostBlock.vendor_metadata.io_viamo.uiData.xPosition > 0

if (isMovingRight || hasMoreLeftSpaceAvailable) { ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the new getters like selectedBlockAtTheFurthestLeftPosition are only used here, can we move them into this file as a modue-level functions that we call directly? This would mitigate iterating every block on the canvas on every change if we're only ever using here :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for recommending self-explaining variable instead of comments, this way the code is easier to read

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with selectedBlockAtTheFurthestLeftPosition concern

const otherSelectedBlocks = filter(rootGetters['flow/selectedBlocks'], currentBlock => currentBlock.uuid !== block.uuid);
forEach(otherSelectedBlocks, async (currentBlock: IBlock) => {
let newPosition = {} as IPosition
await dispatch('setBlockPositionFromDelta', { delta: translationDelta, block: currentBlock }).then(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @safydy-r , a couple things on this one: I am feeling confused by the need to manage block and draggable separately. Can we wrap these two mutations into a single action (eg. setBlockAndSyncDraggablePositionTo({pos}) or setBlockAndSyncDraggablePositionFromDelta({delta})) then just call that everywhere? I think we want them to be the same in most circumstances, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good remark, I think setBlockAndSyncDraggablePositionFromDelta would be perfect. Changing ...

}

if(translationDelta.y > 0 /* moving to the top */ ||
rootGetters['flow/selectedBlockAtTheTopPosition'].vendor_metadata.io_viamo.uiData.yPosition - state.toolbarHeight > 0 /* top space still available */) {
Copy link
Member

@bzabos bzabos Jun 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might get hard to maintain as the UI becomes more fancy. It feels fragile to try to match css and logic. Is there a way we can remove the need to track anything to do with toolbar height? My first thought is to use CSS to manage margins:

------------------------ Toolbar
------------------------ Alerts Toolbar
|----------------------| Canvas
|----------------------|
|----------------------|
|----------------------|

Using the same logic as we already use to show/hide alerts-toolbar, we can (create, then) apply .has-notification-alerts-banner class to canvas which can add a margin-top of whatever the magic number is. This mitigates mixing javascript and css, keeps pixel variations within css, and avoids having those magic numbers sprinkled throughout our formulas and vuex state.

If we use margins instead of padding, then the top of what we can see on the canvas becomes the true top of the canvas and the formulas needn't be concerned.

What do you think about this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree this toolbarHeight might introduce new complexity to the code. I will check what can we do with margin as you suggested

},

isAnyTopSpaceAvailable(state, getters) {
return getters.selectedBlockAtTheTopPosition.vendor_metadata.io_viamo.uiData.yPosition - state.toolbarHeight > 0
Copy link
Member Author

@safydy-r safydy-r Jun 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bzabos , your comment about separating pixel computation is still relevant here.
I introduced this toolbarHeight because we would like to know in JS side if there is no more space between the topBlock and the toolbar, and we know the toolbar has a dynamic height.

I tried your proposal

Using the same logic as we already use to show/hide alerts-toolbar, we can (create, then) apply .has-notification-alerts-banner class to canvas which can add a margin-top of whatever the magic number is. This mitigates mixing javascript and css, keeps pixel variations within css, and avoids having those magic numbers sprinkled throughout our formulas and vuex state.

... but I cannot resolve the challenge of removing this formula getters.selectedBlockAtTheTopPosition.vendor_metadata.io_viamo.uiData.yPosition - state.toolbarHeight > 0 from JS. Any idea ?

Screen Shot 2021-06-21 at 3 08 05 PM

safydy added 3 commits July 13, 2021 17:22
…ocks-alternative-2

# Conflicts:
#	src/components/interaction-designer/Block.vue
#	src/components/interaction-designer/toolbar/ErrorNotifications.vue
#	src/components/interaction-designer/toolbar/SelectionBanner.vue
#	src/components/interaction-designer/toolbar/TreeBuilderToolbar.vue
#	src/store/builder/index.ts
#	src/store/flow/block.ts
#	src/store/flow/flow.ts
#	src/store/flow/index.ts
#	src/views/InteractionDesigner.vue
@github-actions
Copy link

Found 16 violations:

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)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/restrict-plus-operands
Severity: ERROR
File: src/store/builder/index.ts L248

Operands of '+' operation must either be both strings or both numbers. (@typescript-eslint/restrict-plus-operands)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/restrict-plus-operands
Severity: ERROR
File: src/store/builder/index.ts L247

Operands of '+' operation must either be both strings or both numbers. (@typescript-eslint/restrict-plus-operands)

Reporter: ESLint
Rule: eslint.rules.lodash/prefer-filter
Severity: ERROR
File: src/store/builder/index.ts L227

Prefer _.filter or _.some over an if statement inside a _.forEach (lodash/prefer-filter)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/strict-boolean-expressions
Severity: ERROR
File: src/store/builder/index.ts L207

Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/strict-boolean-expressions
Severity: ERROR
File: src/store/builder/index.ts L198

Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)

Reporter: ESLint
Rule: eslint.rules.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L108

Do not use property shorthand syntax (lodash/prop-shorthand)

Reporter: ESLint
Rule: eslint.rules.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L104

Do not use property shorthand syntax (lodash/prop-shorthand)

Reporter: ESLint
Rule: eslint.rules.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L95

Do not use property shorthand syntax (lodash/prop-shorthand)

Reporter: ESLint
Rule: eslint.rules.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L95

Do not use property shorthand syntax (lodash/prop-shorthand)

Reporter: ESLint
Rule: eslint.rules.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L95

Do not use property shorthand syntax (lodash/prop-shorthand)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/strict-boolean-expressions
Severity: ERROR
File: src/store/flow/flow.ts L64

Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/strict-boolean-expressions
Severity: ERROR
File: src/store/flow/flow.ts L63

Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/explicit-module-boundary-types
Severity: WARN
File: src/views/InteractionDesigner.vue L350

Argument 'height' should be typed. (@typescript-eslint/explicit-module-boundary-types)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/explicit-module-boundary-types
Severity: WARN
File: src/views/InteractionDesigner.vue L350

Missing return type on function. (@typescript-eslint/explicit-module-boundary-types)

Reporter: ESLint
Rule: eslint.rules.@typescript-eslint/explicit-module-boundary-types
Severity: WARN
File: src/views/InteractionDesigner.vue L133

Missing return type on function. (@typescript-eslint/explicit-module-boundary-types)

@@ -259,11 +260,17 @@ export default {
computed: {

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)


const newPosition: IPosition = {
x: initialXPosition + x,
y: initialYPosition + y,

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.@typescript-eslint/restrict-plus-operands
Severity: ERROR
File: src/store/builder/index.ts L248

Operands of '+' operation must either be both strings or both numbers. (@typescript-eslint/restrict-plus-operands)

} = block

const newPosition: IPosition = {
x: initialXPosition + x,

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.@typescript-eslint/restrict-plus-operands
Severity: ERROR
File: src/store/builder/index.ts L247

Operands of '+' operation must either be both strings or both numbers. (@typescript-eslint/restrict-plus-operands)

}

// Translate other selected blocks
forEach(getters.selectedBlocks, (currentBlock: IBlock) => {

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.lodash/prefer-filter
Severity: ERROR
File: src/store/builder/index.ts L227

Prefer _.filter or _.some over an if statement inside a _.forEach (lodash/prefer-filter)

}

const isMovingToTheTop = translationDelta.y > 0
if (isMovingToTheTop || getters.isAnyTopSpaceAvailable) {

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.@typescript-eslint/strict-boolean-expressions
Severity: ERROR
File: src/store/builder/index.ts L207

Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)


let shouldReversePosition = false
const isMovingToTheRight = translationDelta.x > 0
if (isMovingToTheRight || getters.isAnyLeftSpaceAvailable) {

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.@typescript-eslint/strict-boolean-expressions
Severity: ERROR
File: src/store/builder/index.ts L198

Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)

},

selectedBlockAtTheFurthestLeftPosition(_state, getters) {
return minBy(getters.selectedBlocks, 'vendor_metadata.io_viamo.uiData.xPosition')

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.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L108

Do not use property shorthand syntax (lodash/prop-shorthand)

},

selectedBlockAtTheTopPosition(_state, getters) {
return minBy(getters.selectedBlocks, 'vendor_metadata.io_viamo.uiData.yPosition')

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.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L104

Do not use property shorthand syntax (lodash/prop-shorthand)

@@ -89,6 +95,26 @@ export const getters: GetterTree<IBuilderState, IRootState> = {
exitLabelsById: (_state, _getters, {flow: {flows}}) => mapValues(keyBy(flatMap(flows[0].blocks, 'exits'), 'uuid'), 'label'),

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.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L95

Do not use property shorthand syntax (lodash/prop-shorthand)

@@ -89,6 +95,26 @@ export const getters: GetterTree<IBuilderState, IRootState> = {
exitLabelsById: (_state, _getters, {flow: {flows}}) => mapValues(keyBy(flatMap(flows[0].blocks, 'exits'), 'uuid'), 'label'),

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.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L95

Do not use property shorthand syntax (lodash/prop-shorthand)

@@ -89,6 +95,26 @@ export const getters: GetterTree<IBuilderState, IRootState> = {
exitLabelsById: (_state, _getters, {flow: {flows}}) => mapValues(keyBy(flatMap(flows[0].blocks, 'exits'), 'uuid'), 'label'),

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.lodash/prop-shorthand
Severity: WARN
File: src/store/builder/index.ts L95

Do not use property shorthand syntax (lodash/prop-shorthand)

@@ -63,6 +63,7 @@ export const getters: GetterTree<IFlowsState, IRootState> = {
hasVoiceMode: (state, getters) => includes(getters.activeFlow.supported_modes || [], SupportedMode.IVR),
hasOfflineMode: (state, getters) => includes(getters.activeFlow.supported_modes || [], SupportedMode.OFFLINE),

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.@typescript-eslint/strict-boolean-expressions
Severity: ERROR
File: src/store/flow/flow.ts L64

Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)

@@ -63,6 +63,7 @@ export const getters: GetterTree<IFlowsState, IRootState> = {
hasVoiceMode: (state, getters) => includes(getters.activeFlow.supported_modes || [], SupportedMode.IVR),

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.@typescript-eslint/strict-boolean-expressions
Severity: ERROR
File: src/store/flow/flow.ts L63

Unexpected any value in conditional. An explicit comparison or type cast is required. (@typescript-eslint/strict-boolean-expressions)

@@ -347,7 +348,7 @@ export default {
},

handleToolBarHeightUpdate(height) {

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.@typescript-eslint/explicit-module-boundary-types
Severity: WARN
File: src/views/InteractionDesigner.vue L350

Argument 'height' should be typed. (@typescript-eslint/explicit-module-boundary-types)

@@ -347,7 +348,7 @@ export default {
},

handleToolBarHeightUpdate(height) {

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.@typescript-eslint/explicit-module-boundary-types
Severity: WARN
File: src/views/InteractionDesigner.vue L350

Missing return type on function. (@typescript-eslint/explicit-module-boundary-types)

@@ -132,7 +132,6 @@ export default {

data() {

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.@typescript-eslint/explicit-module-boundary-types
Severity: WARN
File: src/views/InteractionDesigner.vue L133

Missing return type on function. (@typescript-eslint/explicit-module-boundary-types)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants