mirror of https://github.com/grafana/grafana
Navigation: Use navid and pagnav in alert rules pages (#55722)
* add navid and pagenav to edit/add/view alert rules * move ruleeditor smaller component to its own file * fix form alignments with new layout * fixed broken test * reuse AlertingPageWrapperpull/56317/head
parent
a25516fbe3
commit
4eea5d5190
@ -0,0 +1,24 @@ |
||||
import { css } from '@emotion/css'; |
||||
import React from 'react'; |
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data'; |
||||
import { Alert, LinkButton, useStyles2 } from '@grafana/ui'; |
||||
|
||||
interface AlertWarningProps { |
||||
title: string; |
||||
children: React.ReactNode; |
||||
} |
||||
export function AlertWarning({ title, children }: AlertWarningProps) { |
||||
return ( |
||||
<Alert className={useStyles2(warningStyles).warning} severity="warning" title={title}> |
||||
<p>{children}</p> |
||||
<LinkButton href="alerting/list">To rule list</LinkButton> |
||||
</Alert> |
||||
); |
||||
} |
||||
|
||||
const warningStyles = (theme: GrafanaTheme2) => ({ |
||||
warning: css` |
||||
margin: ${theme.spacing(4)}; |
||||
`,
|
||||
}); |
@ -0,0 +1,53 @@ |
||||
import React, { useEffect } from 'react'; |
||||
|
||||
import { Alert, LoadingPlaceholder } from '@grafana/ui'; |
||||
import { useCleanup } from 'app/core/hooks/useCleanup'; |
||||
import { useDispatch } from 'app/types'; |
||||
import { RuleIdentifier } from 'app/types/unified-alerting'; |
||||
|
||||
import { AlertWarning } from './AlertWarning'; |
||||
import { AlertRuleForm } from './components/rule-editor/AlertRuleForm'; |
||||
import { useIsRuleEditable } from './hooks/useIsRuleEditable'; |
||||
import { useUnifiedAlertingSelector } from './hooks/useUnifiedAlertingSelector'; |
||||
import { fetchEditableRuleAction } from './state/actions'; |
||||
import { initialAsyncRequestState } from './utils/redux'; |
||||
import * as ruleId from './utils/rule-id'; |
||||
|
||||
interface ExistingRuleEditorProps { |
||||
identifier: RuleIdentifier; |
||||
} |
||||
|
||||
export function ExistingRuleEditor({ identifier }: ExistingRuleEditorProps) { |
||||
useCleanup((state) => (state.unifiedAlerting.ruleForm.existingRule = initialAsyncRequestState)); |
||||
const { loading, result, error, dispatched } = useUnifiedAlertingSelector((state) => state.ruleForm.existingRule); |
||||
const dispatch = useDispatch(); |
||||
const { isEditable } = useIsRuleEditable(ruleId.ruleIdentifierToRuleSourceName(identifier), result?.rule); |
||||
|
||||
useEffect(() => { |
||||
if (!dispatched) { |
||||
dispatch(fetchEditableRuleAction(identifier)); |
||||
} |
||||
}, [dispatched, dispatch, identifier]); |
||||
|
||||
if (loading || isEditable === undefined) { |
||||
return <LoadingPlaceholder text="Loading rule..." />; |
||||
} |
||||
|
||||
if (error) { |
||||
return ( |
||||
<Alert severity="error" title="Failed to load rule"> |
||||
{error.message} |
||||
</Alert> |
||||
); |
||||
} |
||||
|
||||
if (!result) { |
||||
return <AlertWarning title="Rule not found">Sorry! This rule does not exist.</AlertWarning>; |
||||
} |
||||
|
||||
if (isEditable === false) { |
||||
return <AlertWarning title="Cannot edit rule">Sorry! You do not have permission to edit this rule.</AlertWarning>; |
||||
} |
||||
|
||||
return <AlertRuleForm existing={result} />; |
||||
} |
@ -1,115 +1,72 @@ |
||||
import { css } from '@emotion/css'; |
||||
import React, { FC, useEffect } from 'react'; |
||||
import React, { FC } from 'react'; |
||||
import { useAsync } from 'react-use'; |
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data'; |
||||
import { Alert, LinkButton, LoadingPlaceholder, useStyles2, withErrorBoundary } from '@grafana/ui'; |
||||
import { Page } from 'app/core/components/Page/Page'; |
||||
import { useCleanup } from 'app/core/hooks/useCleanup'; |
||||
import { NavModelItem } from '@grafana/data'; |
||||
import { withErrorBoundary } from '@grafana/ui'; |
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; |
||||
import { useDispatch } from 'app/types'; |
||||
import { RuleIdentifier } from 'app/types/unified-alerting'; |
||||
|
||||
import { AlertWarning } from './AlertWarning'; |
||||
import { ExistingRuleEditor } from './ExistingRuleEditor'; |
||||
import { AlertingPageWrapper } from './components/AlertingPageWrapper'; |
||||
import { AlertRuleForm } from './components/rule-editor/AlertRuleForm'; |
||||
import { useIsRuleEditable } from './hooks/useIsRuleEditable'; |
||||
import { useUnifiedAlertingSelector } from './hooks/useUnifiedAlertingSelector'; |
||||
import { fetchAllPromBuildInfoAction, fetchEditableRuleAction } from './state/actions'; |
||||
import { fetchAllPromBuildInfoAction } from './state/actions'; |
||||
import { useRulesAccess } from './utils/accessControlHooks'; |
||||
import { initialAsyncRequestState } from './utils/redux'; |
||||
import * as ruleId from './utils/rule-id'; |
||||
|
||||
interface ExistingRuleEditorProps { |
||||
identifier: RuleIdentifier; |
||||
} |
||||
|
||||
const ExistingRuleEditor: FC<ExistingRuleEditorProps> = ({ identifier }) => { |
||||
useCleanup((state) => (state.unifiedAlerting.ruleForm.existingRule = initialAsyncRequestState)); |
||||
const { loading, result, error, dispatched } = useUnifiedAlertingSelector((state) => state.ruleForm.existingRule); |
||||
const dispatch = useDispatch(); |
||||
const { isEditable } = useIsRuleEditable(ruleId.ruleIdentifierToRuleSourceName(identifier), result?.rule); |
||||
|
||||
useEffect(() => { |
||||
if (!dispatched) { |
||||
dispatch(fetchEditableRuleAction(identifier)); |
||||
} |
||||
}, [dispatched, dispatch, identifier]); |
||||
|
||||
if (loading || isEditable === undefined) { |
||||
return ( |
||||
<Page.Contents> |
||||
<LoadingPlaceholder text="Loading rule..." /> |
||||
</Page.Contents> |
||||
); |
||||
} |
||||
|
||||
if (error) { |
||||
return ( |
||||
<Page.Contents> |
||||
<Alert severity="error" title="Failed to load rule"> |
||||
{error.message} |
||||
</Alert> |
||||
</Page.Contents> |
||||
); |
||||
} |
||||
type RuleEditorProps = GrafanaRouteComponentProps<{ id?: string }>; |
||||
|
||||
if (!result) { |
||||
return <AlertWarning title="Rule not found">Sorry! This rule does not exist.</AlertWarning>; |
||||
} |
||||
const defaultPageNav: Partial<NavModelItem> = { |
||||
icon: 'bell', |
||||
id: 'alert-rule-view', |
||||
breadcrumbs: [{ title: 'Alert rules', url: 'alerting/list' }], |
||||
}; |
||||
|
||||
if (isEditable === false) { |
||||
return <AlertWarning title="Cannot edit rule">Sorry! You do not have permission to edit this rule.</AlertWarning>; |
||||
const getPageNav = (state: 'edit' | 'add') => { |
||||
if (state === 'edit') { |
||||
return { ...defaultPageNav, id: 'alert-rule-edit', text: 'Edit rule' }; |
||||
} else if (state === 'add') { |
||||
return { ...defaultPageNav, id: 'alert-rule-add', text: 'Add rule' }; |
||||
} |
||||
|
||||
return <AlertRuleForm existing={result} />; |
||||
return undefined; |
||||
}; |
||||
|
||||
type RuleEditorProps = GrafanaRouteComponentProps<{ id?: string }>; |
||||
|
||||
const RuleEditor: FC<RuleEditorProps> = ({ match }) => { |
||||
const dispatch = useDispatch(); |
||||
const { id } = match.params; |
||||
const identifier = ruleId.tryParse(id, true); |
||||
|
||||
const { loading } = useAsync(async () => { |
||||
const { loading = true } = useAsync(async () => { |
||||
await dispatch(fetchAllPromBuildInfoAction()); |
||||
}, [dispatch]); |
||||
|
||||
const { canCreateGrafanaRules, canCreateCloudRules, canEditRules } = useRulesAccess(); |
||||
|
||||
if (!identifier && !canCreateGrafanaRules && !canCreateCloudRules) { |
||||
return <AlertWarning title="Cannot create rules">Sorry! You are not allowed to create rules.</AlertWarning>; |
||||
} |
||||
|
||||
if (identifier && !canEditRules(identifier.ruleSourceName)) { |
||||
return <AlertWarning title="Cannot edit rules">Sorry! You are not allowed to edit rules.</AlertWarning>; |
||||
} |
||||
const getContent = () => { |
||||
if (loading) { |
||||
return; |
||||
} |
||||
|
||||
if (loading) { |
||||
return ( |
||||
<Page.Contents> |
||||
<LoadingPlaceholder text="Loading..." /> |
||||
</Page.Contents> |
||||
); |
||||
} |
||||
if (!identifier && !canCreateGrafanaRules && !canCreateCloudRules) { |
||||
return <AlertWarning title="Cannot create rules">Sorry! You are not allowed to create rules.</AlertWarning>; |
||||
} |
||||
|
||||
if (identifier) { |
||||
return <ExistingRuleEditor key={id} identifier={identifier} />; |
||||
} |
||||
if (identifier && !canEditRules(identifier.ruleSourceName)) { |
||||
return <AlertWarning title="Cannot edit rules">Sorry! You are not allowed to edit rules.</AlertWarning>; |
||||
} |
||||
|
||||
return <AlertRuleForm />; |
||||
}; |
||||
if (identifier) { |
||||
return <ExistingRuleEditor key={id} identifier={identifier} />; |
||||
} |
||||
|
||||
const AlertWarning: FC<{ title: string }> = ({ title, children }) => ( |
||||
<Alert className={useStyles2(warningStyles).warning} severity="warning" title={title}> |
||||
<p>{children}</p> |
||||
<LinkButton href="alerting/list">To rule list</LinkButton> |
||||
</Alert> |
||||
); |
||||
return <AlertRuleForm />; |
||||
}; |
||||
|
||||
const warningStyles = (theme: GrafanaTheme2) => ({ |
||||
warning: css` |
||||
margin: ${theme.spacing(4)}; |
||||
`,
|
||||
}); |
||||
return ( |
||||
<AlertingPageWrapper isLoading={loading} pageId="alert-list" pageNav={getPageNav(identifier ? 'edit' : 'add')}> |
||||
{getContent()} |
||||
</AlertingPageWrapper> |
||||
); |
||||
}; |
||||
|
||||
export default withErrorBoundary(RuleEditor, { style: 'page' }); |
||||
|
Loading…
Reference in new issue