-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Templates): Styling for Templates Parameters (#4978)
* moved over from workflowParameterField to TemplatesParameterField * added .less styling * hide parameters tab on no parameters * finisehd css for tempaltesParmeterField * removed parameter description as it is not part of parameters field * added tests for templatesParametersField * fixed display parameter tests * fixed tests in parametersTab and brought back unwanted changes * updated submodule to fix merge conflict
- Loading branch information
1 parent
47b7c07
commit 8cf13cd
Showing
20 changed files
with
360 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
libs/designer-ui/src/lib/templates/__tests__/templatesParameterField.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import type { TemplatesParameterFieldProps } from '../templatesParametersField'; | ||
import { TemplatesParameterField } from '../templatesParametersField'; | ||
import { initializeIcons } from '@fluentui/react'; | ||
import * as React from 'react'; | ||
import { useIntl } from 'react-intl'; | ||
import * as ReactShallowRenderer from 'react-test-renderer/shallow'; | ||
import { describe, beforeEach, afterEach, it, expect } from 'vitest'; | ||
describe('ui/templates/templatesParameterField', () => { | ||
let minimal: TemplatesParameterFieldProps; | ||
let minimalWithError: TemplatesParameterFieldProps; | ||
let renderer: ReactShallowRenderer.ShallowRenderer; | ||
|
||
beforeEach(() => { | ||
minimal = { | ||
definition: { value: 'blue', name: 'test1', type: 'String', description: 'description1', displayName: 'display name' }, | ||
validationError: undefined, | ||
}; | ||
minimalWithError = { | ||
...minimal, | ||
validationError: 'validation failed', | ||
}; | ||
renderer = ReactShallowRenderer.createRenderer(); | ||
initializeIcons(); | ||
}); | ||
|
||
afterEach(() => { | ||
renderer.unmount(); | ||
}); | ||
|
||
it('should construct.', () => { | ||
renderer.render(<TemplatesParameterField {...minimal} />); | ||
const parameterFields = renderer.getRenderOutput(); | ||
expect(parameterFields).toBeDefined(); | ||
}); | ||
|
||
it('should render all fields when passed a parameter definition.', () => { | ||
const intl = useIntl(); | ||
renderer.render(<TemplatesParameterField {...minimal} />); | ||
const parameterFields = renderer.getRenderOutput(); | ||
expect(parameterFields.props.children).toHaveLength(3); | ||
|
||
const [displayName, description, valueField]: any[] = React.Children.toArray(parameterFields.props.children); | ||
|
||
expect(displayName.props.className).toBe('msla-templates-parameter-heading'); | ||
expect(displayName.props.children).toBeTruthy(); | ||
const [label]: any[] = React.Children.toArray(displayName.props.children); | ||
expect(label.props.className).toBe('msla-templates-parameter-heading-text'); | ||
expect(label.props.text).toBe(minimal.definition.displayName); | ||
|
||
expect(description.props.className).toBe('msla-templates-parameter-description'); | ||
expect(description.props.children).toBeTruthy(); | ||
|
||
const [text]: any[] = React.Children.toArray(description.props.children); | ||
expect(text.props.className).toBe('msla-templates-parameter-description-text'); | ||
expect(text.props.children).toBe('description1'); | ||
|
||
const defaultValueDescription = intl.formatMessage({ | ||
defaultMessage: 'Enter value for parameter.', | ||
id: '7jAQar', | ||
description: 'Parameter Field Default Value Placeholder Text', | ||
}); | ||
|
||
const valueLabelText = `Value (${minimal.definition.type})`; | ||
const valueLabelId = `${minimal.definition.name}-value`; | ||
|
||
expect(valueField.props.className).toBe('msla-templates-parameter-field'); | ||
expect(valueField.props.children).toHaveLength(2); | ||
|
||
const [label2, textField]: any[] = React.Children.toArray(valueField.props.children); | ||
expect(label2.props.text).toBe(valueLabelText); | ||
expect(label2.props.htmlFor).toBe(valueLabelId); | ||
|
||
expect(textField.props.id).toBe(valueLabelId); | ||
expect(textField.props.ariaLabel).toBe(valueLabelText); | ||
expect(textField.props.placeholder).toBe(defaultValueDescription); | ||
expect(textField.props.value).toBe(minimal.definition.value); | ||
}); | ||
it('should render the error message when there is a validation error', () => { | ||
renderer.render(<TemplatesParameterField {...minimalWithError} />); | ||
const parameterFields = renderer.getRenderOutput(); | ||
expect(parameterFields.props.children).toHaveLength(3); | ||
|
||
const [_displayName, _description, valueField]: any[] = React.Children.toArray(parameterFields.props.children); | ||
const valueLabelText = `Value (${minimal.definition.type})`; | ||
const valueLabelId = `${minimal.definition.name}-value`; | ||
|
||
expect(valueField.props.className).toBe('msla-templates-parameter-field'); | ||
expect(valueField.props.children).toHaveLength(2); | ||
|
||
const [label2, textField]: any[] = React.Children.toArray(valueField.props.children); | ||
expect(label2.props.text).toBe(valueLabelText); | ||
expect(label2.props.htmlFor).toBe(valueLabelId); | ||
|
||
expect(textField.props.id).toBe(valueLabelId); | ||
expect(textField.props.errorMessage).toBe(minimalWithError.validationError); | ||
}); | ||
|
||
it('should render nothing when type passed is invalid.', () => { | ||
const props = { ...minimal, definition: { ...minimal.definition, type: 'random' } }; | ||
renderer.render(<TemplatesParameterField {...props} />); | ||
const parameterFields = renderer.getRenderOutput(); | ||
const [, type]: any[] = React.Children.toArray(parameterFields.props.children); | ||
expect(type.props.selectedKey).toBeUndefined(); | ||
}); | ||
}); |
32 changes: 32 additions & 0 deletions
32
libs/designer-ui/src/lib/templates/templatesParametersField.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
.msla-templates-parameters { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 16px; | ||
|
||
.msla-templates-parameter-heading { | ||
margin-bottom: 8px; | ||
} | ||
|
||
.msla-templates-parameter-heading-text { | ||
font-weight: 600; | ||
font-size: 14px; | ||
} | ||
|
||
.msla-templates-parameter-description { | ||
margin-bottom: 16px; | ||
} | ||
|
||
.msla-templates-parameter-description-text { | ||
font-size: 13px; | ||
color: @ms-color-secondary; | ||
} | ||
|
||
.ms-List-cell { | ||
padding-bottom: 16px; | ||
} | ||
|
||
.msla-templates-parameter-field { | ||
display: flex; | ||
min-height: 24px; | ||
} | ||
} |
115 changes: 115 additions & 0 deletions
115
libs/designer-ui/src/lib/templates/templatesParametersField.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import type { ILabelStyles, IStyle, ITextFieldStyles } from '@fluentui/react'; | ||
import { TextField } from '@fluentui/react'; | ||
import { useState } from 'react'; | ||
import { useIntl } from 'react-intl'; | ||
import { Text } from '@fluentui/react-components'; | ||
import { Label } from '../label'; | ||
import type { EventHandler } from '../eventhandler'; | ||
import type { Template } from '@microsoft/logic-apps-shared'; | ||
|
||
const labelStyles: Partial<ILabelStyles> = { | ||
root: { | ||
display: 'inline-block', | ||
minWidth: '120px', | ||
verticalAlign: 'top', | ||
padding: '0px', | ||
}, | ||
}; | ||
|
||
const fieldStyles: IStyle = { | ||
display: 'inline-block', | ||
flexGrow: 1, | ||
flexShrink: 1, | ||
flexBasis: 'auto', | ||
}; | ||
|
||
const textFieldStyles: Partial<ITextFieldStyles> = { | ||
root: fieldStyles, | ||
}; | ||
|
||
export interface TemplatesParameterUpdateEvent { | ||
newDefinition: Template.ParameterDefinition; | ||
useLegacy?: boolean; | ||
} | ||
|
||
export type TemplatesParameterUpdateHandler = EventHandler<TemplatesParameterUpdateEvent>; | ||
|
||
export interface TemplatesParameterFieldProps { | ||
definition: Template.ParameterDefinition; | ||
validationError: string | undefined; | ||
onChange?: TemplatesParameterUpdateHandler; | ||
useLegacy?: boolean; | ||
isReadOnly?: boolean; | ||
required?: boolean; | ||
} | ||
|
||
export const TemplatesParameterField = ({ | ||
definition, | ||
validationError, | ||
onChange, | ||
required = true, | ||
isReadOnly, | ||
useLegacy, | ||
}: TemplatesParameterFieldProps): JSX.Element => { | ||
const [value, setValue] = useState<string | undefined>(stringifyValue(definition.value)); | ||
const intl = useIntl(); | ||
|
||
const parameterValueId = `${definition.name}-value`; | ||
|
||
const valueTitle = intl.formatMessage({ | ||
defaultMessage: 'Value', | ||
id: 'ClZW2r', | ||
description: 'Parameter Field Value Title', | ||
}); | ||
const valueDescription = intl.formatMessage({ | ||
defaultMessage: 'Enter value for parameter.', | ||
id: 'rSIBjh', | ||
description: 'Parameter Field Value Placeholder Text', | ||
}); | ||
|
||
const onValueChange = (_event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string): void => { | ||
handleValueChange(newValue); | ||
}; | ||
|
||
const handleValueChange = (value?: string) => { | ||
setValue(value); | ||
|
||
onChange?.({ | ||
newDefinition: { | ||
...definition, | ||
value, | ||
}, | ||
useLegacy, | ||
}); | ||
}; | ||
|
||
return ( | ||
<> | ||
<div className="msla-templates-parameter-heading"> | ||
<Label className="msla-templates-parameter-heading-text" text={definition.displayName} isRequiredField={required} /> | ||
</div> | ||
<div className="msla-templates-parameter-description"> | ||
<Text className="msla-templates-parameter-description-text">{definition.description}</Text> | ||
</div> | ||
|
||
<div className="msla-templates-parameter-field"> | ||
<Label styles={labelStyles} text={`${valueTitle} (${definition.type})`} htmlFor={parameterValueId} /> | ||
<TextField | ||
data-testid={parameterValueId} | ||
id={parameterValueId} | ||
ariaLabel={`${valueTitle} (${definition.type})`} | ||
placeholder={valueDescription} | ||
value={value} | ||
errorMessage={validationError} | ||
styles={textFieldStyles} | ||
onChange={onValueChange} | ||
disabled={isReadOnly} | ||
/> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
function stringifyValue(value: any): string { | ||
return typeof value !== 'string' ? JSON.stringify(value) : value; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 4 additions & 4 deletions
8
libs/designer/src/lib/core/state/templates/templateselectors.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import { useSelector } from "react-redux"; | ||
import type { RootState } from "./store"; | ||
import { useSelector } from 'react-redux'; | ||
import type { RootState } from './store'; | ||
|
||
export const useAreServicesInitialized = () => { | ||
return useSelector((state: RootState) => state.template.servicesInitialized ?? false); | ||
}; | ||
return useSelector((state: RootState) => state.template.servicesInitialized ?? false); | ||
}; |
11 changes: 10 additions & 1 deletion
11
libs/designer/src/lib/core/templates/TemplatesDesignerContext.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule templateFiles
updated
9 files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.