diff --git a/packages/grafana-e2e-selectors/src/selectors/pages.ts b/packages/grafana-e2e-selectors/src/selectors/pages.ts index 4c97cac64c9..d82715816f1 100644 --- a/packages/grafana-e2e-selectors/src/selectors/pages.ts +++ b/packages/grafana-e2e-selectors/src/selectors/pages.ts @@ -181,7 +181,7 @@ export const Pages = { ShareDashboardModal: { shareButton: 'Share dashboard or panel', PublicDashboard: { - Tab: 'Tab Public Dashboard', + Tab: 'Tab Public dashboard', WillBePublicCheckbox: 'data-testid public dashboard will be public checkbox', LimitedDSCheckbox: 'data-testid public dashboard limited datasources checkbox', CostIncreaseCheckbox: 'data-testid public dashboard cost may increase checkbox', diff --git a/public/app/features/dashboard/components/ShareModal/ShareModal.tsx b/public/app/features/dashboard/components/ShareModal/ShareModal.tsx index a36b87087d4..3990a14183a 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareModal.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareModal.tsx @@ -62,7 +62,7 @@ function getTabs(props: Props) { } if (Boolean(config.featureToggles['publicDashboards'])) { - tabs.push({ label: 'Public Dashboard', value: 'share', component: SharePublicDashboard }); + tabs.push({ label: 'Public dashboard', value: 'share', component: SharePublicDashboard }); } return tabs; diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard.test.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard.test.tsx index 565ebeeb716..017d54dd808 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard.test.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard.test.tsx @@ -74,7 +74,7 @@ describe('SharePublic', () => { render( {}} />); expect(screen.getByRole('tablist')).toHaveTextContent('Link'); - expect(screen.getByRole('tablist')).not.toHaveTextContent('Public Dashboard'); + expect(screen.getByRole('tablist')).not.toHaveTextContent('Public dashboard'); }); it('renders share panel when public dashboards feature is enabled', async () => { @@ -90,14 +90,14 @@ describe('SharePublic', () => { await waitFor(() => screen.getByText('Link')); expect(screen.getByRole('tablist')).toHaveTextContent('Link'); - expect(screen.getByRole('tablist')).toHaveTextContent('Public Dashboard'); + expect(screen.getByRole('tablist')).toHaveTextContent('Public dashboard'); - fireEvent.click(screen.getByText('Public Dashboard')); + fireEvent.click(screen.getByText('Public dashboard')); await screen.findByText('Welcome to Grafana public dashboards alpha!'); }); - it('renders default time in inputs', async () => { + it('renders default relative time in input', async () => { config.featureToggles.publicDashboards = true; const mockDashboard = new DashboardModel({ uid: 'mockDashboardUid', @@ -107,17 +107,38 @@ describe('SharePublic', () => { }); expect(mockDashboard.time).toEqual({ from: 'now-6h', to: 'now' }); + //@ts-ignore - mockDashboard.originalTime = { from: 'test-from', to: 'test-to' }; + mockDashboard.originalTime = { from: 'now-6h', to: 'now' }; render( {}} />); await waitFor(() => screen.getByText('Link')); - fireEvent.click(screen.getByText('Public Dashboard')); + fireEvent.click(screen.getByText('Public dashboard')); await screen.findByText('Welcome to Grafana public dashboards alpha!'); - expect(screen.getByDisplayValue('test-from')).toBeInTheDocument(); - expect(screen.getByDisplayValue('test-to')).toBeInTheDocument(); + expect(screen.getByText('Last 6 hours')).toBeInTheDocument(); + }); + it('renders default absolute time in input 2', async () => { + config.featureToggles.publicDashboards = true; + const mockDashboard = new DashboardModel({ + uid: 'mockDashboardUid', + }); + const mockPanel = new PanelModel({ + id: 'mockPanelId', + }); + + mockDashboard.time = { from: '2022-08-30T03:00:00.000Z', to: '2022-09-04T02:59:59.000Z' }; + //@ts-ignore + mockDashboard.originalTime = { from: '2022-08-30T06:00:00.000Z', to: '2022-09-04T06:59:59.000Z' }; + + render( {}} />); + + await waitFor(() => screen.getByText('Link')); + fireEvent.click(screen.getByText('Public dashboard')); + + await screen.findByText('Welcome to Grafana public dashboards alpha!'); + expect(screen.getByText('2022-08-30 00:00:00 to 2022-09-04 01:59:59')).toBeInTheDocument(); }); // test checking if current version of dashboard in state is persisted to db diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard.tsx index d25b1afe658..9f45f0e137b 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard.tsx @@ -1,5 +1,7 @@ +import { css } from '@emotion/css'; import React, { useCallback, useEffect, useState } from 'react'; +import { GrafanaTheme2 } from '@grafana/data/src'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; import { reportInteraction } from '@grafana/runtime/src'; import { @@ -8,14 +10,19 @@ import { Checkbox, ClipboardButton, Field, + HorizontalGroup, FieldSet, Input, Label, LinkButton, Switch, + TimeRangeInput, + useStyles2, + VerticalGroup, } from '@grafana/ui'; import { notifyApp } from 'app/core/actions'; import { createErrorNotification } from 'app/core/copy/appNotification'; +import { getTimeRange } from 'app/features/dashboard/utils/timeRange'; import { dispatch } from 'app/store/store'; import { contextSrv } from '../../../../core/services/context_srv'; @@ -43,6 +50,7 @@ interface Acknowledgements { export const SharePublicDashboard = (props: Props) => { const dashboardVariables = props.dashboard.getVariables(); const selectors = e2eSelectors.pages.ShareDashboardModal.PublicDashboard; + const styles = useStyles2(getStyles); const hasWritePermissions = contextSrv.hasAccess(AccessControlAction.DashboardsPublicWrite, isOrgAdmin()); @@ -57,6 +65,11 @@ export const SharePublicDashboard = (props: Props) => { usage: false, }); + const timeRange = getTimeRange( + { from: props.dashboard.getDefaultTime().from, to: props.dashboard.getDefaultTime().to }, + props.dashboard.timezone + ); + useEffect(() => { reportInteraction('grafana_dashboards_public_share_viewed'); @@ -94,9 +107,7 @@ export const SharePublicDashboard = (props: Props) => { ); // check if all conditions have been acknowledged - const acknowledged = () => { - return acknowledgements.public && acknowledgements.datasources && acknowledgements.usage; - }; + const acknowledged = acknowledgements.public && acknowledgements.datasources && acknowledgements.usage; return ( <> @@ -115,133 +126,116 @@ export const SharePublicDashboard = (props: Props) => { To allow the current dashboard to be published publicly, toggle the switch. For now we do not support template variables or frontend datasources.

- We'd love your feedback. To share, please comment on this{' '} - - GitHub discussion - - . +

+ We'd love your feedback. To share, please comment on this{' '} + + GitHub discussion + + . +


-
- Before you click Save, please acknowledge the following information:
+
+

Before you click Save, please acknowledge the following information:

-
-
+ onAcknowledge('public', e.currentTarget.checked)} /> -
-
-
- onAcknowledge('datasources', e.currentTarget.checked)} - /> - -
-
- onAcknowledge('usage', e.currentTarget.checked)} - /> - -
-
+ + onAcknowledge('datasources', e.currentTarget.checked)} + /> + + + + onAcknowledge('usage', e.currentTarget.checked)} + /> + + +
+
-

Public Dashboard Configuration

-
- -
- From: - } - /> - To: - } - /> -
-
- - { - reportInteraction('grafana_dashboards_public_enable_clicked', { - action: publicDashboard?.isEnabled ? 'disable' : 'enable', - }); +

Public dashboard configuration

+
+ + + + {}} /> + + + + { + reportInteraction('grafana_dashboards_public_enable_clicked', { + action: publicDashboard?.isEnabled ? 'disable' : 'enable', + }); - setPublicDashboardConfig({ - ...publicDashboard, - isEnabled: !publicDashboard.isEnabled, - }); - }} - /> - -
- -
- {publicDashboardPersisted(publicDashboard) && publicDashboard.isEnabled && ( - - { - return generatePublicDashboardUrl(publicDashboard); - }} - > - Copy - - } + setPublicDashboardConfig({ + ...publicDashboard, + isEnabled: !publicDashboard.isEnabled, + }); + }} /> - - )} + + {publicDashboardPersisted(publicDashboard) && publicDashboard.isEnabled && ( + + generatePublicDashboardUrl(publicDashboard)} + > + Copy + + } + /> + + )} +
- {hasWritePermissions ? ( props.dashboard.hasUnsavedChanges() && ( { )}
@@ -265,3 +259,20 @@ export const SharePublicDashboard = (props: Props) => { ); }; + +const getStyles = (theme: GrafanaTheme2) => ({ + checkboxes: css` + margin: ${theme.spacing(2, 0)}; + `, + timeRange: css` + padding: ${theme.spacing(1, 1)}; + margin: ${theme.spacing(0, 0, 2, 0)}; + `, + dashboardConfig: css` + margin: ${theme.spacing(0, 0, 3, 0)}; + `, + publicUrl: css` + width: 100%; + margin-bottom: 0; + `, +}); diff --git a/public/app/features/dashboard/services/TimeSrv.ts b/public/app/features/dashboard/services/TimeSrv.ts index e9792b20e9e..4e8e18c6eb3 100644 --- a/public/app/features/dashboard/services/TimeSrv.ts +++ b/public/app/features/dashboard/services/TimeSrv.ts @@ -15,6 +15,7 @@ import appEvents from 'app/core/app_events'; import { config } from 'app/core/config'; import { contextSrv, ContextSrv } from 'app/core/services/context_srv'; import { getShiftedTimeRange, getZoomedTimeRange } from 'app/core/utils/timePicker'; +import { getTimeRange } from 'app/features/dashboard/utils/timeRange'; import { AbsoluteTimeEvent, ShiftTimeEvent, ShiftTimeEventDirection, ZoomOutEvent } from '../../../types/events'; import { TimeModel } from '../state/TimeModel'; @@ -316,19 +317,7 @@ export class TimeSrv { }; timeRange(): TimeRange { - // make copies if they are moment (do not want to return out internal moment, because they are mutable!) - const raw = { - from: isDateTime(this.time.from) ? dateTime(this.time.from) : this.time.from, - to: isDateTime(this.time.to) ? dateTime(this.time.to) : this.time.to, - }; - - const timezone = this.timeModel ? this.timeModel.getTimezone() : undefined; - - return { - from: dateMath.parse(raw.from, false, timezone, this.timeModel?.fiscalYearStartMonth)!, - to: dateMath.parse(raw.to, true, timezone, this.timeModel?.fiscalYearStartMonth)!, - raw: raw, - }; + return getTimeRange(this.time, this.timeModel); } zoomOut(factor: number, updateUrl = true) { diff --git a/public/app/features/dashboard/utils/timeRange.ts b/public/app/features/dashboard/utils/timeRange.ts new file mode 100644 index 00000000000..79cf1f10244 --- /dev/null +++ b/public/app/features/dashboard/utils/timeRange.ts @@ -0,0 +1,22 @@ +import { DateTime, TimeRange } from '@grafana/data'; +import { dateMath, dateTime, isDateTime } from '@grafana/data/src'; +import { TimeModel } from 'app/features/dashboard/state/TimeModel'; + +export const getTimeRange = ( + time: { from: DateTime | string; to: DateTime | string }, + timeModel?: TimeModel +): TimeRange => { + // make copies if they are moment (do not want to return out internal moment, because they are mutable!) + const raw = { + from: isDateTime(time.from) ? dateTime(time.from) : time.from, + to: isDateTime(time.to) ? dateTime(time.to) : time.to, + }; + + const timezone = timeModel ? timeModel.getTimezone() : undefined; + + return { + from: dateMath.parse(raw.from, false, timezone, timeModel?.fiscalYearStartMonth)!, + to: dateMath.parse(raw.to, true, timezone, timeModel?.fiscalYearStartMonth)!, + raw: raw, + }; +};