Skip to content

Commit

Permalink
Merge branch 'main' into luhan/allowClaimsValidator
Browse files Browse the repository at this point in the history
  • Loading branch information
boydc2014 committed Nov 9, 2020
2 parents 62f66a4 + 952a841 commit d273182
Show file tree
Hide file tree
Showing 37 changed files with 4,029 additions and 3,337 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
import formatMessage from 'format-message';
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { Stack, StackItem } from 'office-ui-fabric-react/lib/Stack';
import React, { Fragment, useEffect, useCallback } from 'react';
import React, { Fragment, useEffect, useCallback, useMemo } from 'react';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { RouteComponentProps } from '@reach/router';
import querystring from 'query-string';
Expand Down Expand Up @@ -212,6 +212,18 @@ const DefineConversation: React.FC<DefineConversationProps> = (props) => {
updateField('location', location);
}, [focusedStorageFolder]);

const locationSelectContent = useMemo(() => {
return (
<LocationSelectContent
createFolder={createFolder}
focusedStorageFolder={focusedStorageFolder}
operationMode={{ read: true, write: true }}
updateFolder={updateFolder}
onCurrentPathUpdate={onCurrentPathUpdateWrap}
/>
);
}, [focusedStorageFolder]);

return (
<Fragment>
<DialogWrapper
Expand Down Expand Up @@ -246,14 +258,7 @@ const DefineConversation: React.FC<DefineConversationProps> = (props) => {
/>
</StackItem>
</Stack>
<LocationSelectContent
createFolder={createFolder}
focusedStorageFolder={focusedStorageFolder}
operationMode={{ read: true, write: true }}
updateFolder={updateFolder}
onCurrentPathUpdate={onCurrentPathUpdateWrap}
/>

{locationSelectContent}
<DialogFooter>
<DefaultButton text={formatMessage('Cancel')} onClick={onDismiss} />
<PrimaryButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import { jsx, css } from '@emotion/core';
import { useState, MouseEvent, KeyboardEvent } from 'react';

import { INDENT_PER_LEVEL } from './constants';

type Props = {
children: React.ReactNode;
summary: React.ReactNode;
depth?: number;
detailsRef?: (el: HTMLElement | null) => void;
onToggle?: (newState: boolean) => void;
defaultState?: boolean;
};

const summaryStyle = css`
Expand All @@ -20,33 +24,40 @@ const summaryStyle = css`
`;

const nodeStyle = (depth: number) => css`
margin-left: ${depth * 16}px;
margin-left: ${depth * INDENT_PER_LEVEL}px;
`;

const TRIANGLE_SCALE = 0.6;

const detailsStyle = css`
&:not([open]) > summary::-webkit-details-marker {
transform: scaleX(${TRIANGLE_SCALE});
min-width: 10px;
}
&[open] > summary::-webkit-details-marker {
transform: scaleY(${TRIANGLE_SCALE});
min-width: 10px;
}
`;

export const ExpandableNode = ({ children, summary, detailsRef, depth = 0 }: Props) => {
const [isExpanded, setExpanded] = useState(true);
export const ExpandableNode = ({ children, summary, detailsRef, depth = 0, onToggle, defaultState = true }: Props) => {
const [isExpanded, setExpanded] = useState(defaultState);

function setExpandedWithCallback(newState: boolean) {
setExpanded(newState);
onToggle?.(newState);
}

function handleClick(ev: MouseEvent) {
if ((ev.target as Element)?.tagName.toLowerCase() === 'summary') {
setExpanded(!isExpanded);
setExpandedWithCallback(!isExpanded);
}
ev.preventDefault();
}

function handleKey(ev: KeyboardEvent) {
if (ev.key === 'Enter' || ev.key === 'Space') setExpanded(!isExpanded);
if (ev.key === 'Enter' || ev.key === 'Space') setExpandedWithCallback(!isExpanded);
}

return (
Expand Down
95 changes: 70 additions & 25 deletions Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.

/** @jsx jsx */
import React, { useCallback, useState, useEffect } from 'react';
import React, { useCallback, useState, useEffect, useRef } from 'react';
import { jsx, css } from '@emotion/core';
import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox';
import { FocusZone, FocusZoneDirection } from 'office-ui-fabric-react/lib/FocusZone';
Expand All @@ -20,6 +20,7 @@ import {
rootBotProjectIdSelector,
botProjectSpaceSelector,
jsonSchemaFilesByProjectIdSelector,
pageElementState,
} from '../../recoilModel';
import { getFriendlyName } from '../../utils/dialogUtil';
import { triggerNotSupported } from '../../utils/dialogValidator';
Expand All @@ -28,6 +29,7 @@ import { LoadingSpinner } from '../LoadingSpinner';

import { TreeItem } from './treeItem';
import { ExpandableNode } from './ExpandableNode';
import { INDENT_PER_LEVEL } from './constants';

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

Expand Down Expand Up @@ -65,8 +67,6 @@ const tree = css`
label: tree;
`;

const SUMMARY_ARROW_SPACE = 28; // the rough pixel size of the dropdown arrow to the left of a Details/Summary element

// -------------------- Helper functions -------------------- //

const getTriggerIndex = (trigger: ITrigger, dialog: DialogInfo): number => {
Expand Down Expand Up @@ -139,6 +139,8 @@ type Props = {
defaultSelected?: Partial<TreeLink>;
};

const TREE_PADDING = 100; // the horizontal space taken up by stuff in the tree other than text or indentation

export const ProjectTree: React.FC<Props> = ({
onSelectAllLink: onAllSelected = undefined,
showTriggers = true,
Expand All @@ -148,7 +150,16 @@ export const ProjectTree: React.FC<Props> = ({
onSelect,
defaultSelected,
}) => {
const { onboardingAddCoachMarkRef, navigateToFormDialogSchema } = useRecoilValue(dispatcherState);
const { onboardingAddCoachMarkRef, navigateToFormDialogSchema, setPageElementState } = useRecoilValue(
dispatcherState
);
const treeRef = useRef<HTMLDivElement>(null);

const pageElements = useRecoilValue(pageElementState).design;
const leftSplitWidth = pageElements?.leftSplitWidth ?? treeRef?.current?.clientWidth ?? 0;
const getPageElement = (name: string) => pageElements?.[name];
const setPageElement = (name: string, value: any) =>
setPageElementState('design', { ...pageElements, [name]: value });

const [filter, setFilter] = useState('');
const formDialogComposerFeatureEnabled = useFeatureFlag('FORM_DIALOG');
Expand Down Expand Up @@ -254,18 +265,19 @@ export const ProjectTree: React.FC<Props> = ({
>
<TreeItem
showProps
forceIndent={bot.isRemote ? SUMMARY_ARROW_SPACE : 0}
hasChildren={!bot.isRemote}
icon={bot.isRemote ? icons.EXTERNAL_SKILL : icons.BOT}
isActive={doesLinkMatch(link, selectedLink)}
link={link}
menu={[{ label: formatMessage('Create/edit skill manifest'), onClick: () => {} }]}
textWidth={leftSplitWidth - TREE_PADDING}
onSelect={handleOnSelect}
/>
</span>
);
};

const renderDialogHeader = (skillId: string, dialog: DialogInfo) => {
const renderDialogHeader = (skillId: string, dialog: DialogInfo, depth: number) => {
const warningContent = notificationMap[skillId][dialog.id]
?.filter((diag) => diag.severity === DiagnosticSeverity.Warning)
.map((diag) => diag.message)
Expand Down Expand Up @@ -301,8 +313,8 @@ export const ProjectTree: React.FC<Props> = ({
role="grid"
>
<TreeItem
hasChildren
showProps
forceIndent={showTriggers ? 0 : SUMMARY_ARROW_SPACE}
icon={isFormDialog ? icons.FORM_DIALOG : icons.DIALOG}
isActive={doesLinkMatch(dialogLink, selectedLink)}
link={dialogLink}
Expand All @@ -329,6 +341,7 @@ export const ProjectTree: React.FC<Props> = ({
]
: []),
]}
textWidth={leftSplitWidth - TREE_PADDING}
onSelect={handleOnSelect}
/>
</span>
Expand All @@ -337,7 +350,13 @@ export const ProjectTree: React.FC<Props> = ({
};
};

const renderTrigger = (item: any, dialog: DialogInfo, projectId: string, dialogLink?: TreeLink): React.ReactNode => {
const renderTrigger = (
item: any,
dialog: DialogInfo,
projectId: string,
dialogLink: TreeLink,
depth: number
): React.ReactNode => {
const link: TreeLink = {
projectId: rootProjectId,
skillId: projectId === rootProjectId ? undefined : projectId,
Expand All @@ -354,7 +373,7 @@ export const ProjectTree: React.FC<Props> = ({
<TreeItem
key={`${item.id}_${item.index}`}
dialogName={dialog.displayName}
forceIndent={48}
extraSpace={INDENT_PER_LEVEL}
icon={icons.TRIGGER}
isActive={doesLinkMatch(link, selectedLink)}
link={link}
Expand All @@ -367,6 +386,7 @@ export const ProjectTree: React.FC<Props> = ({
},
},
]}
textWidth={leftSplitWidth - TREE_PADDING}
onSelect={handleOnSelect}
/>
);
Expand All @@ -382,7 +402,13 @@ export const ProjectTree: React.FC<Props> = ({
return scope.toLowerCase().includes(filter.toLowerCase());
};

const renderTriggerList = (triggers: ITrigger[], dialog: DialogInfo, projectId: string, dialogLink?: TreeLink) => {
const renderTriggerList = (
triggers: ITrigger[],
dialog: DialogInfo,
projectId: string,
dialogLink: TreeLink,
depth: number
) => {
return triggers
.filter((tr) => filterMatch(dialog.displayName) || filterMatch(getTriggerName(tr)))
.map((tr) => {
Expand All @@ -395,17 +421,18 @@ export const ProjectTree: React.FC<Props> = ({
{ ...tr, index, displayName: getTriggerName(tr), warningContent, errorContent },
dialog,
projectId,
dialogLink
dialogLink,
depth
);
});
};

const renderTriggerGroupHeader = (displayName: string, dialog: DialogInfo, projectId: string) => {
const renderTriggerGroupHeader = (displayName: string, dialog: DialogInfo, projectId: string, depth: number) => {
const link: TreeLink = {
dialogId: dialog.id,
displayName,
isRoot: false,
projectId: projectId,
projectId,
};
return (
<span
Expand All @@ -416,12 +443,12 @@ export const ProjectTree: React.FC<Props> = ({
`}
role="grid"
>
<TreeItem showProps forceIndent={0} isSubItemActive={false} link={link} />
<TreeItem showProps isSubItemActive={false} link={link} textWidth={leftSplitWidth - TREE_PADDING} />
</span>
);
};

