Skip to content
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

feat: Disable / Enable actions #3416

Merged
merged 23 commits into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
83a7c50
impl disable/enable editor API
yeze322 Jun 11, 2020
e818c5d
disable / enable e2e
yeze322 Jun 11, 2020
8caf135
Merge branch 'master' into visual/disabled
yeze322 Jun 12, 2020
89c013d
propagate the 'disabled' property
yeze322 Jun 12, 2020
c406c71
take css out of CardTemplate
yeze322 Jun 12, 2020
46d6507
take css out of ActionHeader
yeze322 Jun 15, 2020
18b52c6
connect to the 'disabled' property in data
yeze322 Jun 15, 2020
7115bc8
CSS: disbaled effect
yeze322 Jun 15, 2020
042b5ab
update icon of Disabled/Enabled
yeze322 Jun 15, 2020
0490c0b
Merge branch 'master' into visual/disabled
yeze322 Jun 16, 2020
185ea2a
rename inheritParentProperty
yeze322 Jun 16, 2020
ff55604
shallow copy json in IndexedNode to support immutable
yeze322 Jun 16, 2020
c4cb431
Merge branch 'master' into visual/disabled
yeze322 Jun 20, 2020
6d5decf
rename files with '.style' suffix
yeze322 Jun 20, 2020
2618aa9
apply disable effect to PromptWidget
yeze322 Jun 20, 2020
d99cd06
only disable nodes when disabled === true
yeze322 Jun 20, 2020
d9e9e79
Merge branch 'master' into visual/disabled
yeze322 Jun 24, 2020
a37d2d6
contextual Disable/Enable btn state
yeze322 Jun 24, 2020
8c7c9b4
Merge branch 'master' into visual/disabled
yeze322 Jun 24, 2020
9b241ea
Merge branch 'master' into visual/disabled
yeze322 Jul 6, 2020
d0cfe99
Merge branch 'master' into visual/disabled
yeze322 Jul 8, 2020
9dd2ebd
move disable/enable button into toolbar
yeze322 Jul 8, 2020
2d042d2
avoid undefined array in UT
yeze322 Jul 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions Composer/packages/client/src/components/ToolBar/ToolBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

/** @jsx jsx */
import { jsx } from '@emotion/core';
import { useCallback, Fragment } from 'react';
import { useCallback, Fragment, useMemo } from 'react';
import formatMessage from 'format-message';
import { ActionButton, CommandButton } from 'office-ui-fabric-react/lib/Button';
import { DialogInfo } from '@bfc/shared';
import get from 'lodash/get';

import { useStoreContext } from '../../hooks/useStoreContext';
import { VisualEditorAPI } from '../../pages/design/FrameAPI';

import { headerSub, leftActions, rightActions, actionButton } from './styles';

Expand Down Expand Up @@ -67,8 +69,20 @@ export function ToolBar(props: ToolbarProps) {
} = props;
const {
actions: { onboardingAddCoachMarkRef, createDialogBegin, exportToZip },
state: { projectId },
state: { projectId, visualEditorSelection },
} = useStoreContext();

const { actionSelected, showDisableBtn, showEnableBtn } = useMemo(() => {
const actionSelected = Array.isArray(visualEditorSelection) && visualEditorSelection.length > 0;
if (!actionSelected) {
return {};
}
const selectedActions = visualEditorSelection.map((id) => get(currentDialog?.content, id));
const showDisableBtn = selectedActions.some((x) => get(x, 'disabled') !== true);
const showEnableBtn = selectedActions.some((x) => get(x, 'disabled') === true);
return { actionSelected, showDisableBtn, showEnableBtn };
}, [visualEditorSelection]);

const left: IToolBarItem[] = [];
const right: IToolBarItem[] = [];

