Skip to content

Commit

Permalink
feat(Designer): Dynamic data performance improvements (#4483)
Browse files Browse the repository at this point in the history
* Combined dynamic data clear dispatches

* Added .eslintcache to .gitignore

* Reduced dispatches on load

* Schema request is now cached so multiple operations can share data

* Added performance debug component for testing

* Don't run dev slice in prod

* Removed .eslintcache from repo

* Collapsed "updateExistingInputTokenTitles" action

* Removed unneeded "updateNodeParameters" dispatch

* Removed comments + log

---------

Co-authored-by: Riley Evans <rileyevans@Rileys-MacBook-Pro.local>
  • Loading branch information
rllyy97 and Riley Evans committed Apr 8, 2024
1 parent f48f2fe commit 1f6477c
Show file tree
Hide file tree
Showing 25 changed files with 498 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,18 @@ const DesignerEditor = () => {
}));

const dispatch = useDispatch<AppDispatch>();
const { isReadOnly, isDarkMode, isMonitoringView, runId, appId, showChatBot, language, hostOptions, showConnectionsPanel } = useSelector(
(state: RootState) => state.workflowLoader
);
const {
isReadOnly,
isDarkMode,
isMonitoringView,
runId,
appId,
showChatBot,
language,
hostOptions,
showConnectionsPanel,
showPerformanceDebug,
} = useSelector((state: RootState) => state.workflowLoader);