// renders a named expandible node with the triggers as items underneath
// renders a named expandable node with the triggers as items underneath
const renderTriggerGroup = (
projectId: string,
dialog: DialogInfo,
Expand All @@ -432,14 +459,21 @@ export const ProjectTree: React.FC<Props> = ({
const groupDisplayName =
groupName === NoGroupingTriggerGroupName ? formatMessage('form-wide operations') : groupName;
const key = `${projectId}.${dialog.id}.group-${groupName}`;
const link: TreeLink = {
dialogId: dialog.id,
displayName: groupName,
isRoot: false,
projectId,
};

return (
<ExpandableNode
key={key}
depth={startDepth}
summary={renderTriggerGroupHeader(groupDisplayName, dialog, projectId)}
summary={renderTriggerGroupHeader(groupDisplayName, dialog, projectId, startDepth + 1)}
onToggle={(newState) => setPageElement(key, newState)}
>
<div>{renderTriggerList(triggers, dialog, projectId)}</div>
<div>{renderTriggerList(triggers, dialog, projectId, link, startDepth + 1)}</div>
</ExpandableNode>
);
};
Expand All @@ -457,10 +491,10 @@ export const ProjectTree: React.FC<Props> = ({
});
};

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

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

if (showTriggers) {
return filteredDialogs.map((dialog: DialogInfo) => {
const { summaryElement, dialogLink } = renderDialogHeader(projectId, dialog);
const { summaryElement, dialogLink } = renderDialogHeader(projectId, dialog, startDepth);
const key = 'dialog-' + dialog.id;
return (
<ExpandableNode
key={dialog.id}
key={key}
defaultState={getPageElement(key)}
depth={startDepth}
detailsRef={dialog.isRoot ? addMainDialogRef : undefined}
summary={summaryElement}
onToggle={(newState) => setPageElement(key, newState)}
>
<div>{renderDialogTriggers(dialog, projectId, startDepth + 1, dialogLink)}</div>
</ExpandableNode>
);
});
} else {
return filteredDialogs.map((dialog: DialogInfo) => renderDialogHeader(projectId, dialog));
return filteredDialogs.map((dialog: DialogInfo) => renderDialogHeader(projectId, dialog, startDepth));
}
};

