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

Bot proj breadcrumbs #4

Merged
merged 31 commits into from
Nov 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ce2b892
remove old breadcrumbs and start making new ones
beyackle Oct 30, 2020
36f178e
Update DesignPage.tsx
beyackle Oct 30, 2020
e75713c
Update DesignPage.tsx
beyackle Oct 30, 2020
9375be0
Merge branch 'main' into beyackle/botProjBreadcrumbs
beyackle Nov 2, 2020
bc98e79
Merge branch 'main' into beyackle/botProjBreadcrumbs
beyackle Nov 2, 2020
f4c1f38
Merge branch 'main' into beyackle/botProjBreadcrumbs
beyackle Nov 2, 2020
545fc05
Merge branch 'beyackle/botProjBreadcrumbs' of https://github.com/micr…
beyackle Nov 2, 2020
2cb872c
update unit tests to remove breadcrumb things
beyackle Nov 2, 2020
be78ab3
Merge branch 'main' into beyackle/botProjBreadcrumbs
beyackle Nov 2, 2020
5f9d19a
fix duplicate key bug in breadcrumbs
beyackle Nov 2, 2020
fd79d22
fix e2e test
beyackle Nov 3, 2020
3c512cb
detect and display action names in breadcrumb
beyackle Nov 3, 2020
2195958
rewrite to make typechecker happy
beyackle Nov 3, 2020
11a04e8
Merge branch 'main' into beyackle/botProjBreadcrumbs
beyackle Nov 3, 2020
84a4e92
make new DesignPage unit tests
beyackle Nov 3, 2020
b672b16
Update publisher.ts
beyackle Nov 3, 2020
212bb1b
Update publisher.ts
beyackle Nov 3, 2020
09409b3
Merge branch 'main' into beyackle/botProjBreadcrumbs
cwhitten Nov 4, 2020
75c8348
restore navigation in undo
beyackle Nov 4, 2020
03a9028
Merge branch 'main' into beyackle/botProjBreadcrumbs
beyackle Nov 4, 2020
083c0be
retrieve breadcrumb from URL on location change
beyackle Nov 4, 2020
434550a
read double-nested $designer fields
beyackle Nov 4, 2020
e87dfff
navigate to trigger[0] on OpenDialog node events
beyackle Nov 4, 2020
bccc222
Merge branch 'main' into beyackle/botProjBreadcrumbs
beyackle Nov 4, 2020
1d79d27
fix typo and unit tests
beyackle Nov 4, 2020
81ddd6f
Merge branch 'beyackle/botProjBreadcrumbs' of https://github.com/micr…
beyackle Nov 4, 2020
9603669
Update validateDialogName.test.ts
beyackle Nov 4, 2020
b13e2b7
better error-checking for invalid URLs
beyackle Nov 5, 2020
9d561d9
make special "beginDialog" trigger
beyackle Nov 5, 2020
d78cc66
Update en-US.json
beyackle Nov 5, 2020
e315fa6
Update DesignPage.tsx
beyackle Nov 5, 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
4 changes: 2 additions & 2 deletions Composer/cypress/integration/Breadcrumb.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ context('breadcrumb', () => {
hasBreadcrumbItems(cy, ['__TestTodoSample']);
});

