|
@@ -1,16 +1,21 @@
|
|
|
+import {useCallback} from 'react';
|
|
|
import type {RouteComponentProps} from 'react-router';
|
|
|
|
|
|
import {addErrorMessage} from 'sentry/actionCreators/indicator';
|
|
|
import {Alert} from 'sentry/components/alert';
|
|
|
+import LoadingError from 'sentry/components/loadingError';
|
|
|
+import LoadingIndicator from 'sentry/components/loadingIndicator';
|
|
|
+import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
|
|
|
import {t} from 'sentry/locale';
|
|
|
import type {Organization} from 'sentry/types/organization';
|
|
|
import type {Project} from 'sentry/types/project';
|
|
|
import {metric} from 'sentry/utils/analytics';
|
|
|
+import {useApiQuery} from 'sentry/utils/queryClient';
|
|
|
import routeTitleGen from 'sentry/utils/routeTitle';
|
|
|
+import {useNavigate} from 'sentry/utils/useNavigate';
|
|
|
import {normalizeUrl} from 'sentry/utils/withDomainRequired';
|
|
|
import RuleForm from 'sentry/views/alerts/rules/metric/ruleForm';
|
|
|
import type {MetricRule} from 'sentry/views/alerts/rules/metric/types';
|
|
|
-import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView';
|
|
|
|
|
|
type RouteParams = {
|
|
|
projectId: string;
|
|
@@ -24,91 +29,83 @@ type Props = {
|
|
|
userTeamIds: string[];
|
|
|
} & RouteComponentProps<RouteParams, {}>;
|
|
|
|
|
|
-type State = {
|
|
|
- actions: Map<string, any>;
|
|
|
- rule: MetricRule; // This is temp
|
|
|
-} & DeprecatedAsyncView['state'];
|
|
|
-
|
|
|
-class MetricRulesEdit extends DeprecatedAsyncView<Props, State> {
|
|
|
- getDefaultState() {
|
|
|
- return {
|
|
|
- ...super.getDefaultState(),
|
|
|
- actions: new Map(),
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- getTitle(): string {
|
|
|
- const {organization, project} = this.props;
|
|
|
- const {rule} = this.state;
|
|
|
- const ruleName = rule?.name;
|
|
|
-
|
|
|
- return routeTitleGen(
|
|
|
- ruleName ? t('Alert - %s', ruleName) : '',
|
|
|
- organization.slug,
|
|
|
- false,
|
|
|
- project?.slug
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- getEndpoints(): ReturnType<DeprecatedAsyncView['getEndpoints']> {
|
|
|
- const {organization} = this.props;
|
|
|
- const {ruleId} = this.props.params;
|
|
|
-
|
|
|
- return [['rule', `/organizations/${organization.slug}/alert-rules/${ruleId}/`]];
|
|
|
- }
|
|
|
-
|
|
|
- onRequestSuccess({stateKey, data}) {
|
|
|
- if (stateKey === 'rule' && data.name) {
|
|
|
- this.props.onChangeTitle(data.name);
|
|
|
+export function MetricRulesEdit({
|
|
|
+ organization,
|
|
|
+ params,
|
|
|
+ project,
|
|
|
+ userTeamIds,
|
|
|
+ onChangeTitle,
|
|
|
+ ...props
|
|
|
+}: Props) {
|
|
|
+ const navigate = useNavigate();
|
|
|
+
|
|
|
+ const {
|
|
|
+ isLoading,
|
|
|
+ isError,
|
|
|
+ data: rule,
|
|
|
+ error,
|
|
|
+ } = useApiQuery<MetricRule>(
|
|
|
+ [`/organizations/${organization.slug}/alert-rules/${params.ruleId}/`],
|
|
|
+ {
|
|
|
+ staleTime: 0,
|
|
|
+ retry: false,
|
|
|
+ onSuccess: data => {
|
|
|
+ onChangeTitle(data[0]?.name ?? '');
|
|
|
+ },
|
|
|
+ onError: ({responseText}) => {
|
|
|
+ const {detail} = JSON.parse(responseText ?? '');
|
|
|
+ if (detail) {
|
|
|
+ addErrorMessage(detail);
|
|
|
+ }
|
|
|
+ },
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- onLoadAllEndpointsSuccess() {
|
|
|
- const {rule} = this.state;
|
|
|
- if (rule?.errors) {
|
|
|
- (rule?.errors || []).map(({detail}) => addErrorMessage(detail, {append: true}));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- handleSubmitSuccess = () => {
|
|
|
- const {organization, router} = this.props;
|
|
|
- const {ruleId} = this.props.params;
|
|
|
+ );
|
|
|
|
|
|
+ const handleSubmitSuccess = useCallback(() => {
|
|
|
metric.endSpan({name: 'saveAlertRule'});
|
|
|
- router.push(
|
|
|
+ navigate(
|
|
|
normalizeUrl({
|
|
|
- pathname: `/organizations/${organization.slug}/alerts/rules/details/${ruleId}/`,
|
|
|
+ pathname: `/organizations/${organization.slug}/alerts/rules/details/${params.ruleId}/`,
|
|
|
})
|
|
|
);
|
|
|
- };
|
|
|
+ }, [params.ruleId, navigate, organization.slug]);
|
|
|
+
|
|
|
+ if (isLoading) {
|
|
|
+ return <LoadingIndicator />;
|
|
|
+ }
|
|
|
|
|
|
- renderError(error?: Error, disableLog = false): React.ReactNode {
|
|
|
- const {errors} = this.state;
|
|
|
- const notFound = Object.values(errors).find(resp => resp && resp.status === 404);
|
|
|
- if (notFound) {
|
|
|
+ if (isError) {
|
|
|
+ if (error?.status === 404) {
|
|
|
return (
|
|
|
<Alert type="error" showIcon>
|
|
|
{t('This alert rule could not be found.')}
|
|
|
</Alert>
|
|
|
);
|
|
|
}
|
|
|
- return super.renderError(error, disableLog);
|
|
|
+
|
|
|
+ return <LoadingError />;
|
|
|
}
|
|
|
|
|
|
- renderBody() {
|
|
|
- const {ruleId} = this.props.params;
|
|
|
- const {rule} = this.state;
|
|
|
+ const title = routeTitleGen(
|
|
|
+ rule?.name ? t('Alert - %s', rule?.name) : '',
|
|
|
+ organization.slug,
|
|
|
+ false,
|
|
|
+ project?.slug
|
|
|
+ );
|
|
|
|
|
|
- return (
|
|
|
+ return (
|
|
|
+ <SentryDocumentTitle title={title}>
|
|
|
<RuleForm
|
|
|
- {...this.props}
|
|
|
- ruleId={ruleId}
|
|
|
+ {...props}
|
|
|
+ params={params}
|
|
|
+ project={project}
|
|
|
+ userTeamIds={userTeamIds}
|
|
|
+ organization={organization}
|
|
|
+ ruleId={params.ruleId}
|
|
|
rule={rule}
|
|
|
- onSubmitSuccess={this.handleSubmitSuccess}
|
|
|
+ onSubmitSuccess={handleSubmitSuccess}
|
|
|
disableProjectSelector
|
|
|
/>
|
|
|
- );
|
|
|
- }
|
|
|
+ </SentryDocumentTitle>
|
|
|
+ );
|
|
|
}
|
|
|
-
|
|
|
-export default MetricRulesEdit;
|