const createBotSubtree = (bot: BotInProject & { hasWarnings: boolean }) => {
const key = 'bot-' + bot.projectId;
if (showDialogs && !bot.isRemote) {
return (
<ExpandableNode key={bot.projectId} summary={renderBotHeader(bot)}>
<ExpandableNode
key={key}
defaultState={getPageElement(key)}
summary={renderBotHeader(bot)}
onToggle={(newState) => setPageElement(key, newState)}
>
<div>{createDetailsTree(bot, 1)}</div>
</ExpandableNode>
);
Expand All @@ -513,6 +556,7 @@ export const ProjectTree: React.FC<Props> = ({

return (
<div
ref={treeRef}
aria-label={formatMessage('Navigation pane')}
className="ProjectTree"
css={root}
Expand Down Expand Up @@ -548,8 +592,9 @@ export const ProjectTree: React.FC<Props> = ({
<div css={tree}>
{onAllSelected != null ? (
<TreeItem
forceIndent={SUMMARY_ARROW_SPACE}
hasChildren={false}
link={{ displayName: formatMessage('All'), projectId: rootProjectId, isRoot: true }}
textWidth={leftSplitWidth - TREE_PADDING}
onSelect={onAllSelected}
/>
) : null}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// 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;
Loading

0 comments on commit d273182

Please sign in to comment.