refine Semi UI alert workflow
This commit is contained in:
@@ -254,6 +254,9 @@ test('renders only selectable Semi alert cards on mobile', async () => {
|
||||
expect(view.container.querySelector('.v2-alert-table-scroll.is-mobile-scroll')).toHaveAttribute('tabindex', '0');
|
||||
expect(view.container.querySelector('.v2-alert-table-scroll.is-mobile-scroll')).toHaveAttribute('aria-label', '告警事件列表,可上下滚动');
|
||||
expect(view.container.querySelector('.v2-alert-event-table')).not.toBeInTheDocument();
|
||||
expect(view.container.querySelectorAll('.v2-alert-kpis .v2-metric-action')).toHaveLength(3);
|
||||
expect(screen.queryByRole('button', { name: /查看未读通知/ })).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('tab', { name: /站内通知/ })).toBeInTheDocument();
|
||||
expect(action).toHaveAttribute('aria-expanded', 'false');
|
||||
expect(action).toHaveTextContent('超限幅度+10 km/h');
|
||||
expect(action.querySelector('.v2-alert-protocol-tag.semi-tag')).toHaveTextContent('JT/T 808');
|
||||
@@ -298,7 +301,7 @@ test('keeps the primary alert query compact and applies advanced filters from a
|
||||
expect(screen.getByRole('button', { name: /更多筛选 · 1/ })).toHaveAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
test('uses the shared Semi bottom SideSheet pattern for mobile advanced filters', async () => {
|
||||
test('uses one focused Semi bottom SideSheet for the complete mobile event filter', async () => {
|
||||
layout.mobile = true;
|
||||
mocks.alertSummaryV2.mockResolvedValue({ active: 0, unprocessed: 0, processing: 0, recovered: 0, closed: 0, ignored: 0, unreadNotifications: 0, asOf: '' });
|
||||
mocks.alertEventsV2.mockResolvedValue({ items: [], total: 0, limit: 20, offset: 0 });
|
||||
@@ -308,11 +311,23 @@ test('uses the shared Semi bottom SideSheet pattern for mobile advanced filters'
|
||||
render(<QueryClientProvider client={client}><MemoryRouter future={ROUTER_FUTURE} initialEntries={['/alerts']}><AlertsPage /></MemoryRouter></QueryClientProvider>);
|
||||
|
||||
await screen.findByText('当前筛选条件没有告警事件');
|
||||
fireEvent.click(screen.getByRole('button', { name: /更多筛选/ }));
|
||||
const trigger = screen.getByRole('button', { name: /修改事件筛选/ });
|
||||
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
||||
fireEvent.click(trigger);
|
||||
|
||||
expect(await screen.findByRole('dialog', { name: '告警高级筛选' })).toBeInTheDocument();
|
||||
expect(document.querySelector('.v2-alert-filter-sidesheet')).toHaveClass('semi-sidesheet-bottom');
|
||||
expect(document.querySelector('.v2-alert-filter-sidesheet .semi-sidesheet-inner')).toHaveStyle({ height: 'min(72dvh, 620px)' });
|
||||
const dialog = await screen.findByRole('dialog', { name: '告警事件筛选' });
|
||||
expect(document.querySelector('.v2-alert-mobile-filter-sidesheet')).toHaveClass('semi-sidesheet-bottom');
|
||||
expect(document.querySelector('.v2-alert-mobile-filter-sidesheet .semi-sidesheet-inner')).toHaveStyle({ height: 'min(82dvh, 690px)' });
|
||||
expect(within(dialog).getByRole('textbox', { name: /关键词/ })).toBeInTheDocument();
|
||||
expect(within(dialog).getByRole('combobox', { name: '协议' })).toBeInTheDocument();
|
||||
expect(within(dialog).getByLabelText('告警起始时间')).toBeInTheDocument();
|
||||
expect(within(dialog).getByLabelText('告警结束时间')).toBeInTheDocument();
|
||||
fireEvent.click(within(dialog).getByRole('combobox', { name: '协议' }));
|
||||
fireEvent.click(await screen.findByText('JT808'));
|
||||
fireEvent.click(within(dialog).getByRole('button', { name: '应用并查询' }));
|
||||
|
||||
await waitFor(() => expect(mocks.alertEventsV2).toHaveBeenLastCalledWith(expect.objectContaining({ protocol: 'JT808' }), expect.anything()));
|
||||
expect(screen.getByRole('button', { name: /修改事件筛选:已启用 1 项/ })).toHaveAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
test('keeps mobile rule selection focused and opens editing in a Semi bottom SideSheet', async () => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { AlertEvent, AlertQuery, AlertRule, AlertRuleInput, AlertStatus, Me
|
||||
import { actionLabels, alertDeltaText, alertValue, canAct, formatAlertTime, operatorLabels, ruleCondition, severityLabels, statusLabels, thresholdText } from '../domain/alert';
|
||||
import { InlineError, PanelEmpty, PanelLoading } from '../shared/AsyncState';
|
||||
import { MetricActionButton } from '../shared/MetricActionButton';
|
||||
import { MobileFilterToggle } from '../shared/MobileFilterToggle';
|
||||
import { ProtocolTag } from '../shared/ProtocolTag';
|
||||
import { SegmentedTabs } from '../shared/SegmentedTabs';
|
||||
import { TablePagination } from '../shared/TablePagination';
|
||||
@@ -188,7 +189,9 @@ function EventWorkspace({ filters, draft, setDraft, setFilters, rules, unread, e
|
||||
const closeDetail = () => { setSelection(undefined); setNote(''); };
|
||||
const selectEvent = useCallback((id: string) => setSelection({ scope: eventScope, id }), [eventScope]);
|
||||
const selectedEvent = detail.data ?? rows.find((row) => row.id === selectedID);
|
||||
useSideSheetA11y(advancedOpen, '.v2-alert-filter-sidesheet', 'v2-alert-advanced-filters', '告警高级筛选', '关闭告警高级筛选');
|
||||
const mobileFiltersOpen = mobileLayout && !filtersCollapsed;
|
||||
useSideSheetA11y(!mobileLayout && advancedOpen, '.v2-alert-filter-sidesheet', 'v2-alert-advanced-filters', '告警高级筛选', '关闭告警高级筛选');
|
||||
useSideSheetA11y(mobileFiltersOpen, '.v2-alert-mobile-filter-sidesheet', 'v2-alert-mobile-filters', '告警事件筛选', '关闭告警事件筛选');
|
||||
useSideSheetA11y(mobileLayout && Boolean(selectedID), '.v2-alert-detail-sidesheet', 'v2-alert-detail', '告警事件详情', '关闭告警详情');
|
||||
const applyDraft = () => {
|
||||
setFilters(draft);
|
||||
@@ -201,6 +204,7 @@ function EventWorkspace({ filters, draft, setDraft, setFilters, rules, unread, e
|
||||
setFilters(EMPTY_FILTERS);
|
||||
setOffset(0);
|
||||
setAdvancedOpen(false);
|
||||
setFiltersCollapsed(true);
|
||||
};
|
||||
const quickStatus = (status: string) => { const next = { ...filters, status }; setDraft(next); setFilters(next); setOffset(0); };
|
||||
const totalPages = Math.max(1, Math.ceil((events.data?.total ?? 0) / limit));
|
||||
@@ -210,8 +214,55 @@ function EventWorkspace({ filters, draft, setDraft, setFilters, rules, unread, e
|
||||
const advancedFilterCount = [filters.ruleId, filters.protocol, filters.dateFrom, filters.dateTo].filter(Boolean).length;
|
||||
const allEventCount = Number(sums?.active ?? 0) + Number(sums?.recovered ?? 0) + Number(sums?.closed ?? 0) + Number(sums?.ignored ?? 0);
|
||||
const inspector = <EventInspector event={selectedEvent} note={note} acting={action.isPending} actionError={action.error instanceof Error ? action.error.message : undefined} editable={editable} onNote={setNote} onAction={(name) => { const event = detail.data; if (event) action.mutate({ name, event }); }} onClose={closeDetail} />;
|
||||
const coreFilterFields = <>
|
||||
<label><span>关键词</span><Input prefix={<IconSearch />} value={draft.keyword} onChange={(value) => setDraft({ ...draft, keyword: value })} placeholder="车牌 / VIN / 规则名称" /></label>
|
||||
<label><span id="alert-severity-label">严重程度</span><Select aria-labelledby="alert-severity-label" value={draft.severity} onChange={(value) => setDraft({ ...draft, severity: String(value) })} optionList={[{ value: '', label: '全部' }, { value: 'critical', label: '紧急' }, { value: 'major', label: '重要' }, { value: 'minor', label: '一般' }]} /></label>
|
||||
<label><span id="alert-status-label">状态</span><Select aria-labelledby="alert-status-label" value={draft.status} onChange={(value) => setDraft({ ...draft, status: String(value) })} optionList={[{ value: '', label: '全部' }, ...Object.entries(statusLabels).map(([value, label]) => ({ value, label }))]} /></label>
|
||||
</>;
|
||||
const advancedFilterFields = <>
|
||||
<label><span id="alert-rule-label">规则</span><Select aria-labelledby="alert-rule-label" value={draft.ruleId} onChange={(value) => setDraft({ ...draft, ruleId: String(value) })} optionList={[{ value: '', label: '全部规则' }, ...rules.map((rule) => ({ value: rule.id, label: rule.name }))]} /></label>
|
||||
<label><span id="alert-protocol-label">协议</span><Select aria-labelledby="alert-protocol-label" value={draft.protocol} onChange={(value) => setDraft({ ...draft, protocol: String(value) })} optionList={[{ value: '', label: '全部协议' }, ...PROTOCOLS.map((item) => ({ value: item, label: item }))]} /></label>
|
||||
<label><span>起始时间</span><Input aria-label="告警起始时间" type="datetime-local" value={draft.dateFrom} onChange={(value) => setDraft({ ...draft, dateFrom: value })} /></label>
|
||||
<label><span>结束时间</span><Input aria-label="告警结束时间" type="datetime-local" value={draft.dateTo} onChange={(value) => setDraft({ ...draft, dateTo: value })} /></label>
|
||||
</>;
|
||||
const primaryMetrics = [
|
||||
{ label: '全部事件', value: allEventCount, tone: 'active', status: '' },
|
||||
{ label: '未处理', value: sums?.unprocessed, tone: 'unprocessed', status: 'unprocessed' },
|
||||
{ label: '处理中', value: sums?.processing, tone: 'processing', status: 'processing' },
|
||||
...(mobileLayout ? [] : [{ label: '未读通知', value: unread, tone: 'notice', status: 'notice' }])
|
||||
];
|
||||
return <>
|
||||
<WorkspaceFilterPanel
|
||||
{mobileLayout ? <div className="v2-alert-mobile-discovery">
|
||||
<MobileFilterToggle
|
||||
title="事件筛选"
|
||||
summary={activeFilterCount ? `已启用 ${activeFilterCount} 项` : '全部告警'}
|
||||
expanded={mobileFiltersOpen}
|
||||
expandedLabel="关闭"
|
||||
collapsedLabel="修改"
|
||||
onToggle={() => setFiltersCollapsed((value) => !value)}
|
||||
/>
|
||||
<SideSheet
|
||||
className="v2-alert-filter-sidesheet v2-alert-mobile-filter-sidesheet"
|
||||
visible={mobileFiltersOpen}
|
||||
placement="bottom"
|
||||
height="min(82dvh, 690px)"
|
||||
aria-label="告警事件筛选"
|
||||
title={<div className="v2-alert-sheet-title"><strong>筛选告警事件</strong><span>车辆、状态、规则与时间范围</span></div>}
|
||||
onCancel={() => setFiltersCollapsed(true)}
|
||||
footer={<div className="v2-alert-mobile-filter-footer"><Button theme="light" onClick={resetFilters}>重置条件</Button><Button theme="solid" onClick={applyDraft}>应用并查询</Button></div>}
|
||||
>
|
||||
<form className="v2-alert-mobile-filter-form" onSubmit={submit}>
|
||||
<section className="v2-alert-mobile-filter-section" aria-label="常用筛选">
|
||||
<header><strong>常用条件</strong><span>快速定位车辆与待处置事件</span></header>
|
||||
<div className="v2-alert-mobile-filter-grid is-primary">{coreFilterFields}</div>
|
||||
</section>
|
||||
<section className="v2-alert-mobile-filter-section" aria-label="精确筛选">
|
||||
<header><strong>精确范围</strong><span>按规则、协议和触发时间进一步收窄</span></header>
|
||||
<div className="v2-alert-mobile-filter-grid">{advancedFilterFields}</div>
|
||||
</section>
|
||||
</form>
|
||||
</SideSheet>
|
||||
</div> : <WorkspaceFilterPanel
|
||||
className="v2-alert-filter-card"
|
||||
title="事件筛选"
|
||||
description="关键词、严重程度、处理状态与高级范围"
|
||||
@@ -222,22 +273,15 @@ function EventWorkspace({ filters, draft, setDraft, setFilters, rules, unread, e
|
||||
onToggle={() => setFiltersCollapsed((value) => !value)}
|
||||
>
|
||||
<form className="v2-alert-filter v2-alert-filter-primary" onSubmit={submit}>
|
||||
<label><span>关键词</span><Input prefix={<IconSearch />} value={draft.keyword} onChange={(value) => setDraft({ ...draft, keyword: value })} placeholder="车牌 / VIN / 规则名称" /></label>
|
||||
<label><span id="alert-severity-label">严重程度</span><Select aria-labelledby="alert-severity-label" value={draft.severity} onChange={(value) => setDraft({ ...draft, severity: String(value) })} optionList={[{ value: '', label: '全部' }, { value: 'critical', label: '紧急' }, { value: 'major', label: '重要' }, { value: 'minor', label: '一般' }]} /></label>
|
||||
<label><span id="alert-status-label">状态</span><Select aria-labelledby="alert-status-label" value={draft.status} onChange={(value) => setDraft({ ...draft, status: String(value) })} optionList={[{ value: '', label: '全部' }, ...Object.entries(statusLabels).map(([value, label]) => ({ value, label }))]} /></label>
|
||||
{coreFilterFields}
|
||||
<Button className="v2-alert-more-filter" theme="light" htmlType="button" icon={<IconFilter />} aria-haspopup="dialog" aria-controls="v2-alert-advanced-filters" aria-expanded={advancedOpen} onClick={() => setAdvancedOpen(true)}>更多筛选{advancedFilterCount ? ` · ${advancedFilterCount}` : ''}</Button>
|
||||
<Button className="v2-primary-button" theme="solid" htmlType="submit">查询</Button>
|
||||
<Button className="v2-secondary-button" theme="light" htmlType="button" onClick={resetFilters}>重置</Button>
|
||||
</form>
|
||||
</WorkspaceFilterPanel>
|
||||
</WorkspaceFilterPanel>}
|
||||
{summary.isError ? <InlineError message={summary.error instanceof Error ? summary.error.message : '告警汇总读取失败'} onRetry={() => summary.refetch()} /> : null}
|
||||
<Card className="v2-alert-kpis-card v2-alert-context-card" bodyStyle={{ padding: 0 }}>
|
||||
<section className="v2-alert-kpis" aria-label="活跃告警概览">{[
|
||||
{ label: '全部事件', value: allEventCount, tone: 'active', status: '' },
|
||||
{ label: '未处理', value: sums?.unprocessed, tone: 'unprocessed', status: 'unprocessed' },
|
||||
{ label: '处理中', value: sums?.processing, tone: 'processing', status: 'processing' },
|
||||
{ label: '未读通知', value: unread, tone: 'notice', status: 'notice' }
|
||||
].map((item) => {
|
||||
<section className="v2-alert-kpis" aria-label="活跃告警概览">{primaryMetrics.map((item) => {
|
||||
const value = Number(item.value ?? 0).toLocaleString('zh-CN');
|
||||
return <MetricActionButton key={item.label} label={item.label} value={value} tone={item.tone} active={item.status !== 'notice' && filters.status === item.status} ariaLabel={item.status === 'notice' ? `查看未读通知,共 ${value} 条` : `筛选${item.label},共 ${value} 条`} onClick={() => item.status === 'notice' ? onTab('notifications') : quickStatus(item.status)} />;
|
||||
})}</section>
|
||||
@@ -273,24 +317,19 @@ function EventWorkspace({ filters, draft, setDraft, setFilters, rules, unread, e
|
||||
</Card>
|
||||
{!mobileLayout && selectedID ? inspector : null}
|
||||
</div>
|
||||
<SideSheet
|
||||
{!mobileLayout ? <SideSheet
|
||||
className="v2-alert-filter-sidesheet"
|
||||
visible={advancedOpen}
|
||||
aria-label="告警高级筛选"
|
||||
placement={mobileLayout ? 'bottom' : 'right'}
|
||||
width={mobileLayout ? undefined : 430}
|
||||
height={mobileLayout ? 'min(72dvh, 620px)' : undefined}
|
||||
placement="right"
|
||||
width={430}
|
||||
title={<div className="v2-alert-sheet-title"><strong>更多筛选</strong><span>按规则、协议和触发时间收窄告警范围</span></div>}
|
||||
onCancel={() => setAdvancedOpen(false)}
|
||||
footer={<div className="v2-alert-sheet-footer"><Button theme="light" onClick={() => setDraft({ ...draft, ruleId: '', protocol: '', dateFrom: '', dateTo: '' })}>清空高级条件</Button><Button theme="solid" onClick={() => { applyDraft(); setAdvancedOpen(false); }}>应用筛选</Button></div>}
|
||||
>
|
||||
<div className="v2-alert-advanced-filter">
|
||||
<label><span id="alert-rule-label">规则</span><Select aria-labelledby="alert-rule-label" value={draft.ruleId} onChange={(value) => setDraft({ ...draft, ruleId: String(value) })} optionList={[{ value: '', label: '全部规则' }, ...rules.map((rule) => ({ value: rule.id, label: rule.name }))]} /></label>
|
||||
<label><span id="alert-protocol-label">协议</span><Select aria-labelledby="alert-protocol-label" value={draft.protocol} onChange={(value) => setDraft({ ...draft, protocol: String(value) })} optionList={[{ value: '', label: '全部协议' }, ...PROTOCOLS.map((item) => ({ value: item, label: item }))]} /></label>
|
||||
<label><span>起始时间</span><Input aria-label="告警起始时间" type="datetime-local" value={draft.dateFrom} onChange={(value) => setDraft({ ...draft, dateFrom: value })} /></label>
|
||||
<label><span>结束时间</span><Input aria-label="告警结束时间" type="datetime-local" value={draft.dateTo} onChange={(value) => setDraft({ ...draft, dateTo: value })} /></label>
|
||||
</div>
|
||||
<div className="v2-alert-advanced-filter">{advancedFilterFields}</div>
|
||||
</SideSheet>
|
||||
: null}
|
||||
<SideSheet
|
||||
className="v2-alert-detail-sidesheet"
|
||||
visible={mobileLayout && Boolean(selectedID)}
|
||||
|
||||
@@ -16748,3 +16748,171 @@
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Semi UI alert mobile workflow.
|
||||
* Keep the event list as the primary task: all filters live in one focused
|
||||
* bottom sheet and only actionable event states occupy the main metric rail.
|
||||
*/
|
||||
@media (max-width: 680px) {
|
||||
.v2-alert-mobile-discovery {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
flex: 0 0 auto;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-discovery > .v2-mobile-filter-toggle.semi-button {
|
||||
min-height: 58px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-sidesheet .semi-sidesheet-inner {
|
||||
width: 100vw !important;
|
||||
overflow: hidden;
|
||||
border-radius: 18px 18px 0 0;
|
||||
background: #f4f7fb;
|
||||
box-shadow: 0 -20px 56px rgba(25, 45, 72, .2);
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-sidesheet.semi-sidesheet-bottom .semi-sidesheet-header {
|
||||
min-height: 68px;
|
||||
border-bottom: 1px solid #dfe7f0;
|
||||
background: rgba(255, 255, 255, .98);
|
||||
padding: 11px 14px;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-sidesheet.semi-sidesheet-bottom .semi-sidesheet-body {
|
||||
overflow: auto;
|
||||
background: #f4f7fb;
|
||||
padding: 12px;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-sidesheet.semi-sidesheet-bottom .semi-sidesheet-footer {
|
||||
border-top: 1px solid #dfe7f0;
|
||||
background: rgba(255, 255, 255, .98);
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-form {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-section {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
border: 1px solid #dfe7f0;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
padding: 12px;
|
||||
box-shadow: 0 8px 24px rgba(31, 53, 80, .055);
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-section > header {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-section > header > strong {
|
||||
color: #2b4058;
|
||||
font-size: 13px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-section > header > span {
|
||||
color: #7c8b9e;
|
||||
font-size: 10px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 11px 9px;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-grid.is-primary > label:first-child,
|
||||
.v2-alert-mobile-filter-grid > label:nth-last-child(-n + 2) {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-grid > label {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
gap: 6px;
|
||||
color: #5f7188;
|
||||
font-size: 11px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-grid > label > .semi-input-wrapper,
|
||||
.v2-alert-mobile-filter-grid > label > .semi-select {
|
||||
width: 100%;
|
||||
min-height: 44px;
|
||||
border-radius: 9px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-grid .semi-input,
|
||||
.v2-alert-mobile-filter-grid .semi-select-selection-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-footer {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
grid-template-columns: minmax(0, .72fr) minmax(0, 1.28fr);
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.v2-alert-mobile-filter-footer > .semi-button {
|
||||
width: 100%;
|
||||
min-height: 42px;
|
||||
border-radius: 9px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.v2-alert-context-card.semi-card {
|
||||
min-height: 96px;
|
||||
}
|
||||
|
||||
.v2-alert-context-card .v2-alert-kpis {
|
||||
height: 62px;
|
||||
min-height: 62px;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.v2-alert-context-card .v2-alert-kpis .v2-metric-action,
|
||||
.v2-alert-context-card .v2-alert-kpis .v2-metric-action-content {
|
||||
min-height: 62px;
|
||||
}
|
||||
|
||||
.v2-alert-context-card .v2-alert-kpis .v2-metric-action {
|
||||
padding: 6px 4px;
|
||||
}
|
||||
|
||||
.v2-alert-context-card .v2-alert-kpis .v2-metric-action-content {
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.v2-alert-context-card .v2-alert-kpis small {
|
||||
color: #687991;
|
||||
font-size: 10px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.v2-alert-context-card .v2-alert-kpis strong {
|
||||
color: #28415f;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.v2-alert-context-card .v2-alert-secondary-states {
|
||||
min-height: 34px;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
padding: 3px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user