Skip to content

Commit

Permalink
Merge branch 'main' into feat/select-dynamic-options
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/components/FormElements/FormElements.tsx
  • Loading branch information
asimonok committed Dec 29, 2023
2 parents 2ce6ada + 88bceb3 commit 4b2a193
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 13 deletions.
20 changes: 20 additions & 0 deletions src/components/ElementEditor/ElementEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,26 @@ export const ElementEditor: React.FC<Props> = ({
aria-label={TEST_IDS.formElementsEditor.fieldShowIf}
/>
</Field>

{element.type !== FormElementType.DISABLED_TEXTAREA &&
element.type !== FormElementType.DISABLED &&
element.type !== FormElementType.LINK && (
<Field label="Disable if returned value is true">
<AutosizeCodeEditor
value={element.disableIf || ''}
language={CodeLanguage.JAVASCRIPT}
onBlur={(code) => {
onChange({
...element,
disableIf: code,
});
}}
monacoOptions={{ formatOnPaste: true, formatOnType: true }}
showLineNumbers={true}
aria-label={TEST_IDS.formElementsEditor.fieldDisableIf}
/>
</Field>
)}
</>
);
};
47 changes: 34 additions & 13 deletions src/components/FormElement/FormElement.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { cx } from '@emotion/css';
import { DateTime, dateTime } from '@grafana/data';
import {
DatePickerWithInput,
DateTimePicker,
FileDropzone,
InlineField,
Expand Down Expand Up @@ -65,6 +66,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
labelWidth={applyWidth(element.labelWidth)}
tooltip={element.tooltip}
transparent={!element.title}
disabled={element.disabled}
>
<NumberInput
value={formatNumberValue(element.value)}
Expand Down Expand Up @@ -94,6 +96,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
className={cx({
[styles.hidden]: element.hidden,
})}
disabled={element.disabled}
>
<Input
value={element.value || ''}
Expand All @@ -118,6 +121,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
labelWidth={applyWidth(element.labelWidth)}
tooltip={element.tooltip}
transparent={!element.title}
disabled={element.disabled}
>
<Input
value={element.value || ''}
Expand Down Expand Up @@ -164,6 +168,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
labelWidth={applyWidth(element.labelWidth)}
tooltip={element.tooltip}
transparent={!element.title}
disabled={element.disabled}
>
<TextArea
value={element.value}
Expand Down Expand Up @@ -207,6 +212,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
labelWidth={applyWidth(element.labelWidth)}
tooltip={element.tooltip}
transparent={!element.title}
disabled={element.disabled}
>
<AutosizeCodeEditor
language={element.language || CodeLanguage.JAVASCRIPT}
Expand All @@ -223,6 +229,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
}}
monacoOptions={{ formatOnPaste: true, formatOnType: true }}
aria-label={TEST_IDS.formElements.fieldCode}
readOnly={element.disabled}
/>
</InlineField>
)}
Expand All @@ -235,6 +242,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
tooltip={element.tooltip}
transparent={!element.title}
data-testid={TEST_IDS.formElements.fieldBooleanContainer}
disabled={element.disabled}
>
<RadioButtonGroup
value={element.value}
Expand All @@ -258,19 +266,28 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
labelWidth={applyWidth(element.labelWidth)}
tooltip={element.tooltip}
transparent={!element.title}
disabled={element.disabled}
>
<DateTimePicker
minDate={element.min ? new Date(element.min) : undefined}
maxDate={element.max ? new Date(element.max) : undefined}
date={dateTime(element.value)}
onChange={(dateTime: DateTime) => {
onChange<typeof element>({
...element,
value: dateTime.toISOString(),
});
}}
data-testid={TEST_IDS.formElements.fieldDateTime}
/>
{element.disabled ? (
<DatePickerWithInput
onChange={undefined as never}
value={element.value}
data-testid={TEST_IDS.formElements.fieldDateTime}
/>
) : (
<DateTimePicker
minDate={element.min ? new Date(element.min) : undefined}
maxDate={element.max ? new Date(element.max) : undefined}
date={dateTime(element.value)}
onChange={(dateTime: DateTime) => {
onChange<typeof element>({
...element,
value: dateTime.toISOString(),
});
}}
data-testid={TEST_IDS.formElements.fieldDateTime}
/>
)}
</InlineField>
)}

