mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 12:12:11 +08:00
Dashboards: Disable variable pickers for snapshots (#52827)
* user essentials mob! 🔱 lastFile:public/app/features/variables/textbox/TextBoxVariablePicker.tsx * user essentials mob! 🔱 * user essentials mob! 🔱 lastFile:public/app/features/variables/adhoc/picker/AdHocFilter.tsx * finish up disabling variables in snapshots * remove accident * use theme.spacing instead of the v1 shim Co-authored-by: Joao Silva <joao.silva@grafana.com> Co-authored-by: Leodegario Pasakdal <leodegario.pasakdal@grafana.com>
This commit is contained in:
@ -49,10 +49,12 @@ class SubMenuUnConnected extends PureComponent<Props> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const readOnlyVariables = dashboard.meta.isSnapshot ?? false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="submenu-controls">
|
<div className="submenu-controls">
|
||||||
<form aria-label="Template variables" className={styles}>
|
<form aria-label="Template variables" className={styles}>
|
||||||
<SubMenuItems variables={variables} />
|
<SubMenuItems variables={variables} readOnly={readOnlyVariables} />
|
||||||
</form>
|
</form>
|
||||||
<Annotations
|
<Annotations
|
||||||
annotations={annotations}
|
annotations={annotations}
|
||||||
|
@ -7,9 +7,10 @@ import { VariableHide, VariableModel } from '../../../variables/types';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
variables: VariableModel[];
|
variables: VariableModel[];
|
||||||
|
readOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SubMenuItems: FunctionComponent<Props> = ({ variables }) => {
|
export const SubMenuItems: FunctionComponent<Props> = ({ variables, readOnly }) => {
|
||||||
const [visibleVariables, setVisibleVariables] = useState<VariableModel[]>([]);
|
const [visibleVariables, setVisibleVariables] = useState<VariableModel[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -29,7 +30,7 @@ export const SubMenuItems: FunctionComponent<Props> = ({ variables }) => {
|
|||||||
className="submenu-item gf-form-inline"
|
className="submenu-item gf-form-inline"
|
||||||
data-testid={selectors.pages.Dashboard.SubMenu.submenuItem}
|
data-testid={selectors.pages.Dashboard.SubMenu.submenuItem}
|
||||||
>
|
>
|
||||||
<PickerRenderer variable={variable} />
|
<PickerRenderer variable={variable} readOnly={readOnly} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { PureComponent, ReactNode } from 'react';
|
import React, { PureComponent, ReactNode } from 'react';
|
||||||
|
|
||||||
import { DataSourceRef, SelectableValue } from '@grafana/data';
|
import { DataSourceRef, SelectableValue } from '@grafana/data';
|
||||||
|
import { Segment } from '@grafana/ui';
|
||||||
import { AdHocVariableFilter } from 'app/features/variables/types';
|
import { AdHocVariableFilter } from 'app/features/variables/types';
|
||||||
|
|
||||||
import { AdHocFilterBuilder } from './AdHocFilterBuilder';
|
import { AdHocFilterBuilder } from './AdHocFilterBuilder';
|
||||||
@ -17,6 +18,7 @@ interface Props {
|
|||||||
// Passes options to the datasources getTagKeys(options?: any) method
|
// Passes options to the datasources getTagKeys(options?: any) method
|
||||||
// which is called to fetch the available filter key options in AdHocFilterKey.tsx
|
// which is called to fetch the available filter key options in AdHocFilterKey.tsx
|
||||||
getTagKeysOptions?: any;
|
getTagKeysOptions?: any;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,35 +49,43 @@ export class AdHocFilter extends PureComponent<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { filters } = this.props;
|
const { filters, disabled } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="gf-form-inline">
|
<div className="gf-form-inline">
|
||||||
{this.renderFilters(filters)}
|
{this.renderFilters(filters, disabled)}
|
||||||
<AdHocFilterBuilder
|
|
||||||
datasource={this.props.datasource!}
|
{!disabled && (
|
||||||
appendBefore={filters.length > 0 ? <ConditionSegment label="AND" /> : null}
|
<AdHocFilterBuilder
|
||||||
onCompleted={this.appendFilterToVariable}
|
datasource={this.props.datasource!}
|
||||||
getTagKeysOptions={this.props.getTagKeysOptions}
|
appendBefore={filters.length > 0 ? <ConditionSegment label="AND" /> : null}
|
||||||
/>
|
onCompleted={this.appendFilterToVariable}
|
||||||
|
getTagKeysOptions={this.props.getTagKeysOptions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFilters(filters: AdHocVariableFilter[]) {
|
renderFilters(filters: AdHocVariableFilter[], disabled?: boolean) {
|
||||||
|
if (filters.length === 0 && disabled) {
|
||||||
|
return <Segment disabled={disabled} value="No filters" options={[]} onChange={() => {}} />;
|
||||||
|
}
|
||||||
|
|
||||||
return filters.reduce((segments: ReactNode[], filter, index) => {
|
return filters.reduce((segments: ReactNode[], filter, index) => {
|
||||||
if (segments.length > 0) {
|
if (segments.length > 0) {
|
||||||
segments.push(<ConditionSegment label="AND" key={`condition-${index}`} />);
|
segments.push(<ConditionSegment label="AND" key={`condition-${index}`} />);
|
||||||
}
|
}
|
||||||
segments.push(this.renderFilterSegments(filter, index));
|
segments.push(this.renderFilterSegments(filter, index, disabled));
|
||||||
return segments;
|
return segments;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFilterSegments(filter: AdHocVariableFilter, index: number) {
|
renderFilterSegments(filter: AdHocVariableFilter, index: number, disabled?: boolean) {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={`filter-${index}`}>
|
<React.Fragment key={`filter-${index}`}>
|
||||||
<AdHocFilterRenderer
|
<AdHocFilterRenderer
|
||||||
|
disabled={disabled}
|
||||||
datasource={this.props.datasource!}
|
datasource={this.props.datasource!}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
onKeyChange={this.onChange(index, 'key')}
|
onKeyChange={this.onChange(index, 'key')}
|
||||||
|
@ -10,10 +10,11 @@ interface Props {
|
|||||||
filterKey: string | null;
|
filterKey: string | null;
|
||||||
onChange: (item: SelectableValue<string | null>) => void;
|
onChange: (item: SelectableValue<string | null>) => void;
|
||||||
getTagKeysOptions?: any;
|
getTagKeysOptions?: any;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MIN_WIDTH = 90;
|
const MIN_WIDTH = 90;
|
||||||
export const AdHocFilterKey: FC<Props> = ({ datasource, onChange, filterKey, getTagKeysOptions }) => {
|
export const AdHocFilterKey: FC<Props> = ({ datasource, onChange, disabled, filterKey, getTagKeysOptions }) => {
|
||||||
const loadKeys = () => fetchFilterKeys(datasource, getTagKeysOptions);
|
const loadKeys = () => fetchFilterKeys(datasource, getTagKeysOptions);
|
||||||
const loadKeysWithRemove = () => fetchFilterKeysWithRemove(datasource, getTagKeysOptions);
|
const loadKeysWithRemove = () => fetchFilterKeysWithRemove(datasource, getTagKeysOptions);
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ export const AdHocFilterKey: FC<Props> = ({ datasource, onChange, filterKey, get
|
|||||||
return (
|
return (
|
||||||
<div className="gf-form" data-testid="AdHocFilterKey-add-key-wrapper">
|
<div className="gf-form" data-testid="AdHocFilterKey-add-key-wrapper">
|
||||||
<SegmentAsync
|
<SegmentAsync
|
||||||
|
disabled={disabled}
|
||||||
className="query-segment-key"
|
className="query-segment-key"
|
||||||
Component={plusSegment}
|
Component={plusSegment}
|
||||||
value={filterKey}
|
value={filterKey}
|
||||||
@ -35,6 +37,7 @@ export const AdHocFilterKey: FC<Props> = ({ datasource, onChange, filterKey, get
|
|||||||
return (
|
return (
|
||||||
<div className="gf-form" data-testid="AdHocFilterKey-key-wrapper">
|
<div className="gf-form" data-testid="AdHocFilterKey-key-wrapper">
|
||||||
<SegmentAsync
|
<SegmentAsync
|
||||||
|
disabled={disabled}
|
||||||
className="query-segment-key"
|
className="query-segment-key"
|
||||||
value={filterKey}
|
value={filterKey}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
@ -15,6 +15,7 @@ interface Props {
|
|||||||
onValueChange: (item: SelectableValue<string>) => void;
|
onValueChange: (item: SelectableValue<string>) => void;
|
||||||
placeHolder?: string;
|
placeHolder?: string;
|
||||||
getTagKeysOptions?: any;
|
getTagKeysOptions?: any;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdHocFilterRenderer: FC<Props> = ({
|
export const AdHocFilterRenderer: FC<Props> = ({
|
||||||
@ -25,19 +26,22 @@ export const AdHocFilterRenderer: FC<Props> = ({
|
|||||||
onValueChange,
|
onValueChange,
|
||||||
placeHolder,
|
placeHolder,
|
||||||
getTagKeysOptions,
|
getTagKeysOptions,
|
||||||
|
disabled,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AdHocFilterKey
|
<AdHocFilterKey
|
||||||
|
disabled={disabled}
|
||||||
datasource={datasource}
|
datasource={datasource}
|
||||||
filterKey={key}
|
filterKey={key}
|
||||||
onChange={onKeyChange}
|
onChange={onKeyChange}
|
||||||
getTagKeysOptions={getTagKeysOptions}
|
getTagKeysOptions={getTagKeysOptions}
|
||||||
/>
|
/>
|
||||||
<div className="gf-form">
|
<div className="gf-form">
|
||||||
<OperatorSegment value={operator} onChange={onOperatorChange} />
|
<OperatorSegment disabled={disabled} value={operator} onChange={onOperatorChange} />
|
||||||
</div>
|
</div>
|
||||||
<AdHocFilterValue
|
<AdHocFilterValue
|
||||||
|
disabled={disabled}
|
||||||
datasource={datasource}
|
datasource={datasource}
|
||||||
filterKey={key}
|
filterKey={key}
|
||||||
filterValue={value}
|
filterValue={value}
|
||||||
|
@ -11,15 +11,24 @@ interface Props {
|
|||||||
filterValue?: string;
|
filterValue?: string;
|
||||||
onChange: (item: SelectableValue<string>) => void;
|
onChange: (item: SelectableValue<string>) => void;
|
||||||
placeHolder?: string;
|
placeHolder?: string;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdHocFilterValue: FC<Props> = ({ datasource, onChange, filterKey, filterValue, placeHolder }) => {
|
export const AdHocFilterValue: FC<Props> = ({
|
||||||
|
datasource,
|
||||||
|
disabled,
|
||||||
|
onChange,
|
||||||
|
filterKey,
|
||||||
|
filterValue,
|
||||||
|
placeHolder,
|
||||||
|
}) => {
|
||||||
const loadValues = () => fetchFilterValues(datasource, filterKey);
|
const loadValues = () => fetchFilterValues(datasource, filterKey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="gf-form" data-testid="AdHocFilterValue-value-wrapper">
|
<div className="gf-form" data-testid="AdHocFilterValue-value-wrapper">
|
||||||
<SegmentAsync
|
<SegmentAsync
|
||||||
className="query-segment-value"
|
className="query-segment-value"
|
||||||
|
disabled={disabled}
|
||||||
placeholder={placeHolder}
|
placeholder={placeHolder}
|
||||||
value={filterValue}
|
value={filterValue}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
@ -48,6 +48,7 @@ export class AdHocPickerUnconnected extends PureComponent<Props> {
|
|||||||
<AdHocFilter
|
<AdHocFilter
|
||||||
datasource={datasource}
|
datasource={datasource}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
|
disabled={this.props.readOnly}
|
||||||
addFilter={this.addFilter}
|
addFilter={this.addFilter}
|
||||||
removeFilter={this.removeFilter}
|
removeFilter={this.removeFilter}
|
||||||
changeFilter={this.changeFilter}
|
changeFilter={this.changeFilter}
|
||||||
|
@ -6,6 +6,7 @@ import { Segment } from '@grafana/ui';
|
|||||||
interface Props {
|
interface Props {
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (item: SelectableValue<string>) => void;
|
onChange: (item: SelectableValue<string>) => void;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = ['=', '!=', '<', '>', '=~', '!~'].map<SelectableValue<string>>((value) => ({
|
const options = ['=', '!=', '<', '>', '=~', '!~'].map<SelectableValue<string>>((value) => ({
|
||||||
@ -13,6 +14,14 @@ const options = ['=', '!=', '<', '>', '=~', '!~'].map<SelectableValue<string>>((
|
|||||||
value,
|
value,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const OperatorSegment: FC<Props> = ({ value, onChange }) => {
|
export const OperatorSegment: FC<Props> = ({ value, disabled, onChange }) => {
|
||||||
return <Segment className="query-segment-operator" value={value} options={options} onChange={onChange} />;
|
return (
|
||||||
|
<Segment
|
||||||
|
className="query-segment-operator"
|
||||||
|
value={value}
|
||||||
|
disabled={disabled}
|
||||||
|
options={options}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -37,6 +37,7 @@ function setupTestContext({ pickerState = {}, variable = {} }: Args = {}) {
|
|||||||
const props: VariablePickerProps<VariableWithMultiSupport | VariableWithOptions> = {
|
const props: VariablePickerProps<VariableWithMultiSupport | VariableWithOptions> = {
|
||||||
variable: v,
|
variable: v,
|
||||||
onVariableChange,
|
onVariableChange,
|
||||||
|
readOnly: false,
|
||||||
};
|
};
|
||||||
const Picker = optionPickerFactory();
|
const Picker = optionPickerFactory();
|
||||||
const optionsPicker: OptionsPickerState = { ...initialOptionPickerState, ...pickerState };
|
const optionsPicker: OptionsPickerState = { ...initialOptionPickerState, ...pickerState };
|
||||||
|
@ -130,6 +130,7 @@ export const optionPickerFactory = <Model extends VariableWithOptions | Variable
|
|||||||
onClick={this.onShowOptions}
|
onClick={this.onShowOptions}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onCancel={this.onCancel}
|
onCancel={this.onCancel}
|
||||||
|
disabled={this.props.readOnly}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import { VariableHide, VariableModel } from '../types';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
variable: VariableModel;
|
variable: VariableModel;
|
||||||
|
readOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PickerRenderer: FunctionComponent<Props> = (props) => {
|
export const PickerRenderer: FunctionComponent<Props> = (props) => {
|
||||||
@ -21,7 +22,7 @@ export const PickerRenderer: FunctionComponent<Props> = (props) => {
|
|||||||
<div className="gf-form">
|
<div className="gf-form">
|
||||||
<PickerLabel variable={props.variable} />
|
<PickerLabel variable={props.variable} />
|
||||||
{props.variable.hide !== VariableHide.hideVariable && PickerToRender && (
|
{props.variable.hide !== VariableHide.hideVariable && PickerToRender && (
|
||||||
<PickerToRender variable={props.variable} />
|
<PickerToRender variable={props.variable} readOnly={props.readOnly ?? false} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { FC, MouseEvent, useCallback } from 'react';
|
import React, { FC, MouseEvent, useCallback } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Icon, Tooltip, useStyles } from '@grafana/ui';
|
import { Icon, Tooltip, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
text: string;
|
text: string;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
|
disabled: boolean; // todo: optional?
|
||||||
/**
|
/**
|
||||||
* htmlFor, needed for the label
|
* htmlFor, needed for the label
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VariableLink: FC<Props> = ({ loading, onClick: propsOnClick, text, onCancel, id }) => {
|
export const VariableLink: FC<Props> = ({ loading, disabled, onClick: propsOnClick, text, onCancel, id }) => {
|
||||||
const styles = useStyles(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const onClick = useCallback(
|
const onClick = useCallback(
|
||||||
(event: MouseEvent<HTMLButtonElement>) => {
|
(event: MouseEvent<HTMLButtonElement>) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
@ -50,6 +51,7 @@ export const VariableLink: FC<Props> = ({ loading, onClick: propsOnClick, text,
|
|||||||
aria-controls={`options-${id}`}
|
aria-controls={`options-${id}`}
|
||||||
id={id}
|
id={id}
|
||||||
title={text}
|
title={text}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<VariableLinkText text={text} />
|
<VariableLinkText text={text} />
|
||||||
<Icon aria-hidden name="angle-down" size="sm" />
|
<Icon aria-hidden name="angle-down" size="sm" />
|
||||||
@ -62,7 +64,7 @@ interface VariableLinkTextProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const VariableLinkText: FC<VariableLinkTextProps> = ({ text }) => {
|
const VariableLinkText: FC<VariableLinkTextProps> = ({ text }) => {
|
||||||
const styles = useStyles(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
return <span className={styles.textAndTags}>{text}</span>;
|
return <span className={styles.textAndTags}>{text}</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,28 +90,34 @@ const LoadingIndicator: FC<Pick<Props, 'onCancel'>> = ({ onCancel }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme) => ({
|
const getStyles = (theme: GrafanaTheme2) => ({
|
||||||
container: css`
|
container: css`
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
padding: 0 ${theme.spacing.sm};
|
padding: 0 ${theme.spacing(1)};
|
||||||
background-color: ${theme.colors.formInputBg};
|
background-color: ${theme.components.input.background};
|
||||||
border: 1px solid ${theme.colors.formInputBorder};
|
border: 1px solid ${theme.components.input.borderColor};
|
||||||
border-radius: ${theme.border.radius.sm};
|
border-radius: ${theme.shape.borderRadius(1)};
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: ${theme.colors.text};
|
color: ${theme.colors.text};
|
||||||
height: ${theme.height.md}px;
|
height: ${theme.spacing(theme.components.height.md)};
|
||||||
|
|
||||||
.label-tag {
|
.label-tag {
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: ${theme.colors.action.disabledBackground};
|
||||||
|
color: ${theme.colors.action.disabledText};
|
||||||
|
border: 1px solid ${theme.colors.action.disabledBackground};
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
textAndTags: css`
|
textAndTags: css`
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin-right: ${theme.spacing.xxs};
|
margin-right: ${theme.spacing(0.25)};
|
||||||
user-select: none;
|
user-select: none;
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ import { VariableModel } from '../types';
|
|||||||
|
|
||||||
export interface VariablePickerProps<Model extends VariableModel = VariableModel> {
|
export interface VariablePickerProps<Model extends VariableModel = VariableModel> {
|
||||||
variable: Model;
|
variable: Model;
|
||||||
|
readOnly: boolean;
|
||||||
onVariableChange?: (variable: Model) => void;
|
onVariableChange?: (variable: Model) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import { toVariablePayload } from '../utils';
|
|||||||
|
|
||||||
export interface Props extends VariablePickerProps<TextBoxVariableModel> {}
|
export interface Props extends VariablePickerProps<TextBoxVariableModel> {}
|
||||||
|
|
||||||
export function TextBoxVariablePicker({ variable, onVariableChange }: Props): ReactElement {
|
export function TextBoxVariablePicker({ variable, onVariableChange, readOnly }: Props): ReactElement {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [updatedValue, setUpdatedValue] = useState(variable.current.value);
|
const [updatedValue, setUpdatedValue] = useState(variable.current.value);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -68,6 +68,7 @@ export function TextBoxVariablePicker({ variable, onVariableChange }: Props): Re
|
|||||||
value={updatedValue}
|
value={updatedValue}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
|
disabled={readOnly}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
placeholder="Enter variable value"
|
placeholder="Enter variable value"
|
||||||
id={`var-${variable.id}`}
|
id={`var-${variable.id}`}
|
||||||
|
Reference in New Issue
Block a user