diff --git a/static/app/components/group/inboxBadges/shortId.tsx b/static/app/components/group/inboxBadges/shortId.tsx
index 88f5873beead92..6c4ef3a912c1a1 100644
--- a/static/app/components/group/inboxBadges/shortId.tsx
+++ b/static/app/components/group/inboxBadges/shortId.tsx
@@ -21,7 +21,7 @@ function ShortId({shortId, avatar}: Props) {
export default ShortId;
-const Wrapper = styled('div')`
+export const Wrapper = styled('div')`
display: flex;
align-items: center;
white-space: nowrap;
diff --git a/static/app/components/workflowEngine/gridCell/automationTitleCell.tsx b/static/app/components/workflowEngine/gridCell/automationTitleCell.tsx
deleted file mode 100644
index cf86ed86d6c711..00000000000000
--- a/static/app/components/workflowEngine/gridCell/automationTitleCell.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import {css} from '@emotion/react';
-import styled from '@emotion/styled';
-
-import ProjectBadge from 'sentry/components/idBadge/projectBadge';
-import Link from 'sentry/components/links/link';
-import {space} from 'sentry/styles/space';
-import type {AvatarProject} from 'sentry/types/project';
-
-export type AutomationTitleCellProps = {
- id: string;
- name: string;
- project: AvatarProject;
-};
-
-export function AutomationTitleCell({id, name, project}: AutomationTitleCellProps) {
- return (
-
-
- {name}
-
-
-
- );
-}
-
-const StyledProjectBadge = styled(ProjectBadge)`
- color: ${p => p.theme.subText};
-`;
-
-const Name = styled('strong')`
- color: ${p => p.theme.textColor};
-`;
-
-const TitleWrapper = styled(Link)`
- display: flex;
- flex-direction: column;
- gap: ${space(0.5)};
-
- &:hover ${Name} {
- color: ${p => p.theme.textColor};
- text-decoration: underline;
- }
-`;
diff --git a/static/app/components/workflowEngine/gridCell/monitorsCell.tsx b/static/app/components/workflowEngine/gridCell/connectionCell.tsx
similarity index 85%
rename from static/app/components/workflowEngine/gridCell/monitorsCell.tsx
rename to static/app/components/workflowEngine/gridCell/connectionCell.tsx
index 54cba1e1ba712d..a394882625f7e6 100644
--- a/static/app/components/workflowEngine/gridCell/monitorsCell.tsx
+++ b/static/app/components/workflowEngine/gridCell/connectionCell.tsx
@@ -6,32 +6,32 @@ import {Hovercard} from 'sentry/components/hovercard';
import ProjectBadge from 'sentry/components/idBadge/projectBadge';
import Link from 'sentry/components/links/link';
import {EmptyCell} from 'sentry/components/workflowEngine/gridCell/emptyCell';
-import {tn} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {AvatarProject} from 'sentry/types/project';
-export type Monitor = {
- id: string;
+export type Item = {
+ link: string;
name: string;
project: AvatarProject;
description?: string;
};
-type MonitorsCellProps = {
- monitors: Monitor[];
+export type ConnectionCellProps = {
+ items: Item[];
+ renderText: (count: number) => string;
};
-export function MonitorsCell({monitors}: MonitorsCellProps) {
- if (monitors.length === 0) {
+export function ConnectionCell({items, renderText}: ConnectionCellProps) {
+ if (items.length === 0) {
return ;
}
return (
(
-
+ body={items.map(({name, project, description, link}, index) => (
+
{index > 0 && }
-
+
{name}
))}
>
- {tn('%s monitor', '%s monitors', monitors.length)}
+ {renderText(items.length)}
);
diff --git a/static/app/components/workflowEngine/gridCell/index.spec.tsx b/static/app/components/workflowEngine/gridCell/index.spec.tsx
index c685625a1e8abf..333ea5df3fd53a 100644
--- a/static/app/components/workflowEngine/gridCell/index.spec.tsx
+++ b/static/app/components/workflowEngine/gridCell/index.spec.tsx
@@ -3,7 +3,8 @@ import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
import {TooltipContext} from 'sentry/components/tooltip';
import {ActionCell} from './actionCell';
-import {MonitorsCell} from './monitorsCell';
+import {ConnectionCell} from './connectionCell';
+import {NumberCell} from './numberCell';
import {TimeAgoCell} from './timeAgoCell';
describe('Action Cell Component', function () {
@@ -38,31 +39,38 @@ describe('Time Ago Cell Component', function () {
});
});
-const renderMonitorCell = () => {
+const renderConnectionCell = (renderText: (count: number) => string) => {
render(
-
);
};
-describe('Monitors Cell Component', function () {
- it('renders children and context values', function () {
- renderMonitorCell();
+describe('Connection Cell Component', function () {
+ it('renders monitors', function () {
+ renderConnectionCell(count => count + ' monitor');
const text = screen.getByText('1 monitor');
expect(text).toBeInTheDocument();
});
+ it('renders automations', function () {
+ renderConnectionCell(count => count + ' automation');
+ const text = screen.getByText('1 automation');
+ expect(text).toBeInTheDocument();
+ });
+
it('renders hovercard', async function () {
- renderMonitorCell();
+ renderConnectionCell(count => count + ' monitor');
const span = screen.getByText('1 monitor');
expect(span).toBeInTheDocument();
@@ -72,3 +80,12 @@ describe('Monitors Cell Component', function () {
expect(await screen.findByText('transaction.duration')).toBeInTheDocument();
});
});
+
+describe('Number Cell Component', function () {
+ it('renders', () => {
+ render();
+
+ const text = screen.getByText('3');
+ expect(text).toBeInTheDocument();
+ });
+});
diff --git a/static/app/components/workflowEngine/gridCell/index.stories.tsx b/static/app/components/workflowEngine/gridCell/index.stories.tsx
index b878c44ac756c1..1b93badc395379 100644
--- a/static/app/components/workflowEngine/gridCell/index.stories.tsx
+++ b/static/app/components/workflowEngine/gridCell/index.stories.tsx
@@ -7,103 +7,130 @@ import {
ActionCell,
} from 'sentry/components/workflowEngine/gridCell/actionCell';
import {
- AutomationTitleCell,
- type AutomationTitleCellProps,
-} from 'sentry/components/workflowEngine/gridCell/automationTitleCell';
-import type {Monitor} from 'sentry/components/workflowEngine/gridCell/monitorsCell';
-import {MonitorsCell} from 'sentry/components/workflowEngine/gridCell/monitorsCell';
+ ConnectionCell,
+ type ConnectionCellProps,
+} from 'sentry/components/workflowEngine/gridCell/connectionCell';
+import {NumberCell} from 'sentry/components/workflowEngine/gridCell/numberCell';
import {TimeAgoCell} from 'sentry/components/workflowEngine/gridCell/timeAgoCell';
+import {
+ TitleCell,
+ type TitleCellProps,
+} from 'sentry/components/workflowEngine/gridCell/titleCell';
+import {tn} from 'sentry/locale';
import storyBook from 'sentry/stories/storyBook';
type ExampleAutomation = {
action: Action[];
- automation: AutomationTitleCellProps;
- monitors: Monitor[];
+ linkedItems: ConnectionCellProps;
+ openIssues: number;
timeAgo: Date | null;
+ title: TitleCellProps;
};
export default storyBook('Grid Cell Components', story => {
const data: ExampleAutomation[] = [
{
- automation: {
- id: '1',
+ title: {
name: 'Slack suggested assignees',
project: {slug: 'sentry', platform: 'python'},
+ link: '/monitors/1',
},
action: ['slack'],
timeAgo: new Date(),
- monitors: [
- {
- name: 'my monitor',
- id: 'abc123',
- project: {slug: 'ngrok-luver', platform: 'ruby'},
- },
- ],
+ linkedItems: {
+ items: [
+ {
+ name: 'my monitor',
+ project: {slug: 'ngrok-luver', platform: 'ruby'},
+ link: 'monitors/abc123',
+ },
+ ],
+ renderText: count => tn('%s monitor', '%s monitors', count),
+ },
+ openIssues: 3,
},
{
- automation: {
- id: '2',
+ title: {
name: 'Send Discord notification',
- project: {slug: 'javascript', platform: 'javascript'},
+ project: {
+ slug: 'javascript',
+ platform: 'javascript',
+ },
+ details: ['transaction.duration', '2s warn, 2.5s critical threshold'],
+ link: '/monitors/2',
},
action: ['discord'],
timeAgo: new Date(Date.now() - 2 * 60 * 60 * 1000),
- monitors: [
- {
- name: '/endpoint',
- id: 'def456',
- project: {slug: 'javascript', platform: 'javascript'},
- description: 'transaction.duration',
- },
- {
- name: '/checkout',
- id: 'ghi789',
- project: {slug: 'javascript', platform: 'javascript'},
- description: 'transaction.duration',
- },
- ],
+ linkedItems: {
+ items: [
+ {
+ name: '/endpoint',
+ project: {slug: 'javascript', platform: 'javascript'},
+ description: 'transaction.duration',
+ link: 'monitors/def456',
+ },
+ {
+ name: '/checkout',
+ project: {slug: 'javascript', platform: 'javascript'},
+ description: 'transaction.duration',
+ link: 'monitors/ghi789',
+ },
+ ],
+ renderText: count => tn('%s monitor', '%s monitors', count),
+ },
+ openIssues: 1,
},
{
- automation: {
- id: '3',
+ title: {
name: 'Email suggested assignees',
project: {slug: 'javascript', platform: 'javascript'},
+ details: ['Every hour'],
+ link: '/monitors/3',
},
action: ['email'],
timeAgo: new Date(Date.now() - 25 * 60 * 60 * 1000),
- monitors: [
- {
- name: 'test monitor',
- id: 'jkl012',
- project: {slug: 'bruh', platform: 'android'},
- description: 'transaction.duration',
- },
- {
- name: 'test python monitor',
- id: 'mno345',
- project: {slug: 'bruh.py', platform: 'python'},
- },
- {
- name: 'test swift monitor',
- id: 'pqr678',
- project: {slug: 'bruh.swift', platform: 'swift'},
- },
- ],
+ linkedItems: {
+ items: [
+ {
+ name: 'test automation',
+ project: {slug: 'bruh', platform: 'android'},
+ description: 'transaction.duration',
+ link: 'automations/jkl012',
+ },
+ {
+ name: 'test python automation',
+ project: {slug: 'bruh.py', platform: 'python'},
+ link: 'automations/mno345',
+ },
+ {
+ name: 'test swift automation',
+ project: {slug: 'bruh.swift', platform: 'swift'},
+ link: 'automations/pqr678',
+ },
+ ],
+ renderText: count => tn('%s automation', '%s automations', count),
+ },
+ openIssues: 0,
},
{
- automation: {
- id: '4',
+ title: {
name: 'Send notification',
project: {slug: 'android', platform: 'android'},
+ link: '/monitors/4',
+ disabled: true,
},
action: ['slack', 'discord', 'email'],
timeAgo: null,
- monitors: [],
+ linkedItems: {
+ items: [],
+ renderText: count => tn('%s automation', '%s automations', count),
+ },
+ openIssues: 0,
},
];
- const automationTitleTable: Array> = [
- {key: 'automation', name: 'Name', width: 200},
+ const TitleTable: Array> = [
+ {key: 'title', name: 'Name', width: 200},
];
const actionTable: Array> = [
@@ -114,8 +141,12 @@ export default storyBook('Grid Cell Components', story => {
{key: 'timeAgo', name: 'Last Triggered', width: 200},
];
- const monitorsTable: Array> = [
- {key: 'monitors', name: 'Connected Monitors', width: 200},
+ const linkedGroupsTable: Array> = [
+ {key: 'linkedItems', name: 'Connected Monitors/Automations', width: 200},
+ ];
+
+ const openIssuesTable: Array> = [
+ {key: 'openIssues', name: 'Open Issues', width: 200},
];
const renderHeadCell = (column: GridColumnOrder) => column.name;
@@ -125,30 +156,39 @@ export default storyBook('Grid Cell Components', story => {
dataRow: ExampleAutomation
) => {
switch (column.key) {
- case 'automation':
+ case 'title':
return (
-
);
case 'action':
return ;
case 'timeAgo':
return ;
- case 'monitors':
- return ;
+ case 'linkedItems':
+ return (
+
+ );
+ case 'openIssues':
+ return ;
default:
return null;
}
};
- story('AutomationTitleCell', () => (
+ story('TitleCell', () => (
{
));
- story('MonitorsCell', () => (
+ story('ConnectionCell', () => (
+
+
+
+ ));
+
+ story('NumberCell', () => (
;
+ }
+ return (
+
+ }
+ />
+
+
+ {t('Last seen')}
+
+
+
+ );
+}
+
+const IssueWrapper = styled(Link)<{disabled: boolean}>`
+ color: ${p => (p.disabled ? p.theme.disabled : p.theme.textColor)};
+ font-size: ${p => p.theme.fontSizeMedium};
+
+ ${p =>
+ !p.disabled &&
+ `
+ &:hover {
+ color: ${p.theme.textColor};
+ }
+ `}
+`;
+
+const LastSeenWrapper = styled(Flex)`
+ color: ${p => p.theme.subText};
+`;
diff --git a/static/app/components/workflowEngine/gridCell/numberCell.tsx b/static/app/components/workflowEngine/gridCell/numberCell.tsx
new file mode 100644
index 00000000000000..da19abb2f351ee
--- /dev/null
+++ b/static/app/components/workflowEngine/gridCell/numberCell.tsx
@@ -0,0 +1,7 @@
+type NumberCellProps = {
+ number: number;
+};
+
+export function NumberCell({number}: NumberCellProps) {
+ return {number}
;
+}
diff --git a/static/app/components/workflowEngine/gridCell/titleCell.tsx b/static/app/components/workflowEngine/gridCell/titleCell.tsx
new file mode 100644
index 00000000000000..0221a6993d1860
--- /dev/null
+++ b/static/app/components/workflowEngine/gridCell/titleCell.tsx
@@ -0,0 +1,108 @@
+import {Fragment} from 'react';
+import {css} from '@emotion/react';
+import styled from '@emotion/styled';
+
+import ProjectBadge from 'sentry/components/idBadge/projectBadge';
+import Link from 'sentry/components/links/link';
+import {space} from 'sentry/styles/space';
+import type {AvatarProject} from 'sentry/types/project';
+
+export type TitleCellProps = {
+ link: string;
+ name: string;
+ project: AvatarProject;
+ details?: string[];
+ disabled?: boolean;
+};
+
+export function TitleCell({
+ name,
+ project,
+ details,
+ link,
+ disabled = false,
+}: TitleCellProps) {
+ return (
+
+
+
+ {name}
+ {disabled && — Disabled}
+
+
+
+ {details?.map((detail, index) => (
+
+
+ {detail}
+
+ ))}
+
+
+
+ );
+}
+
+const Name = styled('div')<{disabled: boolean}>`
+ color: ${p => p.theme.textColor};
+ display: flex;
+ flex-direction: row;
+ gap: ${space(0.5)};
+
+ ${p =>
+ p.disabled &&
+ `
+ color: ${p.theme.disabled};
+ `}
+`;
+
+const TitleWrapper = styled(Link)<{disabled: boolean}>`
+ display: flex;
+ flex-direction: column;
+ gap: ${space(0.5)};
+
+ ${p =>
+ !p.disabled &&
+ `
+ &:hover ${Name} {
+ color: ${p.theme.textColor};
+ text-decoration: underline;
+ }
+ `}
+`;
+
+const DetailsWrapper = styled('div')`
+ display: inline-grid;
+ grid-auto-flow: column dense;
+ gap: ${space(0.75)};
+ justify-content: start;
+ align-items: center;
+ color: ${p => p.theme.subText};
+ min-width: 500px;
+ white-space: nowrap;
+ line-height: 1.2;
+
+ @media (min-width: ${p => p.theme.breakpoints.xlarge}) {
+ line-height: 1;
+ }
+`;
+
+const StyledProjectBadge = styled(ProjectBadge)`
+ color: ${p => p.theme.subText};
+`;
+
+const Separator = styled('span')`
+ height: 10px;
+ width: 1px;
+ background-color: ${p => p.theme.innerBorder};
+ border-radius: 1px;
+`;