diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/AcknowledgeCheckboxes.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/AcknowledgeCheckboxes.tsx index af5950db425..21c178b987c 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/AcknowledgeCheckboxes.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/AcknowledgeCheckboxes.tsx @@ -1,18 +1,17 @@ import React from 'react'; +import { UseFormRegister } from 'react-hook-form'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; import { Checkbox, FieldSet, HorizontalGroup, LinkButton, VerticalGroup } from '@grafana/ui/src'; -import { Acknowledgements } from './SharePublicDashboardUtils'; +import { SharePublicDashboardInputs } from './SharePublicDashboard'; export const AcknowledgeCheckboxes = ({ disabled, - acknowledgements, - onAcknowledge, + register, }: { disabled: boolean; - acknowledgements: Acknowledgements; - onAcknowledge: (key: string, val: boolean) => void; + register: UseFormRegister; }) => { const selectors = e2eSelectors.pages.ShareDashboardModal.PublicDashboard; @@ -23,11 +22,11 @@ export const AcknowledgeCheckboxes = ({ onAcknowledge('public', e.currentTarget.checked)} /> + onAcknowledge('datasources', e.currentTarget.checked)} /> onAcknowledge('usage', e.currentTarget.checked)} /> void; - onToggleAnnotations: () => void; dashboard: DashboardModel; + register: UseFormRegister; }) => { const selectors = e2eSelectors.pages.ShareDashboardModal.PublicDashboard; const styles = useStyles2(getStyles); @@ -33,7 +30,7 @@ export const Configuration = ({ return ( <> -

Public dashboard configuration

+

Public dashboard configuration

@@ -43,28 +40,29 @@ export const Configuration = ({ { + {...register('isAnnotationsEnabled')} + onChange={(e) => { + const { onChange } = register('isAnnotationsEnabled'); reportInteraction('grafana_dashboards_annotations_clicked', { - action: isAnnotationsEnabled ? 'disable' : 'enable', + action: e.currentTarget.checked ? 'enable' : 'disable', }); - onToggleAnnotations(); + onChange(e); }} + data-testid={selectors.EnableAnnotationsSwitch} /> { + {...register('enabledSwitch')} + onChange={(e) => { + const { onChange } = register('enabledSwitch'); reportInteraction('grafana_dashboards_public_enable_clicked', { - action: isPubDashEnabled ? 'disable' : 'enable', + action: e.currentTarget.checked ? 'enable' : 'disable', }); - - onToggleEnabled(); + onChange(e); }} + data-testid={selectors.EnableSwitch} /> @@ -74,7 +72,16 @@ export const Configuration = ({ }; const getStyles = (theme: GrafanaTheme2) => ({ + title: css` + margin-bottom: ${theme.spacing(2)}; + `, dashboardConfig: css` margin: ${theme.spacing(0, 0, 3, 0)}; `, + timeRange: css` + margin-bottom: ${theme.spacing(0)}; + `, + timeRangeDisabledText: css` + font-size: ${theme.typography.bodySmall.fontSize}; + `, }); diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx index 8e116400498..b1bdff1ab72 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx @@ -1,5 +1,6 @@ import { css } from '@emotion/css'; -import React, { useContext, useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo } from 'react'; +import { useForm } from 'react-hook-form'; import { Subscription } from 'rxjs'; import { GrafanaTheme2 } from '@grafana/data/src'; @@ -28,7 +29,6 @@ import { AcknowledgeCheckboxes } from 'app/features/dashboard/components/ShareMo import { Configuration } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/Configuration'; import { Description } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/Description'; import { - Acknowledgements, dashboardHasTemplateVariables, generatePublicDashboardUrl, getUnsupportedDashboardDatasources, @@ -45,6 +45,17 @@ import { ShareModal } from '../ShareModal'; interface Props extends ShareModalTabProps {} +type SharePublicDashboardAcknowledgmentInputs = { + publicAcknowledgment: boolean; + dataSourcesAcknowledgment: boolean; + usageAcknowledgment: boolean; +}; + +export type SharePublicDashboardInputs = { + isAnnotationsEnabled: boolean; + enabledSwitch: boolean; +} & SharePublicDashboardAcknowledgmentInputs; + export const SharePublicDashboard = (props: Props) => { const forceUpdate = useForceUpdate(); const styles = useStyles2(getStyles); @@ -65,20 +76,25 @@ export const SharePublicDashboard = (props: Props) => { skip: !hasPublicDashboard, }); + const { + reset, + handleSubmit, + watch, + register, + formState: { dirtyFields }, + } = useForm({ + defaultValues: { + publicAcknowledgment: false, + dataSourcesAcknowledgment: false, + usageAcknowledgment: false, + isAnnotationsEnabled: false, + enabledSwitch: false, + }, + }); + const [createPublicDashboard, { isLoading: isSaveLoading }] = useCreatePublicDashboardMutation(); const [updatePublicDashboard, { isLoading: isUpdateLoading }] = useUpdatePublicDashboardMutation(); - const [acknowledgements, setAcknowledgements] = useState({ - public: false, - datasources: false, - usage: false, - }); - const [enabledSwitch, setEnabledSwitch] = useState({ - isEnabled: false, - wasTouched: false, - }); - const [annotationsEnabled, setAnnotationsEnabled] = useState(false); - useEffect(() => { const eventSubs = new Subscription(); eventSubs.add(props.dashboard.events.subscribe(DashboardMetaChangedEvent, forceUpdate)); @@ -88,21 +104,21 @@ export const SharePublicDashboard = (props: Props) => { }, [props.dashboard.events, forceUpdate]); useEffect(() => { - if (publicDashboardPersisted(publicDashboard)) { - setAcknowledgements({ - public: true, - datasources: true, - usage: true, - }); - setAnnotationsEnabled(!!publicDashboard?.annotationsEnabled); - } - - setEnabledSwitch((prevState) => ({ ...prevState, isEnabled: !!publicDashboard?.isEnabled })); - }, [publicDashboard]); + const isPublicDashboardPersisted = publicDashboardPersisted(publicDashboard); + reset({ + publicAcknowledgment: isPublicDashboardPersisted, + dataSourcesAcknowledgment: isPublicDashboardPersisted, + usageAcknowledgment: isPublicDashboardPersisted, + isAnnotationsEnabled: publicDashboard?.annotationsEnabled, + enabledSwitch: publicDashboard?.isEnabled, + }); + }, [publicDashboard, reset]); const isLoading = isGetLoading || isSaveLoading || isUpdateLoading; const hasWritePermissions = contextSrv.hasAccess(AccessControlAction.DashboardsPublicWrite, isOrgAdmin()); - const acknowledged = acknowledgements.public && acknowledgements.datasources && acknowledgements.usage; + const acknowledged = + watch('publicAcknowledgment') && watch('dataSourcesAcknowledgment') && watch('usageAcknowledgment'); + const isSaveDisabled = useMemo( () => !hasWritePermissions || @@ -111,36 +127,37 @@ export const SharePublicDashboard = (props: Props) => { isLoading || isFetching || isGetError || - (!publicDashboardPersisted(publicDashboard) && !enabledSwitch.wasTouched), + (!publicDashboardPersisted(publicDashboard) && !dirtyFields.enabledSwitch), [ hasWritePermissions, acknowledged, props.dashboard, isLoading, isGetError, - enabledSwitch, publicDashboard, isFetching, + dirtyFields.enabledSwitch, ] ); + const isDeleteDisabled = isLoading || isFetching || isGetError; - const onSavePublicConfig = async () => { + const onSavePublicConfig = async (values: SharePublicDashboardInputs) => { reportInteraction('grafana_dashboards_public_create_clicked'); const req = { dashboard: props.dashboard, - payload: { ...publicDashboard!, isEnabled: enabledSwitch.isEnabled, annotationsEnabled }, + payload: { + ...publicDashboard!, + isEnabled: values.enabledSwitch, + annotationsEnabled: values.isAnnotationsEnabled, + }, }; // create or update based on whether we have existing uid hasPublicDashboard ? updatePublicDashboard(req) : createPublicDashboard(req); }; - const onAcknowledge = (field: string, checked: boolean) => { - setAcknowledgements((prevState) => ({ ...prevState, [field]: checked })); - }; - const onDismissDelete = () => { showModal(ShareModal, { dashboard: props.dashboard, @@ -188,28 +205,22 @@ export const SharePublicDashboard = (props: Props) => { This dashboard cannot be made public because it has template variables ) : ( - <> +


- setEnabledSwitch((prevState) => ({ isEnabled: !prevState.isEnabled, wasTouched: true })) - } - onToggleAnnotations={() => setAnnotationsEnabled((prevState) => !prevState)} /> - {publicDashboardPersisted(publicDashboard) && enabledSwitch.isEnabled && ( + {publicDashboardPersisted(publicDashboard) && watch('enabledSwitch') && ( { )} - {publicDashboard && hasWritePermissions && ( { {(isSaveLoading || isFetching) && } - + )} diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils.ts b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils.ts index f3cf9bdaf84..41a059b1a72 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils.ts +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils.ts @@ -20,12 +20,6 @@ export interface DashboardResponse { meta: DashboardMeta; } -export interface Acknowledgements { - public: boolean; - datasources: boolean; - usage: boolean; -} - // Instance methods export const dashboardHasTemplateVariables = (variables: VariableModel[]): boolean => { return variables.length > 0;