const workflowName = workflowId.split('/').splice(-1)[0];
const siteResourceId = new ArmParser(workflowId).topmostResourceId;
Expand Down Expand Up @@ -299,6 +308,7 @@ const DesignerEditor = () => {
recurrenceInterval: { interval: 1, frequency: 'Minute' },
},
showConnectionsPanel,
showPerformanceDebug,
}}
>
{workflow?.definition ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
ConsumptionRunService,
guid,
startsWith,
StandardCustomCodeService,
} from '@microsoft/logic-apps-shared';
import type { Workflow } from '@microsoft/logic-apps-designer';
import {
Expand Down Expand Up @@ -67,6 +68,7 @@ const DesignerEditorConsumption = () => {
showChatBot,
hostOptions,
showConnectionsPanel,
showPerformanceDebug,
language,
} = useSelector((state: RootState) => state.workflowLoader);

Expand Down Expand Up @@ -214,6 +216,7 @@ const DesignerEditorConsumption = () => {
...hostOptions,
recurrenceInterval: Constants.RECURRENCE_OPTIONS.CONSUMPTION,
},
showPerformanceDebug,
}}
>
{workflow?.definition ? (
Expand Down Expand Up @@ -436,6 +439,18 @@ const getDesignerServices = (
location: 'westcentralus',
});

// This isn't correct but without it I was getting errors
// It's fine just to unblock standalone consumption
const customCodeService = new StandardCustomCodeService({
apiVersion: '2018-11-01',
baseUrl: 'test',
subscriptionId,
resourceGroup,
appName: 'test',
workflowName,
httpClient,
});

const hostService = {};

return {
Expand All @@ -453,6 +468,7 @@ const getDesignerServices = (
runService,
hostService,
chatbotService,
customCodeService,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
useIsReadOnly,
useShowConnectionsPanel,
useHostOptions,
useShowPerformanceDebug,
} from '../../state/workflowLoadingSelectors';
import {
setDarkMode,
Expand All @@ -16,6 +17,7 @@ import {
setAreCustomEditorsEnabled,
setShowConnectionsPanel,
setHostOptions,
setShowPerformanceDebug,
} from '../../state/workflowLoadingSlice';
import { Checkbox } from '@fluentui/react';
import { useCallback } from 'react';
Expand All @@ -28,6 +30,7 @@ const ContextSettings = () => {
const showConnectionsPanel = useShowConnectionsPanel();
const areCustomEditorsEnabled = useAreCustomEditorsEnabled();
const hostOptions = useHostOptions();
const showPerformanceDebug = useShowPerformanceDebug();
const dispatch = useDispatch<AppDispatch>();

const changeMonitoringView = useCallback(
Expand All @@ -42,7 +45,7 @@ const ContextSettings = () => {
);

return (
<div style={{ display: 'flex', gap: '24px' }}>
<div style={{ display: 'flex', gap: '24px', flexWrap: 'wrap' }}>
<Checkbox
label="Read Only"
disabled={isMonitoringView}
Expand Down Expand Up @@ -71,6 +74,11 @@ const ContextSettings = () => {
checked={hostOptions.forceEnableSplitOn}
onChange={(_, checked) => dispatch(setHostOptions({ forceEnableSplitOn: !!checked }))}
/>
<Checkbox
label="Show Performance Debug"
checked={showPerformanceDebug}
onChange={(_, checked) => dispatch(setShowPerformanceDebug(!!checked))}
/>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ export const useShowConnectionsPanel = () => {
export const useAreCustomEditorsEnabled = () => {
return useSelector((state: RootState) => state.workflowLoader.areCustomEditorsEnabled);
};

export const useShowPerformanceDebug = () => {
return useSelector((state: RootState) => state.workflowLoader.showPerformanceDebug);
};
6 changes: 6 additions & 0 deletions apps/Standalone/src/desginer/state/workflowLoadingSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface WorkflowLoadingState {
displayRuntimeInfo: boolean; // show info about where the action is run(i.e. InApp/Shared/Custom)
forceEnableSplitOn?: boolean; // force enable split on for all actions
};
showPerformanceDebug?: boolean;
}

const initialState: WorkflowLoadingState = {
Expand All @@ -49,6 +50,7 @@ const initialState: WorkflowLoadingState = {
hostOptions: {
displayRuntimeInfo: true,
},
showPerformanceDebug: false,
};

type WorkflowPayload = {
Expand Down Expand Up @@ -162,6 +164,9 @@ export const workflowLoadingSlice = createSlice({
setHostOptions: (state, action: PayloadAction<Partial<WorkflowLoadingState['hostOptions']>>) => {
state.hostOptions = { ...state.hostOptions, ...action.payload };
},
setShowPerformanceDebug: (state, action: PayloadAction<boolean>) => {
state.showPerformanceDebug = action.payload;
},
},
extraReducers: (builder) => {
builder.addCase(loadWorkflow.fulfilled, (state, action: PayloadAction<WorkflowPayload | null>) => {
Expand Down Expand Up @@ -199,6 +204,7 @@ export const {
loadLastWorkflow,
setAreCustomEditorsEnabled,
setHostOptions,
setShowPerformanceDebug,
} = workflowLoadingSlice.actions;

export default workflowLoadingSlice.reducer;
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export const initializeOperationDetailsForManifest = async (
const schema = staticResultService.getOperationResultSchema(connectorId, operationId, parsedManifest);
schema.then((schema) => {
if (schema) {
dispatch(addResultSchema({ id: `${connectorId}-${operationId}`, schema: schema }));
dispatch(addResultSchema({ id: `${connectorId}-${operationId}`, schema }));
}
});

Expand Down Expand Up @@ -530,7 +530,7 @@ const initializeRepetitionInfos = async (
);
};

export const updateDynamicDataInNodes = async (getState: () => RootState, dispatch: Dispatch): Promise<void> => {
export const initializeDynamicDataInNodes = async (getState: () => RootState, dispatch: Dispatch): Promise<void> => {
const rootState = getState();
const {
workflow: { nodesMetadata, operations },
Expand All @@ -541,31 +541,32 @@ export const updateDynamicDataInNodes = async (getState: () => RootState, dispat
const allVariables = getAllVariables(variables);
for (const [nodeId, operation] of Object.entries(operations)) {
if (nodeId === Constants.NODE.TYPE.PLACEHOLDER_TRIGGER) continue;
if (!getRecordEntry(errors, nodeId)?.[ErrorLevel.Critical]) {
const nodeDependencies = getRecordEntry(dependencies, nodeId);
const nodeInputs = getRecordEntry(inputParameters, nodeId);
const nodeSettings = getRecordEntry(settings, nodeId);
const isTrigger = isRootNodeInGraph(nodeId, 'root', nodesMetadata);
const nodeOperationInfo = getRecordEntry(operationInfo, nodeId);
const connectionReference = getConnectionReference(connections, nodeId);

if (nodeOperationInfo && nodeDependencies && nodeInputs && nodeSettings) {
updateDynamicDataForValidConnection(
nodeId,
isTrigger,
nodeOperationInfo,
connectionReference,
nodeDependencies,
nodeInputs,
nodeSettings,
allVariables,
dispatch,
getState,
operation
);
}
}
if (getRecordEntry(errors, nodeId)?.[ErrorLevel.Critical]) continue;

const nodeOperationInfo = getRecordEntry(operationInfo, nodeId);
const nodeDependencies = getRecordEntry(dependencies, nodeId);
const nodeInputs = getRecordEntry(inputParameters, nodeId);
const nodeSettings = getRecordEntry(settings, nodeId);
if (!nodeOperationInfo || !nodeDependencies || !nodeInputs || !nodeSettings) continue;

const isTrigger = isRootNodeInGraph(nodeId, 'root', nodesMetadata);
const connectionReference = getConnectionReference(connections, nodeId);

updateDynamicDataForValidConnection(
nodeId,
isTrigger,
nodeOperationInfo,
connectionReference,
nodeDependencies,
nodeInputs,
nodeSettings,
allVariables,
dispatch,
getState,
operation
);
}

dispatch(updateDynamicDataLoadStatus(true));
};

Expand Down
4 changes: 2 additions & 2 deletions libs/designer/src/lib/core/parsers/ParseReduxAction.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Workflow } from '../../common/models/workflow';
import { getConnectionsApiAndMapping } from '../actions/bjsworkflow/connections';
import { updateWorkflowParameters } from '../actions/bjsworkflow/initialize';
import { initializeOperationMetadata, updateDynamicDataInNodes } from '../actions/bjsworkflow/operationdeserializer';
import { initializeOperationMetadata, initializeDynamicDataInNodes } from '../actions/bjsworkflow/operationdeserializer';
import { getConnectionsQuery } from '../queries/connections';
import { initializeConnectionReferences } from '../state/connection/connectionSlice';
import { initializeStaticResultProperties } from '../state/staticresultschema/staticresultsSlice';
Expand Down Expand Up @@ -68,7 +68,7 @@ export const initializeGraphState = createAsyncThunk<
),
getConnectionsApiAndMapping(deserializedWorkflow, thunkAPI.dispatch),
]);
await updateDynamicDataInNodes(thunkAPI.getState, thunkAPI.dispatch);
await initializeDynamicDataInNodes(thunkAPI.getState, thunkAPI.dispatch);

LoggerService().endTrace(traceId, { status: Status.Success });
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface DesignerOptionsState {
nodeSelectAdditionalCallback?: (nodeId: string) => any;
showConnectionsPanel?: boolean;
panelTabHideKeys?: PANEL_TAB_NAMES[];
showPerformanceDebug?: boolean;
}

export interface ServiceOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export const useShowConnectionsPanel = () => {
return useSelector((state: RootState) => state.designerOptions?.showConnectionsPanel ?? false);
};

export const useShowPerformanceDebug = () => {
return useSelector((state: RootState) => state.designerOptions.showPerformanceDebug ?? false);
};

export const useAreDesignerOptionsInitialized = () => {
return useSelector((state: RootState) => state.designerOptions?.designerOptionsInitialized ?? false);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export const designerOptionsSlice = createSlice({
...state.hostOptions,
...action.payload.hostOptions,
};
state.showPerformanceDebug = action.payload.showPerformanceDebug;
state.designerOptionsInitialized = true;
},
},
Expand Down
3 changes: 3 additions & 0 deletions libs/designer/src/lib/core/state/dev/devInterfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface DevState {
reduxActionCounts?: Record<string, number>;
}
6 changes: 6 additions & 0 deletions libs/designer/src/lib/core/state/dev/devSelectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { RootState } from '../../store';
import { useSelector } from 'react-redux';

export const useReduxActionCounts = () => {
return useSelector((state: RootState) => state.dev.reduxActionCounts ?? {});
};
31 changes: 31 additions & 0 deletions libs/designer/src/lib/core/state/dev/devSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { resetWorkflowState } from '../global';
import type { DevState } from './devInterfaces';
import { createSlice } from '@reduxjs/toolkit';

const initialState: DevState = {
reduxActionCounts: {},
};

export const devSlice = createSlice({
name: 'dev',
initialState,
reducers: {
// Nothing
},
extraReducers: (builder) => {
// Reset the state on workflow reset
builder.addCase(resetWorkflowState, () => initialState);
// Count the number of times each action is dispatched
builder.addMatcher(
() => true,
(state, action) => {
state.reduxActionCounts = {
...state.reduxActionCounts,
[action.type]: (state.reduxActionCounts?.[action.type] ?? 0) + 1,
};
}
);
},
});

export default devSlice.reducer;
Loading

0 comments on commit 1f6477c

Please sign in to comment.