Skip to content

Commit e66b2d7

Browse files
committed
feat(investigations): Consolidate cell actions
1 parent 683dd51 commit e66b2d7

2 files changed

Lines changed: 139 additions & 84 deletions

File tree

static/app/views/investigations/detail/cell.tsx

Lines changed: 71 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {TextArea} from '@sentry/scraps/textarea';
1111

1212
import {addErrorMessage} from 'sentry/actionCreators/indicator';
1313
import {openConfirmModal} from 'sentry/components/confirm';
14-
import {DropdownMenu} from 'sentry/components/dropdownMenu';
14+
import {DropdownMenu, type MenuItemProps} from 'sentry/components/dropdownMenu';
1515
import {Duration} from 'sentry/components/duration';
1616
import {SeerMarkdown} from 'sentry/components/seer/markdown';
1717
import {ChartContent} from 'sentry/components/seer/markdown/embeds/components/chart';
@@ -21,7 +21,6 @@ import {
2121
IconChevron,
2222
IconClose,
2323
IconEllipsis,
24-
IconRefresh,
2524
IconReturn,
2625
IconSeer,
2726
} from 'sentry/icons';
@@ -150,33 +149,50 @@ export function InvestigationCell({
150149
}
151150
}
152151

153-
const refinementButton = (
154-
<Button
155-
size="xs"
156-
variant="transparent"
157-
icon={<IconSeer size="xs" />}
158-
aria-label={t('Ask Seer about %s', displayTitle)}
159-
disabled={waitingForDependencies}
160-
onClick={panelOpen ? () => setPanelOpen(false) : openPanel}
161-
/>
152+
const actionItems: MenuItemProps[] = [];
153+
if (block.kind === 'query') {
154+
actionItems.push({
155+
key: 'rerun',
156+
label: t('Rerun'),
157+
disabled:
158+
!canRun ||
159+
rerunMutation.isPending ||
160+
isExecutionActive(block.currentExecution?.status) ||
161+
!(block.generationPrompt || block.content).trim(),
162+
onAction: () => void rerun(),
163+
});
164+
}
165+
actionItems.push(
166+
{
167+
key: 'refine',
168+
label: t('Refine'),
169+
disabled: waitingForDependencies,
170+
onAction: openPanel,
171+
},
172+
{
173+
key: 'delete',
174+
label: t('Delete'),
175+
priority: 'danger',
176+
disabled:
177+
!canRun ||
178+
deleteMutation.isPending ||
179+
isExecutionActive(block.currentExecution?.status),
180+
onAction: () =>
181+
openConfirmModal({
182+
message: t('Are you sure you want to delete this cell?'),
183+
priority: 'danger',
184+
confirmText: t('Delete'),
185+
onConfirm: () =>
186+
deleteMutation.mutate({
187+
block,
188+
investigationVersion: investigation.version,
189+
}),
190+
}),
191+
}
162192
);
163193

164-
const queryHeaderActions = (
165-
<Flex align="center" gap="xs" flexShrink={0}>
166-
{refinementButton}
167-
<Button
168-
size="xs"
169-
variant="transparent"
170-
icon={<IconRefresh size="xs" />}
171-
aria-label={t('Rerun %s', displayTitle)}
172-
busy={rerunMutation.isPending}
173-
disabled={
174-
!canRun ||
175-
isExecutionActive(block.currentExecution?.status) ||
176-
!(block.generationPrompt || block.content).trim()
177-
}
178-
onClick={() => void rerun()}
179-
/>
194+
const cellActions = (
195+
<CellActions data-cell-actions flexShrink={0}>
180196
<DropdownMenu
181197
position="bottom-end"
182198
usePortal
@@ -187,30 +203,9 @@ export function InvestigationCell({
187203
icon: <IconEllipsis size="xs" />,
188204
'aria-label': t('Cell actions for %s', displayTitle),
189205
}}
190-
items={[
191-
{
192-
key: 'delete',
193-
label: t('Delete'),
194-
priority: 'danger',
195-
disabled:
196-
!canRun ||
197-
deleteMutation.isPending ||
198-
isExecutionActive(block.currentExecution?.status),
199-
onAction: () =>
200-
openConfirmModal({
201-
message: t('Are you sure you want to delete this cell?'),
202-
priority: 'danger',
203-
confirmText: t('Delete'),
204-
onConfirm: () =>
205-
deleteMutation.mutate({
206-
block,
207-
investigationVersion: investigation.version,
208-
}),
209-
}),
210-
},
211-
]}
206+
items={actionItems}
212207
/>
213-
</Flex>
208+
</CellActions>
214209
);
215210

216211
const panel = panelOpen ? (
@@ -240,7 +235,7 @@ export function InvestigationCell({
240235
{block.kind === 'query' ? (
241236
<Fragment>
242237
<QueryResult
243-
actions={queryHeaderActions}
238+
actions={cellActions}
244239
block={block}
245240
progressState={progressState}
246241
/>
@@ -250,8 +245,8 @@ export function InvestigationCell({
250245
<Fragment>
251246
<CellResult
252247
block={block}
248+
actions={cellActions}
253249
progressState={progressState}
254-
refinementButton={refinementButton}
255250
streamedMarkdown={
256251
isExecutionActive(block.currentExecution?.status)
257252
? streamedTextQuery.data?.partialMarkdown
@@ -266,20 +261,20 @@ export function InvestigationCell({
266261
}
267262

268263
function CellResult({
264+
actions,
269265
block,
270266
progressState,
271-
refinementButton,
272267
streamedMarkdown,
273268
}: {
269+
actions: React.ReactNode;
274270
block: InvestigationBlock;
275271
progressState: CellProgressState;
276-
refinementButton: React.ReactNode;
277272
streamedMarkdown?: string | null;
278273
}) {
279274
const markdown =
280275
streamedMarkdown ?? getTextOutput(block.output) ?? (block.content.trim() || null);
281276
return (
282-
<Stack
277+
<CellHoverSurface
283278
position="relative"
284279
flex={1}
285280
minWidth={0}
@@ -288,15 +283,15 @@ function CellResult({
288283
data-cell-variant="unbordered"
289284
>
290285
<Container position="absolute" top={0} right={0}>
291-
{refinementButton}
286+
{actions}
292287
</Container>
293288
<CellExecutionAlert block={block} />
294289
{markdown ? (
295290
<SeerMarkdown raw={markdown} />
296291
) : (
297292
<CellProgress state={progressState} />
298293
)}
299-
</Stack>
294+
</CellHoverSurface>
300295
);
301296
}
302297

@@ -321,7 +316,7 @@ function QueryResult({
321316
getChartMetadata(chart);
322317

323318
return (
324-
<Stack width="100%" gap="sm">
319+
<CellHoverSurface width="100%" gap="sm">
325320
<QueryDisclosureButton
326321
size="sm"
327322
variant="transparent"
@@ -381,7 +376,7 @@ function QueryResult({
381376
</Container>
382377
</Stack>
383378
) : null}
384-
</Stack>
379+
</CellHoverSurface>
385380
);
386381
}
387382

@@ -1131,6 +1126,23 @@ const QueryDisclosureButton = styled(Button)`
11311126
text-align: left;
11321127
`;
11331128

1129+
const CellActions = styled(Flex)`
1130+
opacity: 0;
1131+
`;
1132+
1133+
const CellHoverSurface = styled(Stack)`
1134+
&:hover ${CellActions},
1135+
&:focus-within ${CellActions} {
1136+
opacity: 1;
1137+
}
1138+
1139+
@media (hover: none) {
1140+
${CellActions} {
1141+
opacity: 1;
1142+
}
1143+
}
1144+
`;
1145+
11341146
const QueryTable = styled('table')`
11351147
min-width: 100%;
11361148
border-collapse: collapse;

0 commit comments

Comments
 (0)