From 534ecb37aaee2c6793e6f5626a0f0b6c57f5eabe Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Thu, 5 Mar 2020 18:36:59 +0800 Subject: [PATCH 1/4] clean affected parent node cache --- .../visual-designer/src/editors/ObiEditor.tsx | 16 ++++++++++++++++ .../visual-designer/src/store/DesignerCache.ts | 7 +++++++ .../visual-designer/src/utils/jsonTracker.ts | 16 ++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx b/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx index aafe981915..efaff7e3c1 100644 --- a/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx +++ b/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx @@ -6,6 +6,7 @@ import { jsx } from '@emotion/core'; import { useContext, FC, useEffect, useState, useRef } from 'react'; import { MarqueeSelection, Selection } from 'office-ui-fabric-react/lib/MarqueeSelection'; import { deleteAction, deleteActions, LgTemplateRef, LgMetaData } from '@bfc/shared'; +import get from 'lodash/get'; import { NodeEventTypes } from '../constants/NodeEventTypes'; import { KeyboardCommandTypes, KeyboardPrimaryTypes } from '../constants/KeyboardCommandTypes'; @@ -20,12 +21,14 @@ import { appendNodesAfter, pasteNodes, deleteNodes, + getParentPaths, } from '../utils/jsonTracker'; import { moveCursor, querySelectableElements, SelectorElement } from '../utils/cursorTracker'; import { NodeIndexGenerator } from '../utils/NodeIndexGetter'; import { normalizeSelection } from '../utils/normalizeSelection'; import { KeyboardZone } from '../components/lib/KeyboardZone'; import { scrollNodeIntoView } from '../utils/nodeOperation'; +import { designerCache } from '../store/DesignerCache'; import { AdaptiveDialogEditor } from './AdaptiveDialogEditor'; @@ -59,6 +62,14 @@ export const ObiEditor: FC = ({ return removeLgTemplates(lgFileId, normalizedLgTemplates); }; + const trackLayoutChange = (actionPath: string) => { + const affectedPaths = getParentPaths(actionPath); + for (const path of affectedPaths) { + const json = get(data, path); + designerCache.uncacheBoundary(json); + } + }; + const dispatchEvent = (eventName: NodeEventTypes, eventData: any): any => { let handler; switch (eventName) { @@ -79,12 +90,14 @@ export const ObiEditor: FC = ({ handler = ({ caller, callee }) => onOpen(callee, caller); break; case NodeEventTypes.Delete: + trackLayoutChange(eventData.id); handler = e => { onChange(deleteNode(data, e.id, node => deleteAction(node, deleteLgTemplates))); onFocusSteps([]); }; break; case NodeEventTypes.Insert: + trackLayoutChange(eventData.id); if (eventData.$type === 'PASTE') { handler = e => { // TODO: clean this along with node deletion. @@ -129,6 +142,7 @@ export const ObiEditor: FC = ({ }; break; case NodeEventTypes.CutSelection: + trackLayoutChange(eventData.id); handler = e => { const { dialog, cutData } = cutNodes(data, e.actionIds); onChange(dialog); @@ -137,6 +151,7 @@ export const ObiEditor: FC = ({ }; break; case NodeEventTypes.DeleteSelection: + trackLayoutChange(eventData.id); handler = e => { const dialog = deleteNodes(data, e.actionIds, nodes => deleteActions(nodes, deleteLgTemplates)); onChange(dialog); @@ -144,6 +159,7 @@ export const ObiEditor: FC = ({ }; break; case NodeEventTypes.AppendSelection: + trackLayoutChange(eventData.id); handler = e => { // forbid paste to root level. if (!e.target || e.target === focusedEvent) return; diff --git a/Composer/packages/extensions/visual-designer/src/store/DesignerCache.ts b/Composer/packages/extensions/visual-designer/src/store/DesignerCache.ts index 39e27f9bb7..b4a52ff7f8 100644 --- a/Composer/packages/extensions/visual-designer/src/store/DesignerCache.ts +++ b/Composer/packages/extensions/visual-designer/src/store/DesignerCache.ts @@ -36,6 +36,13 @@ export class DesignerCache { return true; } + uncacheBoundary(actionData: BaseSchema): boolean { + const key = this.getActionDataHash(actionData); + if (!key) return false; + + return delete this.boundaryCache[key]; + } + loadBounary(actionData: BaseSchema): Boundary | undefined { const key = this.getActionDataHash(actionData); if (key) { diff --git a/Composer/packages/extensions/visual-designer/src/utils/jsonTracker.ts b/Composer/packages/extensions/visual-designer/src/utils/jsonTracker.ts index e6ab0647fa..dc58c0bd18 100644 --- a/Composer/packages/extensions/visual-designer/src/utils/jsonTracker.ts +++ b/Composer/packages/extensions/visual-designer/src/utils/jsonTracker.ts @@ -221,3 +221,19 @@ export async function pasteNodes(inputDialog, arrayPath, arrayIndex, newNodes, c targetArray.currentData.splice(arrayIndex, 0, ...copiedNodes); return dialog; } + +export const getParentPaths = (actionPath: string): string[] => { + if (!actionPath) return []; + const selectors = actionPath.split('.'); + // exclude the path of current action + selectors.pop(); + if (!selectors.length) return []; + + let path = selectors[0]; + const results = [path]; + for (let i = 1; i < selectors.length; i++) { + path = `${path}.${selectors[i]}`; + results.push(path); + } + return results; +}; From cc36cea0600ee2e63381221895e12fdd1f9b4f7a Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Thu, 5 Mar 2020 18:40:14 +0800 Subject: [PATCH 2/4] add UT for getParentPaths --- .../__tests__/transformers/jsonTracker.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Composer/packages/extensions/visual-designer/__tests__/transformers/jsonTracker.test.ts b/Composer/packages/extensions/visual-designer/__tests__/transformers/jsonTracker.test.ts index 8db837f16f..ff921503cc 100644 --- a/Composer/packages/extensions/visual-designer/__tests__/transformers/jsonTracker.test.ts +++ b/Composer/packages/extensions/visual-designer/__tests__/transformers/jsonTracker.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { insert, deleteNode, queryNode } from '../../src/utils/jsonTracker'; +import { insert, deleteNode, queryNode, getParentPaths } from '../../src/utils/jsonTracker'; describe('queryNode', () => { describe('can query correct result', () => { @@ -161,3 +161,13 @@ describe('delete node flow', () => { }); }); }); + +describe('getParentPaths', () => { + it('can generate correct parent paths.', () => { + expect(getParentPaths('a')).toEqual([]); + expect(getParentPaths('a.b')).toEqual(['a']); + expect(getParentPaths('a.b.c')).toEqual(['a', 'a.b']); + expect(getParentPaths('a.b.c.d')).toEqual(['a', 'a.b', 'a.b.c']); + expect(getParentPaths('triggers[0].actions[0].actions')).toEqual(['triggers[0]', 'triggers[0].actions[0]']); + }); +}); From d5beedefb8612d90dbf8dbf3ec8c4f299413ece3 Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Fri, 6 Mar 2020 10:24:37 +0800 Subject: [PATCH 3/4] support batch change --- .../visual-designer/src/editors/ObiEditor.tsx | 17 +++++++++++------ .../visual-designer/src/utils/jsonTracker.ts | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx b/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx index efaff7e3c1..8ddff39582 100644 --- a/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx +++ b/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx @@ -62,7 +62,7 @@ export const ObiEditor: FC = ({ return removeLgTemplates(lgFileId, normalizedLgTemplates); }; - const trackLayoutChange = (actionPath: string) => { + const trackActionChange = (actionPath: string) => { const affectedPaths = getParentPaths(actionPath); for (const path of affectedPaths) { const json = get(data, path); @@ -70,6 +70,11 @@ export const ObiEditor: FC = ({ } }; + const trackActionListChange = (actionPaths: string[]) => { + if (!Array.isArray(actionPaths)) return; + actionPaths.forEach(x => trackActionChange(x)); + }; + const dispatchEvent = (eventName: NodeEventTypes, eventData: any): any => { let handler; switch (eventName) { @@ -90,14 +95,14 @@ export const ObiEditor: FC = ({ handler = ({ caller, callee }) => onOpen(callee, caller); break; case NodeEventTypes.Delete: - trackLayoutChange(eventData.id); + trackActionChange(eventData.id); handler = e => { onChange(deleteNode(data, e.id, node => deleteAction(node, deleteLgTemplates))); onFocusSteps([]); }; break; case NodeEventTypes.Insert: - trackLayoutChange(eventData.id); + trackActionChange(eventData.id); if (eventData.$type === 'PASTE') { handler = e => { // TODO: clean this along with node deletion. @@ -142,7 +147,7 @@ export const ObiEditor: FC = ({ }; break; case NodeEventTypes.CutSelection: - trackLayoutChange(eventData.id); + trackActionChange(eventData.actionIds); handler = e => { const { dialog, cutData } = cutNodes(data, e.actionIds); onChange(dialog); @@ -151,7 +156,7 @@ export const ObiEditor: FC = ({ }; break; case NodeEventTypes.DeleteSelection: - trackLayoutChange(eventData.id); + trackActionListChange(eventData.actionIds); handler = e => { const dialog = deleteNodes(data, e.actionIds, nodes => deleteActions(nodes, deleteLgTemplates)); onChange(dialog); @@ -159,7 +164,7 @@ export const ObiEditor: FC = ({ }; break; case NodeEventTypes.AppendSelection: - trackLayoutChange(eventData.id); + trackActionListChange(eventData.target); handler = e => { // forbid paste to root level. if (!e.target || e.target === focusedEvent) return; diff --git a/Composer/packages/extensions/visual-designer/src/utils/jsonTracker.ts b/Composer/packages/extensions/visual-designer/src/utils/jsonTracker.ts index dc58c0bd18..1ee33a0576 100644 --- a/Composer/packages/extensions/visual-designer/src/utils/jsonTracker.ts +++ b/Composer/packages/extensions/visual-designer/src/utils/jsonTracker.ts @@ -223,7 +223,7 @@ export async function pasteNodes(inputDialog, arrayPath, arrayIndex, newNodes, c } export const getParentPaths = (actionPath: string): string[] => { - if (!actionPath) return []; + if (typeof actionPath !== 'string') return []; const selectors = actionPath.split('.'); // exclude the path of current action selectors.pop(); From 2a1e515639f3529d2e6aff83223d6a445dcfc46b Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Fri, 6 Mar 2020 10:43:41 +0800 Subject: [PATCH 4/4] use trackActionListChange in CutSelection --- .../extensions/visual-designer/src/editors/ObiEditor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx b/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx index 8ddff39582..d2130e8e82 100644 --- a/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx +++ b/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx @@ -147,7 +147,7 @@ export const ObiEditor: FC = ({ }; break; case NodeEventTypes.CutSelection: - trackActionChange(eventData.actionIds); + trackActionListChange(eventData.actionIds); handler = e => { const { dialog, cutData } = cutNodes(data, e.actionIds); onChange(dialog);