Skip to content

feat(aci): setup automation details #92521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions static/app/types/workflowEngine/automations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import type {DataConditionGroup} from 'sentry/types/workflowEngine/dataCondition

interface NewAutomation {
actionFilters: DataConditionGroup[];
config: {frequency?: number};
detectorIds: string[];
environment: string;
name: string;
triggers: DataConditionGroup;
disabled?: boolean;
}

export interface Automation extends Readonly<NewAutomation> {
readonly dateCreated: string;
readonly dateUpdated: string;
readonly id: string;
readonly lastTriggered: string;
}
1 change: 1 addition & 0 deletions static/app/utils/useParams.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ParamKeys =
| 'appId'
| 'appSlug'
| 'authId'
| 'automationId'
| 'codeId'
| 'dataExportId'
| 'dashboardId'
Expand Down
78 changes: 0 additions & 78 deletions static/app/views/automations/components/conditionsPanel.tsx

This file was deleted.

139 changes: 69 additions & 70 deletions static/app/views/automations/detail.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/* eslint-disable no-alert */
import {Fragment} from 'react';
import styled from '@emotion/styled';

import {Flex} from 'sentry/components/container/flex';
import {Button} from 'sentry/components/core/button';
import {LinkButton} from 'sentry/components/core/button/linkButton';
import {DateTime} from 'sentry/components/dateTime';
import {KeyValueTable, KeyValueTableRow} from 'sentry/components/keyValueTable';
import LoadingError from 'sentry/components/loadingError';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
import TimeSince from 'sentry/components/timeSince';
import {ActionsProvider} from 'sentry/components/workflowEngine/layout/actions';
Expand All @@ -15,79 +16,45 @@ import DetailLayout from 'sentry/components/workflowEngine/layout/detail';
import Section from 'sentry/components/workflowEngine/ui/section';
import {useWorkflowEngineFeatureGate} from 'sentry/components/workflowEngine/useWorkflowEngineFeatureGate';
import {IconEdit} from 'sentry/icons';
import {t} from 'sentry/locale';
import {t, tct} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Detector} from 'sentry/types/workflowEngine/detectors';
import getDuration from 'sentry/utils/duration/getDuration';
import useOrganization from 'sentry/utils/useOrganization';
import {useParams} from 'sentry/utils/useParams';
import AutomationHistoryList from 'sentry/views/automations/components/automationHistoryList';
import ConditionsPanel from 'sentry/views/automations/components/conditionsPanel';
import ConnectedMonitorsList from 'sentry/views/automations/components/connectedMonitorsList';
import {useAutomationQuery} from 'sentry/views/automations/hooks';
import {makeAutomationBasePathname} from 'sentry/views/automations/pathnames';

function HistoryAndConnectedMonitors() {
return (
<div>
<Section title={t('History')}>
<AutomationHistoryList history={[]} />
</Section>
<Section title={t('Connected Monitors')}>
<ConnectedMonitorsList monitors={[]} />
</Section>
</div>
);
}

function Details() {
return (
<Flex column gap={space(3)}>
<Flex column gap={space(1)}>
<SectionHeading>{t('Last Triggered')}</SectionHeading>
<span>
<TimeSince date={new Date()} />
</span>
</Flex>
<Flex column gap={space(1)}>
<SectionHeading>{t('Conditions')}</SectionHeading>
<ConditionsPanel
when_conditions={[
t('An issue escalates'),
t('A new event is captured for an issue'),
]}
if_conditions={[
t('Issue is assigned to no one'),
t('Current issue priority is high'),
]}
actions={[
t(
'Notify Suggested Assignees and if none can be found then notify Recently Active Members'
),
]}
/>
</Flex>
<Flex column gap={space(1)}>
<SectionHeading>{t('Details')}</SectionHeading>
<KeyValueTable>
<KeyValueTableRow
keyName={t('Date created')}
value={<DateTime date={new Date()} dateOnly year />}
/>
<KeyValueTableRow keyName={t('Created by')} value="Jane Doe" />
<KeyValueTableRow
keyName={t('Last modified')}
value={<TimeSince date={new Date()} />}
/>
<KeyValueTableRow keyName={t('Team')} value="Platform" />
</KeyValueTable>
</Flex>
</Flex>
);
}
import {useDetectorQueriesByIds} from 'sentry/views/detectors/hooks';

