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

fix(Designer): Array editor UX update #6244

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions Localize/lang/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2814,6 +2814,7 @@
"_zUWAsJ.comment": "Label for description of custom isInt Function",
"_zUgja+.comment": "Label for button to clear the editor",
"_zViEGr.comment": "Time zone value ",
"_zWpl5p.comment": "Tooltip for button to remove array item. Do not remove the double single quotes around the display name, as it is needed to wrap the placeholder text.",
"_zb3lE6.comment": "Chatbot message telling user to set up action in order to save the workflow",
"_zcZpHT.comment": "Label for description of custom parseDateTime Function",
"_zec5Ay.comment": "Chatbot stop generating flow button alt text",
Expand Down Expand Up @@ -3559,6 +3560,7 @@
"zUWAsJ": "Returns a boolean that indicates whether a string is an integer",
"zUgja+": "Clear custom value",
"zViEGr": "(UTC+12:00) Petropavlovsk-Kamchatsky - Old",
"zWpl5p": "Remove parameter ''{itemKey}'' and its value",
"zb3lE6": "To save this workflow, finish setting up this action:",
"zcZpHT": "Converts a string, with optionally a locale and a format to a date",
"zec5Ay": "Stop",
Expand Down
66 changes: 28 additions & 38 deletions libs/designer-ui/src/lib/arrayeditor/arrayeditor.less
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
@import (reference) '../variables.less';

@command-icon-width: 16px;
@padding: 5px;

