Skip to content

Commit

Permalink
refactor: break down the design page(the first step) (microsoft#5623)
Browse files Browse the repository at this point in the history
* perf: split the design page

* fix confilcts

* fix some comments

* fix lint

* fix e2e test

* refine the four parts

* remove unused import

* fix dialogid is empty

* fix e2e test

Co-authored-by: Srinaath Ravichandran <[email protected]>
  • Loading branch information
lei9444 and srinaath authored Feb 1, 2021
1 parent cfcf6b1 commit d0f7ceb
Show file tree
Hide file tree
Showing 17 changed files with 1,094 additions and 801 deletions.
2 changes: 1 addition & 1 deletion Composer/cypress/integration/LuisDeploy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ context('Luis Deploy', () => {
cy.route('GET', '/api/publish/*/status/default', { endpointURL: 'anything', status: 404 });
cy.visit('/home');
cy.createBot('ToDoBotWithLuisSample');
cy.visitPage('Design');
});

it('can deploy luis success', () => {
Expand All @@ -17,7 +18,6 @@ context('Luis Deploy', () => {
cy.findAllByTestId('rootLUISRegion').click();
cy.findByText('westus').click();
cy.visitPage('User Input');
cy.url().should('contain', 'language-understanding/all');
cy.visitPage('Design');
cy.route({
method: 'POST',
Expand Down
2 changes: 1 addition & 1 deletion Composer/cypress/integration/NewDialog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ context('Creating a new Dialog', () => {
cy.findByTestId('BotHeader-__TestTodoSample').within(() => {
cy.findByTestId('dialogMoreButton').click({ force: true });
});
cy.findAllByText('Add a dialog').click();
cy.findAllByText('Add a dialog').click({ force: true });
cy.findByTestId('NewDialogName').type('{selectall}TestNewDialog2{enter}');
cy.findByTestId('ProjectTree').within(() => {
cy.findByText('TestNewDialog2').should('exist');
Expand Down
27 changes: 5 additions & 22 deletions Composer/packages/client/src/components/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,11 @@

/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import { Fragment, useMemo } from 'react';
import { Fragment } from 'react';
import formatMessage from 'format-message';
import { NeutralColors } from '@uifabric/fluent-theme';
import { ActionButton, CommandButton } from 'office-ui-fabric-react/lib/Button';
import { IContextualMenuProps, IIconProps } from 'office-ui-fabric-react/lib';
import { EditorExtension, mergePluginConfigs, PluginConfig } from '@bfc/extension-client';
import { useRecoilValue } from 'recoil';

import plugins from '../plugins';
import { currentProjectIdState, schemasState } from '../recoilModel';
import { useShell } from '../shell/useShell';

// -------------------- Styles -------------------- //

Expand Down Expand Up @@ -103,15 +97,6 @@ type ToolbarProps = {
// fabric-ui IButtonProps interface}
export const Toolbar = (props: ToolbarProps) => {
const { toolbarItems = [], ...rest } = props;
const projectId = useRecoilValue(currentProjectIdState);
const schemas = useRecoilValue(schemasState(projectId));
const shellForPropertyEditor = useShell('DesignPage', projectId);

const pluginConfig: PluginConfig = useMemo(() => {
const sdkUISchema = schemas?.ui?.content ?? {};
const userUISchema = schemas?.uiOverrides?.content ?? {};
return mergePluginConfigs({ uiSchema: sdkUISchema }, plugins, { uiSchema: userUISchema });
}, [schemas?.ui?.content, schemas?.uiOverrides?.content]);

const left: IToolbarItem[] = [];
const right: IToolbarItem[] = [];
Expand All @@ -127,11 +112,9 @@ export const Toolbar = (props: ToolbarProps) => {
}

return (
<EditorExtension plugins={pluginConfig} projectId={projectId} shell={shellForPropertyEditor}>
<div aria-label={formatMessage('toolbar')} css={headerSub} role="region" {...rest}>
<div css={leftActions}>{left.map(renderItemList)} </div>
<div css={rightActions}>{right.map(renderItemList)}</div>
</div>
</EditorExtension>
<div aria-label={formatMessage('toolbar')} css={headerSub} role="region" {...rest}>
<div css={leftActions}>{left.map(renderItemList)} </div>
<div css={rightActions}>{right.map(renderItemList)}</div>
</div>
);
};
190 changes: 190 additions & 0 deletions Composer/packages/client/src/pages/design/CommandBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/** @jsx jsx */
import { jsx } from '@emotion/core';
import React, { useMemo, useCallback, useEffect } from 'react';
import formatMessage from 'format-message';
import get from 'lodash/get';
import { getEditorAPI, registerEditorAPI } from '@bfc/shared';
import { useRecoilValue } from 'recoil';

import { Toolbar, IToolbarItem } from '../../components/Toolbar';
import { createDiagnosticsPageUrl, navigateTo } from '../../utils/navigation';
import {
visualEditorSelectionState,
dispatcherState,
rootBotProjectIdSelector,
currentDialogState,
} from '../../recoilModel';
import { undoFunctionState } from '../../recoilModel/undo/history';
import { undoStatusSelectorFamily } from '../../recoilModel/selectors/undo';
import { DiagnosticsHeader } from '../../components/DiagnosticsHeader';
import TelemetryClient from '../../telemetry/TelemetryClient';

type CommandBarProps = { dialogId?: string; projectId: string };

const CommandBar: React.FC<CommandBarProps> = ({ dialogId, projectId }) => {
const currentDialog = useRecoilValue(currentDialogState({ dialogId, projectId }));
const { undo, redo, clearUndo } = useRecoilValue(undoFunctionState(projectId));
const rootProjectId = useRecoilValue(rootBotProjectIdSelector) ?? projectId;
const visualEditorSelection = useRecoilValue(visualEditorSelectionState);
const [canUndo, canRedo] = useRecoilValue(undoStatusSelectorFamily(projectId));

const { onboardingAddCoachMarkRef } = useRecoilValue(dispatcherState);

useEffect(() => {
registerEditorAPI('Editing', {
Undo: () => undo(),
Redo: () => redo(),
});
//leave design page should clear the history
return clearUndo;
}, []);

const { actionSelected, showDisableBtn, showEnableBtn } = useMemo(() => {
const actionSelected = Array.isArray(visualEditorSelection) && visualEditorSelection.length > 0;
if (!actionSelected) {
return { actionSelected: false, showDisableBtn: false, showEnableBtn: false };
}
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, currentDialog?.content]);

const EditorAPI = getEditorAPI();

const toolbarItems: IToolbarItem[] = useMemo(
() => [
{
type: 'element',
element: <DiagnosticsHeader onClick={() => navigateTo(createDiagnosticsPageUrl(rootProjectId))} />,
align: 'right',
},
{
type: 'dropdown',
text: formatMessage('Edit'),
align: 'left',
dataTestid: 'EditFlyout',
buttonProps: {
iconProps: { iconName: 'Edit' },
},
menuProps: {
onMenuOpened: () => {
TelemetryClient.track('ToolbarButtonClicked', { name: 'edit' });
},
items: [
{
key: 'edit.undo',
text: formatMessage('Undo'),
disabled: !canUndo,
onClick: () => {
undo();
TelemetryClient.track('ToolbarButtonClicked', { name: 'undo' });
},
},
{
key: 'edit.redo',
text: formatMessage('Redo'),
disabled: !canRedo,
onClick: () => {
redo();
TelemetryClient.track('ToolbarButtonClicked', { name: 'redo' });
},
},
{
key: 'edit.cut',
text: formatMessage('Cut'),
disabled: !actionSelected,
onClick: () => {
EditorAPI.Actions.CutSelection();
TelemetryClient.track('ToolbarButtonClicked', { name: 'cut' });
},
},
{
key: 'edit.copy',
text: formatMessage('Copy'),
disabled: !actionSelected,
onClick: () => {
EditorAPI.Actions.CopySelection();
TelemetryClient.track('ToolbarButtonClicked', { name: 'copy' });
},
},
{
key: 'edit.move',
text: formatMessage('Move'),
disabled: !actionSelected,
onClick: () => {
EditorAPI.Actions.MoveSelection();
TelemetryClient.track('ToolbarButtonClicked', { name: 'move' });
},
},
{
key: 'edit.delete',
text: formatMessage('Delete'),
disabled: !actionSelected,
onClick: () => {
EditorAPI.Actions.DeleteSelection();
TelemetryClient.track('ToolbarButtonClicked', { name: 'delete' });
},
},
],
},
},
{
type: 'dropdown',
text: formatMessage('Disable'),
align: 'left',
disabled: !actionSelected,
buttonProps: {
iconProps: { iconName: 'RemoveOccurrence' },
},
menuProps: {
onMenuOpened: () => {
TelemetryClient.track('ToolbarButtonClicked', { name: 'disableDropdown' });
},
items: [
{
key: 'disable',
text: formatMessage('Disable'),
disabled: !showDisableBtn,
onClick: () => {
EditorAPI.Actions.DisableSelection();
TelemetryClient.track('ToolbarButtonClicked', { name: 'disable' });
},
},
{
key: 'enable',
text: formatMessage('Enable'),
disabled: !showEnableBtn,
onClick: () => {
EditorAPI.Actions.EnableSelection();
TelemetryClient.track('ToolbarButtonClicked', { name: 'enable' });
},
},
],
},
},
],
[showDisableBtn, showEnableBtn, actionSelected, canUndo, canRedo]
);

const addNewBtnRef = useCallback((addNew) => {
onboardingAddCoachMarkRef({ addNew });
}, []);

return (
<div css={{ position: 'relative' }} data-testid="DesignPage-ToolBar">
<span
ref={addNewBtnRef}
css={{ width: 120, height: '100%', position: 'absolute', left: 0, visibility: 'hidden' }}
data-testid="CoachmarkRef-AddNew"
/>
<Toolbar toolbarItems={toolbarItems} />
</div>
);
};

export default CommandBar;
Loading

0 comments on commit d0f7ceb

Please sign in to comment.