Dashboards: add delete variable flow to VariableEditorForm (#82149)

* add delete variable flow to VariableEditorForm

* adjust modal logic and replace HorizontalGroup with Stack

* revert onDelete prop name
This commit is contained in:
Sergej-Vlasov 2024-02-09 12:01:58 +00:00 committed by GitHub
parent e0bff6247c
commit 5a5520b5da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 94 additions and 66 deletions

View File

@ -207,6 +207,7 @@ function VariableEditorSettingsListView({ model }: SceneComponentProps<Variables
pageNav={pageNav}
navModel={navModel}
dashboard={dashboard}
onDelete={onDelete}
/>
);
}
@ -234,6 +235,7 @@ interface VariableEditorSettingsEditViewProps {
dashboard: DashboardScene;
onTypeChange: (variableType: EditableVariableType) => void;
onGoBack: () => void;
onDelete: (variableName: string) => void;
}
function VariableEditorSettingsView({
@ -243,6 +245,7 @@ function VariableEditorSettingsView({
dashboard,
onTypeChange,
onGoBack,
onDelete,
}: VariableEditorSettingsEditViewProps) {
const parentTab = pageNav.children!.find((p) => p.active)!;
parentTab.parentItem = pageNav;
@ -255,7 +258,7 @@ function VariableEditorSettingsView({
return (
<Page navModel={navModel} pageNav={editVariablePageNav} layout={PageLayoutType.Standard}>
<NavToolbarActions dashboard={dashboard} />
<VariableEditorForm variable={variable} onTypeChange={onTypeChange} onGoBack={onGoBack} />
<VariableEditorForm variable={variable} onTypeChange={onTypeChange} onGoBack={onGoBack} onDelete={onDelete} />
</Page>
);
}

View File

@ -1,18 +1,19 @@
import { css } from '@emotion/css';
import React, { FormEvent } from 'react';
import { useAsyncFn } from 'react-use';
import { lastValueFrom } from 'rxjs';
import { SelectableValue } from '@grafana/data';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { reportInteraction } from '@grafana/runtime';
import { SceneVariable } from '@grafana/scenes';
import { VariableHide, defaultVariableModel } from '@grafana/schema';
import { HorizontalGroup, Button, LoadingPlaceholder } from '@grafana/ui';
import { Button, LoadingPlaceholder, ConfirmModal, ModalsController, Stack, useStyles2 } from '@grafana/ui';
import { VariableHideSelect } from 'app/features/dashboard-scene/settings/variables/components/VariableHideSelect';
import { VariableLegend } from 'app/features/dashboard-scene/settings/variables/components/VariableLegend';
import { VariableTextAreaField } from 'app/features/dashboard-scene/settings/variables/components/VariableTextAreaField';
import { VariableTextField } from 'app/features/dashboard-scene/settings/variables/components/VariableTextField';
import { VariableValuesPreview } from 'app/features/dashboard-scene/settings/variables/components/VariableValuesPreview';
import { ConfirmDeleteModal } from 'app/features/variables/editor/ConfirmDeleteModal';
import { VariableNameConstraints } from 'app/features/variables/editor/types';
import { VariableTypeSelect } from './components/VariableTypeSelect';
@ -22,9 +23,11 @@ interface VariableEditorFormProps {
variable: SceneVariable;
onTypeChange: (type: EditableVariableType) => void;
onGoBack: () => void;
onDelete: (variableName: string) => void;
}
export function VariableEditorForm({ variable, onTypeChange, onGoBack }: VariableEditorFormProps) {
export function VariableEditorForm({ variable, onTypeChange, onGoBack, onDelete }: VariableEditorFormProps) {
const styles = useStyles2(getStyles);
const { name, type, label, description, hide } = variable.useState();
const EditorToRender = isEditableVariableType(type) ? getVariableEditor(type) : undefined;
const [runQueryState, onRunQuery] = useAsyncFn(async () => {
@ -42,78 +45,100 @@ export function VariableEditorForm({ variable, onTypeChange, onGoBack }: Variabl
const onDescriptionBlur = (e: FormEvent<HTMLTextAreaElement>) =>
variable.setState({ description: e.currentTarget.value });
const onHideChange = (hide: VariableHide) => variable.setState({ hide });
const isHasVariableOptions = hasVariableOptions(variable);
const onDeleteVariable = (hideModal: () => void) => () => {
reportInteraction('Delete variable');
onDelete(name);
hideModal();
};
return (
<>
<form aria-label="Variable editor Form">
<VariableTypeSelect onChange={onVariableTypeChange} type={type} />
<form aria-label="Variable editor Form">
<VariableTypeSelect onChange={onVariableTypeChange} type={type} />
<VariableLegend>General</VariableLegend>
<VariableTextField
name="Name"
description="The name of the template variable. (Max. 50 characters)"
placeholder="Variable name"
defaultValue={name ?? ''}
onBlur={onNameBlur}
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalNameInputV2}
maxLength={VariableNameConstraints.MaxSize}
required
/>
<VariableTextField
name="Label"
description="Optional display name"
placeholder="Label name"
defaultValue={label ?? ''}
onBlur={onLabelBlur}
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInputV2}
/>
<VariableTextAreaField
name="Description"
defaultValue={description ?? ''}
placeholder="Descriptive text"
onBlur={onDescriptionBlur}
width={52}
/>
<VariableLegend>General</VariableLegend>
<VariableTextField
name="Name"
description="The name of the template variable. (Max. 50 characters)"
placeholder="Variable name"
defaultValue={name ?? ''}
onBlur={onNameBlur}
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalNameInputV2}
maxLength={VariableNameConstraints.MaxSize}
required
/>
<VariableTextField
name="Label"
description="Optional display name"
placeholder="Label name"
defaultValue={label ?? ''}
onBlur={onLabelBlur}
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInputV2}
/>
<VariableTextAreaField
name="Description"
defaultValue={description ?? ''}
placeholder="Descriptive text"
onBlur={onDescriptionBlur}
width={52}
/>
<VariableHideSelect onChange={onHideChange} hide={hide || defaultVariableModel.hide!} type={type} />
<VariableHideSelect onChange={onHideChange} hide={hide || defaultVariableModel.hide!} type={type} />
{EditorToRender && <EditorToRender variable={variable} onRunQuery={onRunQuery} />}
{EditorToRender && <EditorToRender variable={variable} onRunQuery={onRunQuery} />}
{isHasVariableOptions && <VariableValuesPreview options={variable.getOptionsForSelect()} />}
{isHasVariableOptions && <VariableValuesPreview options={variable.getOptionsForSelect()} />}
<div style={{ marginTop: '16px' }}>
<HorizontalGroup spacing="md" height="inherit">
{/* <Button variant="destructive" fill="outline" onClick={onModalOpen}>
Delete
</Button> */}
<Button
variant="secondary"
data-testid={selectors.pages.Dashboard.Settings.Variables.Edit.General.applyButton}
onClick={onGoBack}
>
Back to list
</Button>
{isHasVariableOptions && (
<div className={styles.buttonContainer}>
<Stack gap={2}>
<ModalsController>
{({ showModal, hideModal }) => (
<Button
disabled={runQueryState.loading}
variant="secondary"
data-testid={selectors.pages.Dashboard.Settings.Variables.Edit.General.submitButton}
onClick={onRunQuery}
variant="destructive"
fill="outline"
onClick={() => {
showModal(ConfirmModal, {
title: 'Delete variable',
body: `Are you sure you want to delete: ${name}?`,
confirmText: 'Delete variable',
onConfirm: onDeleteVariable(hideModal),
onDismiss: hideModal,
isOpen: true,
});
}}
>
{runQueryState.loading ? <LoadingPlaceholder text="Running query..." /> : `Run query`}
Delete
</Button>
)}
</HorizontalGroup>
</div>
</form>
<ConfirmDeleteModal
isOpen={false}
varName={variable.state.name}
onConfirm={() => console.log('needs implementation')}
onDismiss={() => console.log('needs implementation')}
/>
</>
</ModalsController>
<Button
variant="secondary"
data-testid={selectors.pages.Dashboard.Settings.Variables.Edit.General.applyButton}
onClick={onGoBack}
>
Back to list
</Button>
{isHasVariableOptions && (
<Button
disabled={runQueryState.loading}
variant="secondary"
data-testid={selectors.pages.Dashboard.Settings.Variables.Edit.General.submitButton}
onClick={onRunQuery}
>
{runQueryState.loading ? <LoadingPlaceholder text="Running query..." /> : `Run query`}
</Button>
)}
</Stack>
</div>
</form>
);
}
const getStyles = (theme: GrafanaTheme2) => ({
buttonContainer: css({
marginTop: theme.spacing(2),
}),
});