Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5e40fce
swap out details/summary for ul/li
beyackle Apr 14, 2021
020f14e
fix placement of items
beyackle Apr 14, 2021
a342ee0
Merge branch 'main' into beyackle/electronListStyle
beyackle Apr 15, 2021
8580328
Update ExpandableNode.tsx
beyackle Apr 15, 2021
f203c21
Merge branch 'main' into beyackle/electronListStyle
beyackle Apr 15, 2021
9b16759
fix layout issues and clicking behavior
beyackle Apr 15, 2021
f753120
fix variables
beyackle Apr 15, 2021
5955b70
more fixes
beyackle Apr 15, 2021
5bb8704
Update ExpandableNode.tsx
beyackle Apr 15, 2021
0c51ca5
Merge branch 'main' into beyackle/electronListStyle
beyackle Apr 16, 2021
3fedc48
Update ProjectTree.tsx
beyackle Apr 16, 2021
a167b75
Update ProjectTree.tsx
beyackle Apr 16, 2021
260d5b1
remove stray comment
beyackle Apr 16, 2021
cf5a484
Update expandableNode.test.tsx
beyackle Apr 16, 2021
3820f62
Merge branch 'main' into beyackle/electronListStyle
a-b-r-o-w-n Apr 19, 2021
04f194f
add new timeout to tests
beyackle Apr 19, 2021
1a64edc
Update Breadcrumb.spec.ts
beyackle Apr 19, 2021
a468376
Merge branch 'main' into beyackle/electronListStyle
beyackle Apr 19, 2021
b43b5e0
Merge branch 'main' into beyackle/electronListStyle
beyackle Apr 19, 2021
b849dec
post-merge fixes
beyackle Apr 19, 2021
d2832ee
Merge branch 'beyackle/electronListStyle' of https://github.com/micro…
beyackle Apr 19, 2021
b0d127a
Merge branch 'main' into beyackle/electronListStyle
beyackle Apr 19, 2021
479a23f
scope breadcrumb tests to inside breadcrumb
beyackle Apr 19, 2021
a81e896
Merge branch 'main' into beyackle/electronListStyle
beyackle Apr 19, 2021
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
9 changes: 5 additions & 4 deletions Composer/cypress/integration/Breadcrumb.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ context('breadcrumb', () => {
function hasBreadcrumbItems(cy: Cypress.cy, items: (string | RegExp)[]) {
cy.get('[data-testid="Breadcrumb"]')
.last()
.get('li')
.should(($li) => {
items.forEach((item, idx) => {
expect($li.eq(idx)).to.contain(item);
.within(() => {
cy.get('li').should(($li) => {
items.forEach((item, idx) => {
expect($li.eq(idx)).to.contain(item);
});
});
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ describe('<ExpandableNode />', () => {

it('closes and opens on click', async () => {
if (component == null) fail();

const triangle = await component.findByTestId('summaryTag');
let details = await component.findByTestId('dialog');
expect(details.attributes.getNamedItem('open')).not.toBeNull();
expect(details.childNodes.length).toBe(2); // 1 for the summary itself, 1 for the details

fireEvent.click(triangle);
details = await component.findByTestId('dialog');
expect(details.attributes.getNamedItem('open')).toBeNull();
expect(details.childNodes.length).toBe(1); // when the node is closed, the details don't render at all

fireEvent.click(triangle);
details = await component.findByTestId('dialog');
expect(details.attributes.getNamedItem('open')).not.toBeNull();
expect(details.childNodes.length).toBe(2);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { jsx, css } from '@emotion/core';
import { useState, MouseEvent, KeyboardEvent } from 'react';
import { NeutralColors } from '@uifabric/fluent-theme';

import { INDENT_PER_LEVEL } from './constants';

type Props = {
children: React.ReactNode;
summary: React.ReactNode;
Expand All @@ -18,29 +16,29 @@ type Props = {
isActive?: boolean;
};

const summaryStyle = (depth: number, isActive: boolean, isOpen: boolean) => css`
label: summary;
padding-left: ${depth * INDENT_PER_LEVEL + 12}px;
padding-top: 6px;
display: list-item;
const listItemStyle = (isActive: boolean, isOpen: boolean) => css`
label: listItem;
:hover {
background: ${isActive ? NeutralColors.gray40 : NeutralColors.gray20};
}
background: ${isActive ? NeutralColors.gray30 : NeutralColors.white};
${isOpen
? `list-style-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='10' width='10' viewBox='0 0 16 16'%3E%3Cpath style='fill:black;' d='M 0 8 H 16 L 8 16 L 0 8'/%3E%3C/svg%3E");`
: `list-style-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='10' width='10' viewBox='0 0 16 16'%3E%3Cpath style='fill:black;' d='M 8 0 V 16 L 16 8 L 8 0'/%3E%3C/svg%3E");`}
? `list-style-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='16' width='16' viewBox='0 0 24 16'%3E%3Cpath style='fill:black%3B' d='M 8 8 h 16 l -8 8 l -8 -8'/%3E%3C/svg%3E");`
: `list-style-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='16' width='16' viewBox='0 0 24 16'%3E%3Cpath style='fill:black%3B' d='M 16 0 v 16 l 8 -8 l -8 -8'/%3E%3C/svg%3E");`}
`;

const nodeStyle = css`
margin-top: 2px;
const listStyle = css`
label: list;
margin-top: 0;
margin-left: 16px;
padding-inline-start: 6px;
margin-block-end: 0px;
`;

export const ExpandableNode = ({
children,
summary,
detailsRef,
depth = 0,
onToggle,
defaultState = true,
isActive = false,
Expand All @@ -53,8 +51,10 @@ export const ExpandableNode = ({
}

function handleClick(ev: MouseEvent) {
if ((ev.target as Element)?.tagName.toLowerCase() === 'summary') {
const target = ev.target as Element;
if (target.tagName.toLowerCase() === 'li') {
setExpandedWithCallback(!isExpanded);
ev.stopPropagation();
}
ev.preventDefault();
}
Expand All @@ -64,25 +64,20 @@ export const ExpandableNode = ({
}

return (
<details
<ul
ref={detailsRef}
aria-expanded={isExpanded}
css={nodeStyle}
css={listStyle}
data-testid="dialog"
open={isExpanded}
role="tree"
onClick={handleClick}
onKeyDown={handleKey}
>
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/no-noninteractive-tabindex */}
<summary
css={summaryStyle(depth, isActive, isExpanded)}
data-testid={'summaryTag'}
tabIndex={0}
onClick={handleClick}
onKeyUp={handleKey}
>
<li css={listItemStyle(isActive, isExpanded)} data-testid={'summaryTag'}>
{summary}
</summary>
<div role="group">{children}</div>
</details>
</li>
{isExpanded && <div role="group">{children}</div>}
</ul>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import { TreeItem } from './treeItem';
import { ProjectTreeOptions, TreeLink } from './types';

const headerCSS = (label: string) => css`
margin-top: -6px;
width: 100%;
label: ${label};
`;

Expand Down
32 changes: 10 additions & 22 deletions Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { getBaseName } from '../../utils/fileUtil';

import { TreeItem } from './treeItem';
import { ExpandableNode } from './ExpandableNode';
import { INDENT_PER_LEVEL, LEVEL_PADDING, TREE_PADDING } from './constants';
import { INDENT_PER_LEVEL, TREE_PADDING } from './constants';
import { ProjectTreeHeader, ProjectTreeHeaderMenuItem } from './ProjectTreeHeader';
import { isChildTriggerLinkSelected, doesLinkMatch } from './helpers';
import { ProjectHeader } from './ProjectHeader';
Expand Down Expand Up @@ -61,7 +61,6 @@ const tree = css`
`;

export const headerCSS = (label: string, isActive?: boolean) => css`
margin-top: -6px;
width: 100%;
label: ${label};
:hover {
Expand Down Expand Up @@ -281,7 +280,6 @@ export const ProjectTree: React.FC<Props> = ({
link={dialogLink}
menu={options.showMenu ? menu : options.showQnAMenu ? [QnAMenuItem] : []}
menuOpenCallback={setMenuOpen}
padLeft={depth * LEVEL_PADDING}
showErrors={false}
textWidth={leftSplitWidth - TREE_PADDING}
onSelect={handleOnSelect}
Expand All @@ -292,7 +290,7 @@ export const ProjectTree: React.FC<Props> = ({
};
};

const renderCommonDialogHeader = (skillId: string, depth: number) => {
const renderCommonDialogHeader = (skillId: string) => {
const dialogLink: TreeLink = {
dialogId: 'common',
displayName: formatMessage('Common'),
Expand All @@ -304,15 +302,14 @@ export const ProjectTree: React.FC<Props> = ({
};

return (
<span key={'common'} ref={null} css={headerCSS('dialog-header')} data-testid={`DialogHeader-Common`}>
<span key={'common'} ref={null} css={headerCSS('common-dialog-header')} data-testid={`DialogHeader-Common`}>
<TreeItem
hasChildren
isActive={doesLinkMatch(dialogLink, selectedLink)}
isMenuOpen={isMenuOpen}
itemType={'dialog'}
link={dialogLink}
menuOpenCallback={setMenuOpen}
padLeft={depth * LEVEL_PADDING}
showErrors={false}
textWidth={leftSplitWidth - TREE_PADDING}
onSelect={handleOnSelect}
Expand All @@ -330,8 +327,7 @@ export const ProjectTree: React.FC<Props> = ({
},
dialog: DialogInfo,
projectId: string,
dialogLink: TreeLink,
depth: number
dialogLink: TreeLink
): React.ReactNode => {
const link: TreeLink = {
projectId: rootProjectId,
Expand All @@ -349,12 +345,11 @@ export const ProjectTree: React.FC<Props> = ({
<TreeItem
key={`${item.id}_${item.index}`}
dialogName={dialog.displayName}
extraSpace={INDENT_PER_LEVEL}
extraSpace={16}
isActive={doesLinkMatch(link, selectedLink)}
isMenuOpen={isMenuOpen}
itemType={'trigger'}
link={link}
marginLeft={depth * INDENT_PER_LEVEL}
menu={
options.showDelete
? [
Expand Down Expand Up @@ -387,13 +382,7 @@ export const ProjectTree: React.FC<Props> = ({
return scope.toLowerCase().includes(filter.toLowerCase());
};

const renderTriggerList = (
triggers: ITrigger[],
dialog: DialogInfo,
projectId: string,
dialogLink: TreeLink,
depth: number
) => {
const renderTriggerList = (triggers: ITrigger[], dialog: DialogInfo, projectId: string, dialogLink: TreeLink) => {
return triggers
.filter((tr) => filterMatch(dialog.displayName) || filterMatch(getTriggerName(tr)))
.map((tr) => {
Expand All @@ -406,8 +395,7 @@ export const ProjectTree: React.FC<Props> = ({
{ ...tr, index, displayName: getTriggerName(tr), warningContent, errorContent },
dialog,
projectId,
dialogLink,
depth
dialogLink
);
});
};
Expand Down Expand Up @@ -464,7 +452,7 @@ export const ProjectTree: React.FC<Props> = ({
summary={renderTriggerGroupHeader(groupDisplayName, dialog, projectId)}
onToggle={(newState) => setPageElement(key, newState)}
>
<div role="group">{renderTriggerList(triggers, dialog, projectId, link, 1)}</div>
<div role="group">{renderTriggerList(triggers, dialog, projectId, link)}</div>
</ExpandableNode>
);
};
Expand All @@ -485,7 +473,7 @@ export const ProjectTree: React.FC<Props> = ({
const renderDialogTriggers = (dialog: DialogInfo, projectId: string, startDepth: number, dialogLink: TreeLink) => {
return dialogIsFormDialog(dialog)
? renderDialogTriggersByProperty(dialog, projectId, startDepth + 1)
: renderTriggerList(dialog.triggers, dialog, projectId, dialogLink, 1);
: renderTriggerList(dialog.triggers, dialog, projectId, dialogLink);
};

// flatten lg imports url is same to dialog, to match correct link need render it as dialog
Expand Down Expand Up @@ -634,7 +622,7 @@ export const ProjectTree: React.FC<Props> = ({
// eventually we will filter on topic trigger phrases
const filteredTopics =
filter == null || filter.length === 0 ? topics : topics.filter((topic) => filterMatch(topic.displayName));
const commonLink = options.showCommonLinks ? [renderCommonDialogHeader(projectId, 1)] : [];
const commonLink = options.showCommonLinks ? [renderCommonDialogHeader(projectId)] : [];

const importedLgLinks = options.showLgImports
? lgImportsList.map((file) => renderLgImportAsDialog(file, projectId))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import get from 'lodash/get';

import { ExpandableNode } from './ExpandableNode';
import { TreeItem } from './treeItem';
import { LEVEL_PADDING, INDENT_PER_LEVEL } from './constants';
import { INDENT_PER_LEVEL } from './constants';
import { headerCSS } from './ProjectTree';

type TopicsListProps = {
Expand Down Expand Up @@ -69,8 +69,10 @@ export const TopicsList: React.FC<TopicsListProps> = ({ topics, onToggle, textWi
link={{
displayName: formatMessage('Power Virtual Agents Topics ({count})', { count: topics.length }),
projectId,
isRoot: false,
isRemote: false,
diagnostics: [],
}}
padLeft={0 * LEVEL_PADDING}
showErrors={false}
textWidth={textWidth}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export const SUMMARY_ARROW_SPACE = 28; // the rough pixel size of the dropdown arrow to the left of a Details/Summary element
export const INDENT_PER_LEVEL = 16;
export const ACTION_ICON_WIDTH = 28;
export const THREE_DOTS_ICON_WIDTH = 28;
Expand Down
Loading