Expand All @@ -283,6 +300,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
tooltip={element.tooltip}
transparent={!element.title}
className={cx(styles.slider)}
disabled={element.disabled}
>
<Slider
value={element.value || 0}
Expand All @@ -298,7 +316,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
ariaLabelForHandle={TEST_IDS.formElements.fieldSlider}
/>
</InlineField>
<InlineField className={cx(styles.sliderInput)}>
<InlineField className={cx(styles.sliderInput)} disabled={element.disabled}>
<Input
type="number"
width={8}
Expand All @@ -325,6 +343,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
tooltip={element.tooltip}
transparent={!element.title}
data-testid={TEST_IDS.formElements.fieldRadioContainer}
disabled={element.disabled}
>
<RadioButtonGroup
value={element.value}
Expand All @@ -348,6 +367,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
labelWidth={applyWidth(element.labelWidth)}
tooltip={element.tooltip}
transparent={!element.title}
disabled={element.disabled}
>
<Select
isMulti={element.type === FormElementType.MULTISELECT}
Expand All @@ -373,6 +393,7 @@ export const FormElement: React.FC<Props> = ({ element, onChange, highlightClass
labelWidth={applyWidth(element.labelWidth)}
tooltip={element.tooltip}
transparent={!element.title}
disabled={element.disabled}
>
<FileDropzone
options={{
Expand Down
24 changes: 24 additions & 0 deletions src/components/FormElements/FormElements.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,30 @@ describe('Form Elements', () => {
expect(selectors.fieldSelect()).toBeInTheDocument();
});

it('Should find component with disabled DateTime', async () => {
const options = {
submit: {},
initial: { highlightColor: false },
update: {},
reset: {},
elements: [
{
id: 'dateTime',
type: FormElementType.DATETIME,
value: new Date('10-10-10').toISOString(),
disableIf: 'return true;',
},
],
};

render(getComponent({ options, onChangeElement }));

/**
* Date Time
*/
expect(selectors.fieldDateTime()).toBeInTheDocument();
});

it('Should find component with Select and unset value', async () => {
const options = {
submit: {},
Expand Down
1 change: 1 addition & 0 deletions src/components/FormElements/FormElements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export const FormElements: React.FC<Props> = ({
})
.map((element) => ({
...element,
disabled: element.helpers.disableIf({ elements, replaceVariables }),
options: element.helpers.getOptions({ elements, replaceVariables, data }),
}));
}, [data, elements, replaceVariables]);
Expand Down
19 changes: 19 additions & 0 deletions src/components/FormElementsEditor/FormElementsEditor.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,25 @@ describe('Form Elements Editor', () => {
expect(elementSelectors.fieldShowIf()).toHaveValue('123');
});

it('Should update disableIf', async () => {
const element = { ...FORM_ELEMENT_DEFAULT, id: 'id', type: FormElementType.TEXTAREA, rows: 2 };
const elements = [element];

render(getComponent({ value: elements, onChange }));

/**
* Open id element
*/
const elementSelectors = openElement(element.id, element.type);

/**
* Change textarea rows
*/
await act(() => fireEvent.blur(elementSelectors.fieldDisableIf(), { target: { value: '123' } }));

expect(elementSelectors.fieldDisableIf()).toHaveValue('123');
});

describe('Apply default element options', () => {
it('Should set default Slider options if NewType=SLIDER', async () => {
const element = { ...FORM_ELEMENT_DEFAULT, id: 'id', type: FormElementType.STRING };
Expand Down
1 change: 1 addition & 0 deletions src/constants/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const TEST_IDS = {
fieldTooltip: 'data-testid form-elements-editor field-tooltip',
fieldType: 'form-elements-editor field-type',
fieldShowIf: 'form-elements-editor field-show-if',
fieldDisableIf: 'form-elements-editor field-disable-if',
fieldUnit: 'data-testid form-elements-editor field-unit',
fieldVisibility: 'data-testid form-elements-editor field-visibility',
fieldWidth: 'data-testid form-elements-editor field-width',
Expand Down
27 changes: 27 additions & 0 deletions src/types/form-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ export interface FormElementBase {
*/
showIf?: string;

/**
* Disable If
*
* @type {string}
*/
disableIf?: string;

/**
* Field Name
*/
Expand Down Expand Up @@ -433,10 +440,23 @@ export type ShowIfHelper = (params: {
replaceVariables: InterpolateFunction;
}) => boolean | undefined;

/**
* Disable If Helper
*/
export type DisableIfHelper = (params: {
elements: FormElement[];
replaceVariables: InterpolateFunction;
}) => boolean | undefined;

/**
* Local Form Element
*/
export type LocalFormElement = FormElement & {
/**
* Disabled
*/
disabled?: boolean;

/**
* Helpers
*/
Expand All @@ -448,6 +468,13 @@ export type LocalFormElement = FormElement & {
*/
showIf: ShowIfHelper;

/**
* Disable If Function
*
* @type {DisableIfHelper}
*/
disableIf: DisableIfHelper;

/**
* Get Options Function
*
Expand Down
16 changes: 16 additions & 0 deletions src/utils/form-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from '../constants';
import {
ButtonVariant,
DisableIfHelper,
FormElement,
FormElementByType,
GetOptionsHelper,
Expand Down Expand Up @@ -225,6 +226,20 @@ export const toLocalFormElement = (element: FormElement): LocalFormElement => {
fn(elements, replaceVariables);
}

const disableIf = element.disableIf;

let disableIfFn: DisableIfHelper = () => false;
if (disableIf || disableIf?.trim()) {
const fn = new Function('elements', 'replaceVariables', disableIf);
disableIfFn = ({
elements,
replaceVariables,
}: {
elements: FormElement[];
replaceVariables: InterpolateFunction;
}) => fn(elements, replaceVariables);
}

let getOptions: GetOptionsHelper = () => [];
if (
element.type === FormElementType.DISABLED ||
Expand Down Expand Up @@ -284,6 +299,7 @@ export const toLocalFormElement = (element: FormElement): LocalFormElement => {
: {}),
helpers: {
showIf: showIfFn,
disableIf: disableIfFn,
getOptions,
},
uid: getElementUniqueId(element),
Expand Down

0 comments on commit 4b2a193

Please sign in to comment.