.msla-array-editor-container {
border: 1px dashed @defaultBorderColor;
border: 1px solid @defaultBorderColor;
border-radius: 4px;
display: flex;

> .msla-array-container {
padding: 10px 5px;
}

.msla-array-commands {
vertical-align: top;
display: inline-block;
Expand All @@ -15,9 +19,12 @@

.msla-array-container {
flex: 1 1 100%;
display: flex;
flex-direction: column;
gap: 8px;

&.msla-array-editor-collapsed {
padding: 10px 0px 10px @padding;
padding: 10px;

.msla-input-parameter-label {
align-self: center;
Expand All @@ -40,6 +47,7 @@

.editor-input {
outline: 1px solid @panel-mode-panel-border-color;
border-radius: 2px;
resize: none;
font-size: 15px;
tab-size: 1;
Expand Down Expand Up @@ -80,33 +88,35 @@
}

.msla-array-item-container {
margin: 10px 0;
padding: 0 @padding;

.msla-array-item {
margin-left: 6px;
&.complex {
margin: 4px;
padding: 4px 4px 4px 4px;
display: flex;
flex-direction: row;
align-items: top;
gap: 4px;

.complex-input-container {
flex-grow: 1;
border: 1px dashed @defaultBorderColor;
}
&.isNested {
border: 1px dotted @defaultBorderColor;
border-radius: 4px;
padding: 2px 8px 8px;
display: flex;
flex-direction: column;
gap: 2px;
}

.msla-array-item-header {
display: flex;
justify-content: space-between;
padding-bottom: 4px;
.msla-array-index {
margin: 4px;
}

.msla-array-editor-container-expanded {
width: 100%;
border-radius: 2px;
padding-bottom: 5px;
position: relative;

.editor-input {
outline: 1px solid @panel-mode-panel-border-color;
border-radius: 2px;
resize: none;
font-size: 15px;
tab-size: 1;
Expand Down Expand Up @@ -150,30 +160,10 @@
margin-bottom: @parameter-interval-margin;
}
}

.msla-array-item-commands {
display: inline-block;
width: 30px;
vertical-align: top;

.msla-array-item-contextbutton {
i[data-icon-name='ChevronDown'] {
display: none;
}
&:hover {
background-color: transparent;
}
}
}
}

.msla-array-toolbar {
display: flex;
margin: @padding;

.msla-array-add-item-button {
height: @parameter-inputbox-height;
font-size: @card-label-font-size;
}
margin: 0px 2px;
}
}
4 changes: 1 addition & 3 deletions libs/designer-ui/src/lib/arrayeditor/collapsedarray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ export const CollapsedArray = ({
const { text, isRequiredField } = labelProps as LabelProps;
return (
<div className="msla-input-parameter-label">
<div className="msla-array-editor-label">
<Label text={text} isRequiredField={isRequiredField} requiredMarkerSide={RequiredMarkerSide.LEFT} />
</div>
<Label text={text} isRequiredField={isRequiredField} requiredMarkerSide={RequiredMarkerSide.LEFT} />
</div>
);
};
Expand Down
187 changes: 89 additions & 98 deletions libs/designer-ui/src/lib/arrayeditor/expandedcomplexarray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import type { ComboboxItem, ComplexArrayItems, DropdownItem, TokenPickerButtonEd
import { Combobox, DropdownEditor, StringEditor } from '..';
import constants from '../constants';
import type { ChangeState, GetTokenPickerHandler, loadParameterValueFromStringHandler } from '../editor/base';
import { ItemMenuButton } from './expandedsimplearray';
import { getBooleanDropdownOptions, getComoboxEnumOptions, hideComplexArray } from './util/util';
import type { ItemSchemaItemProps } from './util/util';
import type { IIconProps } from '@fluentui/react';
import { css, DefaultButton } from '@fluentui/react';
import { css } from '@fluentui/react';
import { Label } from '../label';
import { guid } from '@microsoft/logic-apps-shared';
import { useIntl } from 'react-intl';
import { Button, Badge } from '@fluentui/react-components';
import { RemoveItemButton } from './removeitembutton';

const addItemButtonIconProps: IIconProps = {
iconName: 'Add',
};
import { bundleIcon, AddSquareFilled, AddSquareRegular } from '@fluentui/react-icons';

const AddIcon = bundleIcon(AddSquareFilled, AddSquareRegular);

export interface ExpandedComplexArrayProps {
dimensionalSchema: ItemSchemaItemProps[];
Expand All @@ -35,7 +35,6 @@ export const ExpandedComplexArray = ({
allItems,
canDeleteLastItem,
setItems,
isNested = false,
options,
...props
}: ExpandedComplexArrayProps): JSX.Element => {
Expand Down Expand Up @@ -89,105 +88,94 @@ export const ExpandedComplexArray = ({
setItems(newItems);
};

const renderLabel = (index: number, schemaItem: ItemSchemaItemProps, isRequired?: boolean): JSX.Element => {
const { title } = schemaItem;
return (
<div className="msla-array-editor-label">
<Label isRequiredField={isRequired ?? false} text={`${title} - ${index + 1}`} />
</div>
);
};

return (
<div className="msla-array-container msla-array-item-container">
{allItems.map((item, index) => {
return (
<div key={item.key + index} className={css('msla-array-item', 'complex', isNested && 'isNested')}>
{dimensionalSchema.map((schemaItem: ItemSchemaItemProps, i) => {
const complexItem = item.items.find((complexItem) => complexItem.key === schemaItem.key);
const comboboxOptions = getComoboxEnumOptions(options, schemaItem.enum);
const dropdownOptions: DropdownItem[] | undefined =
schemaItem.type === constants.SWAGGER.TYPE.BOOLEAN ? getBooleanDropdownOptions() : undefined;
return (
<div key={schemaItem.key + i}>
{schemaItem.type === constants.SWAGGER.TYPE.ARRAY && schemaItem.items && !hideComplexArray(schemaItem.items) ? (
<div>
<Label text={schemaItem.title} />
<ExpandedComplexArray
{...props}
dimensionalSchema={schemaItem.items}
allItems={complexItem?.arrayItems ?? ([] as ComplexArrayItems[])}
canDeleteLastItem={canDeleteLastItem}
setItems={(newItems) => {
handleNestedArraySaved(newItems, index, schemaItem);
}}
isNested={true}
itemKey={guid()}
/>
</div>
) : (
<>
{
// hide empty readonly editors
schemaItem?.readOnly && (!complexItem || complexItem.value.length === 0) ? null : (
<>
<div className="msla-array-item-header">
{renderLabel(index, schemaItem, schemaItem?.isRequired)}
{i === 0 ? (
<div className="msla-array-item-commands">
<ItemMenuButton
disabled={!!props.readonly}
itemKey={index}
visible={canDeleteLastItem || allItems.length > 1}
onDeleteItem={(index) => deleteItem(index)}
/>
</div>
) : null}
</div>
{comboboxOptions ? (
<Combobox
{...props}
valueType={schemaItem?.type}
options={comboboxOptions}
placeholder={schemaItem.description}
initialValue={complexItem?.value ?? []}
onChange={(newState) => handleArrayElementSaved(newState, index, schemaItem)}
/>
) : dropdownOptions ? (
<DropdownEditor
{...props}
options={dropdownOptions}
initialValue={complexItem?.value ?? []}
onChange={(newState) => handleArrayElementSaved(newState, index, schemaItem)}
/>
) : (
<StringEditor
{...props}
readonly={schemaItem?.readOnly}
valueType={schemaItem?.type}
className="msla-array-editor-container-expanded"
initialValue={complexItem?.value ?? []}
editorBlur={(newState) => handleArrayElementSaved(newState, index, schemaItem)}
placeholder={schemaItem?.description}
/>
)}
</>
)
}
</>
)}
</div>
);
})}
<div key={item.key + index} className={css('msla-array-item', 'complex')}>
<Badge className="msla-array-index" shape="rounded" appearance="tint">
{index + 1}
</Badge>
<div className={'complex-input-container'}>
{dimensionalSchema.map((schemaItem: ItemSchemaItemProps, i) => {
const complexItem = item.items.find((complexItem) => complexItem.key === schemaItem.key);
const comboboxOptions = getComoboxEnumOptions(options, schemaItem.enum);
const dropdownOptions: DropdownItem[] | undefined =
schemaItem.type === constants.SWAGGER.TYPE.BOOLEAN ? getBooleanDropdownOptions() : undefined;
return (
<div key={schemaItem.key + i}>
{schemaItem.type === constants.SWAGGER.TYPE.ARRAY && schemaItem.items && !hideComplexArray(schemaItem.items) ? (
<div>
<Label text={schemaItem.title} />
<ExpandedComplexArray
{...props}
dimensionalSchema={schemaItem.items}
allItems={complexItem?.arrayItems ?? ([] as ComplexArrayItems[])}
canDeleteLastItem={canDeleteLastItem}
setItems={(newItems) => {
handleNestedArraySaved(newItems, index, schemaItem);
}}
itemKey={guid()}
/>
</div>
) : (
<>
{
// hide empty readonly editors
schemaItem?.readOnly && (!complexItem || complexItem.value.length === 0) ? null : (
<>
<Label isRequiredField={schemaItem?.isRequired ?? false} text={schemaItem.title} />
{comboboxOptions ? (
<Combobox
{...props}
valueType={schemaItem?.type}
options={comboboxOptions}
placeholder={schemaItem.description}
initialValue={complexItem?.value ?? []}
onChange={(newState) => handleArrayElementSaved(newState, index, schemaItem)}
/>
) : dropdownOptions ? (
<DropdownEditor
{...props}
options={dropdownOptions}
initialValue={complexItem?.value ?? []}
onChange={(newState) => handleArrayElementSaved(newState, index, schemaItem)}
/>
) : (
<StringEditor
{...props}
readonly={schemaItem?.readOnly}
valueType={schemaItem?.type}
className="msla-array-editor-container-expanded"
initialValue={complexItem?.value ?? []}
editorBlur={(newState) => handleArrayElementSaved(newState, index, schemaItem)}
placeholder={schemaItem?.description}
/>
)}
</>
)
}
</>
)}
</div>
);
})}
</div>
<RemoveItemButton
disabled={!!props.readonly}
itemKey={index}
visible={canDeleteLastItem || allItems.length > 1}
onClick={(index) => deleteItem(index)}
/>
</div>
);
})}
<div className="msla-array-toolbar">
<DefaultButton
<Button
disabled={props.readonly}
className="msla-array-add-item-button"
iconProps={addItemButtonIconProps}
text={addItemButtonLabel}
icon={<AddIcon />}
size={'small'}
appearance="subtle"
onClick={() => {
setItems([
...allItems,
Expand All @@ -199,7 +187,10 @@ export const ExpandedComplexArray = ({
},
]);
}}
/>
style={{ paddingLeft: '1px', gap: '2px' }}
>
{addItemButtonLabel}
</Button>
</div>
</div>
);
Expand Down
Loading
Loading