Expand Down Expand Up @@ -122,6 +136,34 @@ export function ToolBar(props: ToolbarProps) {
</div>
)}
{left.map(itemList)}{' '}
{window.location.href.includes('/dialogs/') && (
<CommandButton
css={actionButton}
disabled={!actionSelected}
iconProps={{ iconName: 'RemoveOccurrence' }}
menuProps={{
items: [
{
key: 'disable',
text: formatMessage('Disable'),
disabled: !showDisableBtn,
onClick: () => {
VisualEditorAPI.disableSelection();
},
},
{
key: 'enable',
text: formatMessage('Enable'),
disabled: !showEnableBtn,
onClick: () => {
VisualEditorAPI.enableSelection();
},
},
],
}}
text={formatMessage('Disable')}
/>
)}
{window.location.href.includes('/dialogs/') && (
<CommandButton
css={actionButton}
Expand Down
2 changes: 2 additions & 0 deletions Composer/packages/client/src/pages/design/FrameAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,7 @@ export const VisualEditorAPI = (() => {
cutSelection: () => visualEditorFrameAPI.invoke('cutSelection'),
moveSelection: () => visualEditorFrameAPI.invoke('moveSelection'),
deleteSelection: () => visualEditorFrameAPI.invoke('deleteSelection'),
disableSelection: () => visualEditorFrameAPI.invoke('disableSelection'),
enableSelection: () => visualEditorFrameAPI.invoke('enableSelection'),
};
})();
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export enum ScreenReaderMessage {
DialogOpened = 'Dialog opened',
ActionDeleted = 'Action deleted',
ActionsDeleted = 'Actions deleted',
ActionsDisabled = 'Actions disabled',
ActionsEnabled = 'Actions enabled',
ActionCreated = 'Action created',
ActionsCreated = 'Actions created',
EventCreated = 'Event created',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export const useEditorEventApi = (
cutSelectedActions,
deleteSelectedAction,
deleteSelectedActions,
disableSelectedActions,
enableSelectedActions,
updateRecognizer,
} = useDialogEditApi(shellApi);
const { createDialog, readDialog, updateDialog } = useDialogApi(shellApi);
Expand Down Expand Up @@ -267,6 +269,20 @@ export const useEditorEventApi = (
announce(ScreenReaderMessage.ActionsDeleted);
};
break;
case NodeEventTypes.DisableSelection:
handler = () => {
const actionIds = getClipboardTargetsFromContext();
onChange(disableSelectedActions(path, data, actionIds));
announce(ScreenReaderMessage.ActionsDisabled);
};
break;
case NodeEventTypes.EnableSelection:
handler = () => {
const actionIds = getClipboardTargetsFromContext();
onChange(enableSelectedActions(path, data, actionIds));
announce(ScreenReaderMessage.ActionsEnabled);
};
break;
case NodeEventTypes.AppendSelection:
handler = (e) => {
trackActionListChange(e.target);
Expand Down Expand Up @@ -300,6 +316,8 @@ export const useEditorEventApi = (
(window as any).cutSelection = () => handleEditorEvent(NodeEventTypes.CutSelection);
(window as any).moveSelection = () => handleEditorEvent(NodeEventTypes.MoveSelection);
(window as any).deleteSelection = () => handleEditorEvent(NodeEventTypes.DeleteSelection);
(window as any).disableSelection = () => handleEditorEvent(NodeEventTypes.DisableSelection);
(window as any).enableSelection = () => handleEditorEvent(NodeEventTypes.EnableSelection);

return {
handleEditorEvent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import { Icon } from 'office-ui-fabric-react/lib/Icon';

import { IconBrickSize } from '../constants/ElementSizes';

export const IconBrick = ({ onClick }): JSX.Element => {
export const IconBrick = ({ onClick, disabled = false }): JSX.Element => {
const brickColor = disabled ? 'transparent' : '#FFFFFF';
const iconColor = disabled ? '#ddd' : '#FED9CC';

return (
<div
css={{
...IconBrickSize,
background: '#FFFFFF',
background: brickColor,
boxShadow: '0px 0.6px 1.8px rgba(0, 0, 0, 0.108), 0px 3.2px 7.2px rgba(0, 0, 0, 0.132)',
borderRadius: '2px',
cursor: 'pointer',
Expand All @@ -31,7 +34,7 @@ export const IconBrick = ({ onClick }): JSX.Element => {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: '#FED9CC',
background: iconColor,
width: 16,
height: 16,
borderRadius: '8px',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export enum NodeEventTypes {
PasteSelection = 'event.data.paste-selection',
MoveSelection = 'event.data.move-selection',
DeleteSelection = 'event.data.delete-selection',
DisableSelection = 'event.data.disable-selection',
EnableSelection = 'event.data.enable-selection',
AppendSelection = 'event.data.paste-selection--keyboard',
InsertSelection = 'event.data.paste-selection--menu',
Undo = 'event.operation.undo',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import clone from 'lodash/clone';

export class IndexedNode {
id: string;
json: any;
constructor(id, payload) {
this.id = id;
this.json = payload;
// Adaptive Flow lib leverages origin json to store necessary UI states,
// thus shallow clone input json here to support immutable case.
this.json = clone(payload);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { IndexedNode } from '../models/IndexedNode';

export const inheritParentProperties = (parentJson: any, childNodes: IndexedNode[]) => {
/** inherit the 'disabled' property */
if (parentJson.disabled === true) {
// Action.disabled is typed with IExpressionString but could be a boolean.
// Composer only show disable effects when it's strictly set to static {true}.
childNodes.forEach((node) => (node.json.disabled = true));
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { AdaptiveFieldNames } from '../constants/AdaptiveFieldNames';
import { AdaptiveKinds } from '../constants/AdaptiveKinds';
import { IndexedNode } from '../models/IndexedNode';

import { inheritParentProperties } from './inheritParentProperty';

const StepsKey = AdaptiveFieldNames.Actions;

export function transformForeach(
Expand All @@ -24,10 +26,13 @@ export function transformForeach(
children: steps,
});

return {
const result = {
foreachDetail: foreachDetailNode,
stepGroup: stepsNode,
loopBegin: new IndexedNode(jsonpath, { $kind: AdaptiveKinds.LoopIndicator }),
loopEnd: new IndexedNode(jsonpath, { $kind: AdaptiveKinds.LoopIndicator }),
};

inheritParentProperties(input, Object.values(result));
return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { AdaptiveFieldNames } from '../constants/AdaptiveFieldNames';
import { AdaptiveKinds } from '../constants/AdaptiveKinds';
import { IndexedNode } from '../models/IndexedNode';

import { inheritParentProperties } from './inheritParentProperty';

const IfBranchKey = AdaptiveFieldNames.Actions;
const ElseBranchKey = AdaptiveFieldNames.ElseActions;

Expand Down Expand Up @@ -33,5 +35,6 @@ export function transformIfCondtion(
}),
};

inheritParentProperties(input, Object.values(result));
return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import { AdaptiveKinds } from '../constants/AdaptiveKinds';
import { IndexedNode } from '../models/IndexedNode';
import { normalizeObiStep } from '../utils/adaptive/stepBuilder';

import { inheritParentProperties } from './inheritParentProperty';

export function transformStepGroup(input, groupId): IndexedNode[] {
if (!input || input.$kind !== AdaptiveKinds.StepGroup) return [];
if (!input.children || !Array.isArray(input.children)) return [];

return input.children.map((step, index) => new IndexedNode(`${groupId}[${index}]`, normalizeObiStep(step)));
const results = input.children.map((step, index) => new IndexedNode(`${groupId}[${index}]`, normalizeObiStep(step)));
inheritParentProperties(input, results);
return results;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { AdaptiveFieldNames } from '../constants/AdaptiveFieldNames';
import { AdaptiveKinds } from '../constants/AdaptiveKinds';
import { IndexedNode } from '../models/IndexedNode';

import { inheritParentProperties } from './inheritParentProperty';

const ConditionKey = AdaptiveFieldNames.Condition;
const CasesKey = AdaptiveFieldNames.Cases;
const CaseStepKey = AdaptiveFieldNames.Actions;
Expand Down Expand Up @@ -52,5 +54,7 @@ export function transformSwitchCondition(
});
})
);

inheritParentProperties(input, [result.condition, result.choice, ...result.branches]);
return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,13 @@ export interface ActionCardProps extends WidgetContainerProps {
}

export const ActionCard: WidgetComponent<ActionCardProps> = ({ header, body, footer, ...widgetContext }) => {
return <CardTemplate body={body} footer={footer} header={header || <ActionHeader {...widgetContext} />} />;
const disabled = widgetContext.data.disabled === true;
return (
<CardTemplate
body={body}
disabled={disabled}
footer={footer}
header={header || <ActionHeader {...widgetContext} />}
/>
);
};
Loading