import { css, cx } from '@emotion/css'; import { useDialog } from '@react-aria/dialog'; import { FocusScope } from '@react-aria/focus'; import { useOverlay } from '@react-aria/overlays'; import React, { useCallback, useMemo, useRef } from 'react'; import { Link } from 'react-router-dom'; import { GrafanaTheme2, locationUtil } from '@grafana/data'; import { locationService, reportInteraction } from '@grafana/runtime'; import { Button, CustomScrollbar, Icon, IconName, PageToolbar, stylesFactory, useForceUpdate } from '@grafana/ui'; import config from 'app/core/config'; import { contextSrv } from 'app/core/services/context_srv'; import { AccessControlAction } from 'app/types'; import { VariableEditorContainer } from '../../../variables/editor/VariableEditorContainer'; import { DashboardModel } from '../../state/DashboardModel'; import { AccessControlDashboardPermissions } from '../DashboardPermissions/AccessControlDashboardPermissions'; import { DashboardPermissions } from '../DashboardPermissions/DashboardPermissions'; import { SaveDashboardAsButton, SaveDashboardButton } from '../SaveDashboard/SaveDashboardButton'; import { AnnotationsSettings } from './AnnotationsSettings'; import { GeneralSettings } from './GeneralSettings'; import { JsonEditorSettings } from './JsonEditorSettings'; import { LinksSettings } from './LinksSettings'; import { VersionsSettings } from './VersionsSettings'; export interface Props { dashboard: DashboardModel; editview: string; } export interface SettingsPage { id: string; title: string; icon: IconName; component: React.ReactNode; } const onClose = () => locationService.partial({ editview: null }); const MakeEditable = (props: { onMakeEditable: () => any }) => (
Dashboard not editable
); export function DashboardSettings({ dashboard, editview }: Props) { const ref = useRef(null); const { overlayProps } = useOverlay( { isOpen: true, onClose, }, ref ); const { dialogProps } = useDialog( { 'aria-label': 'Dashboard settings', }, ref ); const forceUpdate = useForceUpdate(); const onMakeEditable = useCallback(() => { dashboard.editable = true; dashboard.meta.canMakeEditable = false; dashboard.meta.canEdit = true; dashboard.meta.canSave = true; forceUpdate(); }, [dashboard, forceUpdate]); const pages = useMemo((): SettingsPage[] => { const pages: SettingsPage[] = []; if (dashboard.meta.canEdit) { pages.push({ title: 'General', id: 'settings', icon: 'sliders-v-alt', component: , }); pages.push({ title: 'Annotations', id: 'annotations', icon: 'comment-alt', component: , }); pages.push({ title: 'Variables', id: 'templating', icon: 'calculator-alt', component: , }); pages.push({ title: 'Links', id: 'links', icon: 'link', component: , }); } if (dashboard.meta.canMakeEditable) { pages.push({ title: 'General', icon: 'sliders-v-alt', id: 'settings', component: , }); } if (dashboard.id && dashboard.meta.canSave) { pages.push({ title: 'Versions', id: 'versions', icon: 'history', component: , }); } if (dashboard.id && dashboard.meta.canAdmin) { if (!config.rbacEnabled) { pages.push({ title: 'Permissions', id: 'permissions', icon: 'lock', component: , }); } else if (contextSrv.hasPermission(AccessControlAction.DashboardsPermissionsRead)) { pages.push({ title: 'Permissions', id: 'permissions', icon: 'lock', component: , }); } } pages.push({ title: 'JSON Model', id: 'dashboard_json', icon: 'arrow', component: , }); return pages; }, [dashboard, onMakeEditable]); const onPostSave = () => { dashboard.meta.hasUnsavedFolderChange = false; }; const folderTitle = dashboard.meta.folderTitle; const currentPage = pages.find((page) => page.id === editview) ?? pages[0]; const canSaveAs = contextSrv.hasEditPermissionInFolders; const canSave = dashboard.meta.canSave; const styles = getStyles(config.theme2); return (
{currentPage.component}
); } const getStyles = stylesFactory((theme: GrafanaTheme2) => ({ scrollInner: css` min-width: 100%; display: flex; `, settingsWrapper: css` margin: ${theme.spacing(0, 2, 2)}; display: flex; flex-grow: 1; `, settingsContent: css` flex-grow: 1; height: 100%; padding: 32px; border: 1px solid ${theme.colors.border.weak}; background: ${theme.colors.background.primary}; border-radius: ${theme.shape.borderRadius()}; `, }));