export default function AutomationDetail() {
const organization = useOrganization();
useWorkflowEngineFeatureGate({redirect: true});
const params = useParams<{automationId: string}>();

const {
data: automation,
isPending,
isError,
refetch,
} = useAutomationQuery(params.automationId);

const detectorsQuery = useDetectorQueriesByIds(automation?.detectorIds || []);
const detectors = detectorsQuery
.map(result => result.data)
.filter((detector): detector is Detector => detector !== undefined);

if (isPending) {
return <LoadingIndicator />;
}

if (isError) {
return <LoadingError onRetry={refetch} />;
}

return (
<SentryDocumentTitle title={t('Automation')} noSuffix>
<SentryDocumentTitle title={automation.name} noSuffix>
<BreadcrumbsProvider
crumb={{
label: t('Automations'),
Expand All @@ -97,10 +64,47 @@ export default function AutomationDetail() {
<ActionsProvider actions={<Actions />}>
<DetailLayout>
<DetailLayout.Main>
<HistoryAndConnectedMonitors />
<Section title={t('History')}>
<AutomationHistoryList history={[]} />
</Section>
<Section title={t('Connected Monitors')}>
<ConnectedMonitorsList monitors={detectors} />
</Section>
</DetailLayout.Main>
<DetailLayout.Sidebar>
<Details />
<Section title={t('Last Triggered')}>
{automation.lastTriggered ? (
<Flex gap={space(1)}>
<TimeSince date={automation.lastTriggered} />
<Flex>
(<DateTime date={automation.lastTriggered} year timeZone />)
</Flex>
</Flex>
) : (
t('Never')
)}
</Section>
<Section title={t('Environment')}>
{automation.environment || t('All environments')}
</Section>
<Section title={t('Action Interval')}>
{tct('Every [frequency]', {
frequency: getDuration((automation.config.frequency || 0) * 60),
})}
</Section>
<Section title={t('Details')}>
<KeyValueTable>
<KeyValueTableRow
keyName={t('Date created')}
value={<DateTime date={automation.dateCreated} dateOnly year />}
/>
<KeyValueTableRow keyName={t('Created by')} value="placeholder" />
<KeyValueTableRow
keyName={t('Last modified')}
value={<TimeSince date={automation.dateUpdated} />}
/>
</KeyValueTable>
</Section>
</DetailLayout.Sidebar>
</DetailLayout>
</ActionsProvider>
Expand All @@ -124,8 +128,3 @@ function Actions() {
</Fragment>
);
}

const SectionHeading = styled('h4')`
font-size: ${p => p.theme.fontSizeMedium};
margin: 0;
`;
21 changes: 17 additions & 4 deletions static/app/views/automations/hooks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import type {ApiQueryKey} from 'sentry/utils/queryClient';
import {useApiQuery} from 'sentry/utils/queryClient';
import useOrganization from 'sentry/utils/useOrganization';

const makeAutomationsQueryKey = (orgSlug: string): ApiQueryKey => [
`/organizations/${orgSlug}/workflows/`,
];

const makeAutomationQueryKey = (orgSlug: string, automationId: string): ApiQueryKey => [
`/organizations/${orgSlug}/workflows/${automationId}/`,
];

interface UseAutomationsQueryOptions {
query?: string;
sort?: string;
Expand All @@ -21,6 +29,15 @@ export function useAutomationsQuery(_options: UseAutomationsQueryOptions = {}) {
});
}

export function useAutomationQuery(automationId: string) {
const {slug} = useOrganization();

return useApiQuery<Automation>(makeAutomationQueryKey(slug, automationId), {
staleTime: 0,
retry: false,
});
}

export function useDataConditionsQuery(groupType: DataConditionHandlerGroupType) {
const {slug} = useOrganization();

Expand All @@ -33,10 +50,6 @@ export function useDataConditionsQuery(groupType: DataConditionHandlerGroupType)
);
}

const makeAutomationsQueryKey = (orgSlug: string): ApiQueryKey => [
`/organizations/${orgSlug}/workflows/`,
];

export function useAvailableActionsQuery() {
const {slug} = useOrganization();

Expand Down
Loading