it('can show event name in breadcrumb', () => {
it('can show dialog and trigger name in breadcrumb', () => {
cy.findByTestId('ProjectTree').within(() => {
cy.findByTestId('addtodo_Dialog started').click();
});

hasBreadcrumbItems(cy, ['__TestTodoSample', 'Dialog started']);
hasBreadcrumbItems(cy, ['addtodo', 'Dialog started']);
});

it('can show action name in breadcrumb', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const useEditorEventApi = (
onFocusSteps,
onFocusEvent,
onCopy: onClipboardChange,
navTo: onOpen,
navTo,
saveData: onChange,
undo,
redo,
Expand Down Expand Up @@ -153,7 +153,7 @@ export const useEditorEventApi = (
break;
case NodeEventTypes.OpenDialog:
handler = ({ callee }) => {
onOpen(callee);
navTo(callee, '"beginDialog"');
announce(ScreenReaderMessage.DialogOpened);
};
break;
Expand Down
65 changes: 65 additions & 0 deletions Composer/packages/client/__tests__/pages/design/Design.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import React from 'react';

import { renderWithRecoil } from '../../testUtils';
import {
botProjectIdsState,
currentProjectIdState,
dialogsSelectorFamily,
schemasState,
projectMetaDataState,
botProjectFileState,
} from '../../../src/recoilModel';
import { undoFunctionState } from '../../../src/recoilModel/undo/history';
import mockProjectResponse from '../../../src/recoilModel/dispatchers/__tests__/mocks/mockProjectResponse.json';
import DesignPage from '../../../src/pages/design/DesignPage';
import { SAMPLE_DIALOG, SAMPLE_DIALOG_2 } from '../../mocks/sampleDialog';

const projectId = '12345.6789';
const skillId = '56789.1234';
const dialogId = SAMPLE_DIALOG.id;

const initRecoilState = ({ set }) => {
set(currentProjectIdState, projectId);
set(botProjectIdsState, [projectId]);
set(dialogsSelectorFamily(projectId), [SAMPLE_DIALOG]);
set(schemasState(projectId), mockProjectResponse.schemas);
set(projectMetaDataState(projectId), { isRootBot: true });
set(botProjectFileState(projectId), { foo: 'bar' });
set(undoFunctionState(projectId), { canUndo: () => false, canRedo: () => false });
};

const initRecoilStateMulti = ({ set }) => {
set(currentProjectIdState, projectId);
set(botProjectIdsState, [projectId, skillId]);
set(dialogsSelectorFamily(projectId), [SAMPLE_DIALOG]);
set(dialogsSelectorFamily(skillId), [SAMPLE_DIALOG, SAMPLE_DIALOG_2]);
set(schemasState(projectId), mockProjectResponse.schemas);
set(schemasState(skillId), mockProjectResponse.schemas);
set(projectMetaDataState(projectId), { isRootBot: true });
set(botProjectFileState(projectId), { foo: 'bar' });
set(undoFunctionState(projectId), { canUndo: () => false, canRedo: () => false });
set(undoFunctionState(skillId), { canUndo: () => false, canRedo: () => false });
};

describe('publish page', () => {
it('should render the design page (no skill)', () => {
const { getAllByText, getByText } = renderWithRecoil(
<DesignPage dialogId={dialogId} projectId={projectId} />,
initRecoilState
);
getAllByText(SAMPLE_DIALOG.displayName);
getByText('Start Bot');
});

it('should render the design page (with skill)', () => {
const { getAllByText, getByText } = renderWithRecoil(
<DesignPage dialogId={dialogId} projectId={projectId} skillId={skillId} />,
initRecoilStateMulti
);
getAllByText(SAMPLE_DIALOG.displayName);
getAllByText(SAMPLE_DIALOG_2.displayName);
getByText('Start Bot');
});
});
50 changes: 1 addition & 49 deletions Composer/packages/client/__tests__/utils/navigation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,7 @@

import { PromptTab } from '@bfc/shared';

import {
BreadcrumbUpdateType,
getUrlSearch,
checkUrl,
getFocusPath,
clearBreadcrumb,
updateBreadcrumb,
convertPathToUrl,
} from './../../src/utils/navigation';
import { getUrlSearch, checkUrl, getFocusPath, convertPathToUrl } from './../../src/utils/navigation';

const projectId = '123a-sdf123';
const skillId = '98765.4321';
Expand All @@ -27,46 +19,6 @@ describe('getFocusPath', () => {
});
});

describe('Breadcrumb Util', () => {
it('return focus path', () => {
const breadcrumb = [
{ dialogId: `1`, selected: `1`, focused: `1` },
{ dialogId: `2`, selected: `2`, focused: `2` },
{ dialogId: `3`, selected: `3`, focused: `3` },
];
const result1 = clearBreadcrumb(breadcrumb);
expect(result1).toEqual([]);
const result2 = clearBreadcrumb(breadcrumb, 0);
expect(result2).toEqual([]);
const result3 = clearBreadcrumb(breadcrumb, 1);
expect(result3.length).toEqual(1);
expect(result3[0].dialogId).toEqual('1');
const result4 = clearBreadcrumb(breadcrumb, 4);
expect(result4.length).toEqual(3);
});

it('update breadcrumb', () => {
const result1 = updateBreadcrumb([], BreadcrumbUpdateType.Selected);
expect(result1).toEqual([]);
let breadcrumb = [
{ dialogId: `1`, selected: `1`, focused: `1` },
{ dialogId: `2`, selected: `2`, focused: `2` },
{ dialogId: `3`, selected: `3`, focused: `3` },
];
const result2 = updateBreadcrumb(breadcrumb, BreadcrumbUpdateType.Selected);
expect(result2.length).toEqual(1);
expect(result2[0].dialogId).toEqual('1');
breadcrumb = [
{ dialogId: `1`, selected: `1`, focused: `` },
{ dialogId: `2`, selected: `2`, focused: `` },
{ dialogId: `3`, selected: `3`, focused: `3` },
];
const result3 = updateBreadcrumb(breadcrumb, BreadcrumbUpdateType.Focused);
expect(result3.length).toEqual(2);
expect(result3[1].dialogId).toEqual('2');
});
});

describe('composer url util', () => {
it('create url', () => {
const result1 = getUrlSearch('triggers[0]', 'triggers[0].actions[0]');
Expand Down
109 changes: 58 additions & 51 deletions Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export type TreeLink = {
skillId?: string;
dialogId?: string;
trigger?: number;
parentLink?: TreeLink;
};

export type TreeMenuItem = {
Expand Down Expand Up @@ -274,7 +275,7 @@ export const ProjectTree: React.FC<Props> = ({
.map((diag) => diag.message)
.join(',');

const link: TreeLink = {
const dialogLink: TreeLink = {
dialogId: dialog.id,
displayName: dialog.displayName,
isRoot: dialog.isRoot,
Expand All @@ -287,53 +288,56 @@ export const ProjectTree: React.FC<Props> = ({
const isFormDialog = dialogIsFormDialog(dialog);
const showEditSchema = formDialogSchemaExists(skillId, dialog);

return (
<span
key={dialog.id}
ref={dialog.isRoot ? addMainDialogRef : null}
css={css`
margin-top: -6px;
width: 100%;
label: dialog-header;
`}
role="grid"
>
<TreeItem
showProps
forceIndent={showTriggers ? 0 : SUMMARY_ARROW_SPACE}
icon={isFormDialog ? icons.FORM_DIALOG : icons.DIALOG}
isActive={doesLinkMatch(link, selectedLink)}
link={link}
menu={[
...(!dialog.isRoot
? [
{
label: formatMessage('Remove this dialog'),
icon: 'Delete',
onClick: (link) => {
onDeleteDialog(link.dialogId ?? '');
return {
summaryElement: (
<span
key={dialog.id}
ref={dialog.isRoot ? addMainDialogRef : null}
css={css`
margin-top: -6px;
width: 100%;
label: dialog-header;
`}
role="grid"
>
<TreeItem
showProps
forceIndent={showTriggers ? 0 : SUMMARY_ARROW_SPACE}
icon={isFormDialog ? icons.FORM_DIALOG : icons.DIALOG}
isActive={doesLinkMatch(dialogLink, selectedLink)}
link={dialogLink}
menu={[
...(!dialog.isRoot
? [
{
label: formatMessage('Remove this dialog'),
icon: 'Delete',
onClick: (link) => {
onDeleteDialog(link.dialogId ?? '');
},
},
},
]
: []),
...(showEditSchema
? [
{
label: formatMessage('Edit schema'),
icon: 'Edit',
onClick: (link) =>
navigateToFormDialogSchema({ projectId: link.skillId, schemaId: link.dialogName }),
},
]
: []),
]}
onSelect={handleOnSelect}
/>
</span>
);
]
: []),
...(showEditSchema
? [
{
label: formatMessage('Edit schema'),
icon: 'Edit',
onClick: (link) =>
navigateToFormDialogSchema({ projectId: link.skillId, schemaId: link.dialogName }),
},
]
: []),
]}
onSelect={handleOnSelect}
/>
</span>
),
dialogLink,
};
};

const renderTrigger = (item: any, dialog: DialogInfo, projectId: string): React.ReactNode => {
const renderTrigger = (item: any, dialog: DialogInfo, projectId: string, dialogLink?: TreeLink): React.ReactNode => {
const link: TreeLink = {
projectId: rootProjectId,
skillId: projectId === rootProjectId ? undefined : projectId,
Expand All @@ -343,6 +347,7 @@ export const ProjectTree: React.FC<Props> = ({
warningContent: item.warningContent,
errorContent: item.errorContent,
isRoot: false,
parentLink: dialogLink,
};

return (
Expand Down Expand Up @@ -377,7 +382,7 @@ export const ProjectTree: React.FC<Props> = ({
return scope.toLowerCase().includes(filter.toLowerCase());
};

const renderTriggerList = (triggers: ITrigger[], dialog: DialogInfo, projectId: string) => {
const renderTriggerList = (triggers: ITrigger[], dialog: DialogInfo, projectId: string, dialogLink?: TreeLink) => {
return triggers
.filter((tr) => filterMatch(dialog.displayName) || filterMatch(getTriggerName(tr)))
.map((tr) => {
Expand All @@ -389,7 +394,8 @@ export const ProjectTree: React.FC<Props> = ({
return renderTrigger(
{ ...tr, index, displayName: getTriggerName(tr), warningContent, errorContent },
dialog,
projectId
projectId,
dialogLink
);
});
};
Expand Down Expand Up @@ -451,10 +457,10 @@ export const ProjectTree: React.FC<Props> = ({
});
};

const renderDialogTriggers = (dialog: DialogInfo, projectId: string, startDepth: number) => {
const renderDialogTriggers = (dialog: DialogInfo, projectId: string, startDepth: number, dialogLink?: TreeLink) => {
return dialogIsFormDialog(dialog)
? renderDialogTriggersByProperty(dialog, projectId, startDepth)
: renderTriggerList(dialog.triggers, dialog, projectId);
: renderTriggerList(dialog.triggers, dialog, projectId, dialogLink);
};

const createDetailsTree = (bot: BotInProject, startDepth: number) => {
Expand All @@ -471,14 +477,15 @@ export const ProjectTree: React.FC<Props> = ({

if (showTriggers) {
return filteredDialogs.map((dialog: DialogInfo) => {
const { summaryElement, dialogLink } = renderDialogHeader(projectId, dialog);
return (
<ExpandableNode
key={dialog.id}
depth={startDepth}
detailsRef={dialog.isRoot ? addMainDialogRef : undefined}
summary={renderDialogHeader(projectId, dialog)}
summary={summaryElement}
>
<div>{renderDialogTriggers(dialog, projectId, startDepth + 1)}</div>
<div>{renderDialogTriggers(dialog, projectId, startDepth + 1, dialogLink)}</div>
</ExpandableNode>
);
});
Expand Down
Loading