Skip to content
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
3 changes: 2 additions & 1 deletion src/pages/alertRules/Add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import PageLayout from '@/components/pageLayout';
import { generateQueryNameByIndex } from '@/components/QueryName';
import Form from './FormNG';
import { defaultValues } from './Form/constants';
import { getPageFromSearch } from '@/utils/urlPage';

export default function Add() {
const { t } = useTranslation('alertRules');
Expand Down Expand Up @@ -64,7 +65,7 @@ export default function Add() {
}

return (
<PageLayout title={t('title')} showBack backPath='/alert-rules'>
<PageLayout title={t('title')} showBack backPath={`/alert-rules?page=${getPageFromSearch(location.search)}`}>
<div className='n9e h-full overflow-hidden p-0'>
<Form initialValues={initialValues} />
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/pages/alertRules/Edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import PageLayout from '@/components/pageLayout';
import { getWarningStrategy } from '@/services/warning';
import Form from './FormNG';
import { getAlertRulePure } from './services';
import { getPageFromSearch } from '@/utils/urlPage';

export default function Edit() {
const { t } = useTranslation('alertRules');
Expand Down Expand Up @@ -62,7 +63,7 @@ export default function Edit() {
}, 2000);

return (
<PageLayout title={t('title')} showBack backPath='/alert-rules'>
<PageLayout title={t('title')} showBack backPath={`/alert-rules?page=${getPageFromSearch(search)}`}>
<div className='n9e h-full overflow-hidden p-0'>{!_.isEmpty(values) && <Form type={mode === 'clone' ? 2 : 1} initialValues={values} editable={editable} />}</div>
</PageLayout>
);
Expand Down
7 changes: 5 additions & 2 deletions src/pages/alertRules/FormNG/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { createContext, useContext, useEffect, useMemo, useState, useRef,
import { Alert, Button, Card, Col, Form, Input, message, Row, Select, Space } from 'antd';
import { Sparkles, ChevronsUpDown, ChevronsDownUp, PanelRight } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { Link, useHistory, useParams } from 'react-router-dom';
import { Link, useHistory, useParams, useLocation } from 'react-router-dom';
import _ from 'lodash';

import { CommonStateContext } from '@/App';
Expand All @@ -12,6 +12,7 @@ import { DatasourceCateSelectV2 } from '@/components/DatasourceSelect';
import { addStrategy, EditStrategy } from '@/services/warning';
import { scrollToFirstError } from '@/utils';
import { IS_PLUS } from '@/utils/constant';
import { getPageFromSearch } from '@/utils/urlPage';
import RouterPrompt from '@/components/RouterPrompt';

import { defaultValues } from '../Form/constants';
Expand Down Expand Up @@ -72,6 +73,7 @@ function AdvancedSettingsSection(props: {
export default function FormNG(props: IProps) {
const { type, initialValues, editable = true } = props;
const history = useHistory();
const location = useLocation();
const { bgid } = useParams<{ bgid: string }>();
const { t, i18n } = useTranslation('alertRules');

Expand Down Expand Up @@ -194,6 +196,7 @@ export default function FormNG(props: IProps) {
const leaveAfterSave = useCallback(() => {
allowNextRouteRef.current = true;
setAllowedLeave(true);
// 新增/编辑保存后回列表第一页(不带 page 参数,URL 默认第一页)
history.push('/alert-rules');
}, [history]);

Expand Down Expand Up @@ -592,7 +595,7 @@ export default function FormNG(props: IProps) {
{t('common:btn.save')}
</Button>
<TestFireModal bgid={initialValues?.group_id || Number(bgid)} buttonDisabled={editable === false} />
<Link to='/alert-rules'>
<Link to={{ pathname: '/alert-rules', search: `?page=${getPageFromSearch(location.search)}` }}>
<Button>{t('common:btn.cancel')}</Button>
</Link>
</Space>
Expand Down
40 changes: 31 additions & 9 deletions src/pages/alertRules/List/ListNG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { TriangleAlert, CircleCheckBig } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { useDebounceFn } from 'ahooks';
import _ from 'lodash';
import { Link } from 'react-router-dom';
import { Link, useHistory, useLocation } from 'react-router-dom';

import { CommonStateContext } from '@/App';
import { updateAlertRules, deleteStrategy } from '@/services/warning';
Expand All @@ -22,10 +22,11 @@ import localeCompare from '@/pages/dashboard/Renderer/utils/localeCompare';
import { getItems as getNotificationRules, RuleItem as NotificationRuleItem } from '@/pages/notificationRules/services';
import { NS as notificationRulesNS } from '@/pages/notificationRules/constants';
import { AlertRuleType, AlertRuleStatus } from '@/pages/alertRules/types';
import { defaultColumnsConfigs, LOCAL_STORAGE_KEY } from '@/pages/alertRules/List/constants';
import { defaultColumnsConfigs, LOCAL_STORAGE_KEY, FILTER_SESSION_STORAGE_KEY } from '@/pages/alertRules/List/constants';
import EventsDrawer, { Props as EventsDrawerProps } from '@/pages/alertRules/List/EventsDrawer';
import EvalRecordsDrawer, { Props as EvalRecordsDrawerProps } from '@/pages/alertRules/List/EvalRecordsDrawer';
import { matchTriggerType, TRIGGER_TYPE_OPTIONS, TriggerType } from '@/pages/alertRules/List/utils';
import { getPageFromSearch, setPageInSearch, removePageFromSearch } from '@/utils/urlPage';

interface Filter {
cate?: string;
Expand All @@ -37,7 +38,6 @@ interface Filter {
triggerType?: TriggerType;
}

const FILTER_SESSION_STORAGE_KEY = 'alert-rules-filter';
const includesProm = (datasourceList: any[], ids?: number[]) => {
return _.some(ids, (id) => {
return _.some(datasourceList, (item) => {
Expand All @@ -56,31 +56,52 @@ interface Props {
setRefreshFlag?: (flag: string) => void;
linkTarget?: string;
emptyGuide?: React.ReactNode;
gids?: string;
groupSwitchCount?: number;
}

export default function AlertRules(props: Props) {
const { t, i18n } = useTranslation('alertRules');
const { busiGroups, datasourceList, feats } = useContext(CommonStateContext);
const { hideBusinessGroupColumn, showRowSelection, readonly, headerExtra, data, loading, setRefreshFlag, linkTarget, emptyGuide } = props;
const { hideBusinessGroupColumn, showRowSelection, readonly, headerExtra, data, loading, setRefreshFlag, linkTarget, emptyGuide, gids, groupSwitchCount } = props;
const history = useHistory();
const location = useLocation();
let defaultFilter = {} as Filter;
let defaultPage = 1;
try {
const saved = JSON.parse(window.sessionStorage.getItem(FILTER_SESSION_STORAGE_KEY) || '{}');
defaultFilter = saved;
defaultPage = saved.current || 1;
} catch (e) {
console.error(e);
}
const defaultPage = getPageFromSearch(location.search);
const [filter, setFilter] = useState<Filter>(defaultFilter);
const [current, setCurrent] = useState<number>(defaultPage);
const handleFilterChange = (newFilter: Filter) => {
setFilter(newFilter);
Comment on lines +76 to 80
setCurrent(1);
window.sessionStorage.setItem(FILTER_SESSION_STORAGE_KEY, JSON.stringify({ ...newFilter, current: 1 }));
window.sessionStorage.setItem(FILTER_SESSION_STORAGE_KEY, JSON.stringify(newFilter));
history.replace({ pathname: location.pathname, search: setPageInSearch(location.search, 1) });
};
// 新增/编辑/批量操作保存成功后,记录的更新时间会变化,按更新时间倒序的列表会把刚操作的记录排到第一页,
// 因此保存后需要把页码重置为 1,避免停留在旧页码看不到刚操作的记录
const resetPaging = () => {
setCurrent(1);
clearSelection();
history.replace({ pathname: location.pathname, search: removePageFromSearch(location.search) });
};
// 切换业务组时重置到第一页(父组件在业务组选择源头递增计数触发,不依赖 gids 变化时序)
useEffect(() => {
if (groupSwitchCount) {
resetPaging();
}
}, [groupSwitchCount]);
const [queryValue, setQueryValue] = useState<string | undefined>(defaultFilter.search);
const [selectRowKeys, setSelectRowKeys] = useState<React.Key[]>([]);
const [selectedRows, setSelectedRows] = useState<AlertRuleType<any>[]>([]);
const clearSelection = () => {
setSelectRowKeys([]);
setSelectedRows([]);
};
const [visibleColumns, setVisibleColumns] = useState<string[]>(() => getDefaultColumnsConfigs(defaultColumnsConfigs, LOCAL_STORAGE_KEY));
const pagination = usePagination({ PAGESIZE_KEY: 'alert-rules-pagesize' });
const [eventsDrawerProps, setEventsDrawerProps] = useState<EventsDrawerProps>({
Expand Down Expand Up @@ -156,6 +177,7 @@ export default function AlertRules(props: Props) {
className='table-text'
to={{
pathname: `/alert-rules/edit/${record.id}`,
search: `?page=${current}`,
}}
target={linkTarget}
>
Expand Down Expand Up @@ -472,6 +494,7 @@ export default function AlertRules(props: Props) {
selectRowKeys,
selectedRows,
getList: fetchData,
clearSelection,
})}
<TableColumnSelect
options={buildColumnOptions(defaultColumnsConfigs, t)}
Expand All @@ -496,8 +519,7 @@ export default function AlertRules(props: Props) {
pagination={{ ...pagination, current }}
onChange={(pag) => {
setCurrent(pag.current || 1);
const saved = JSON.parse(window.sessionStorage.getItem(FILTER_SESSION_STORAGE_KEY) || '{}');
window.sessionStorage.setItem(FILTER_SESSION_STORAGE_KEY, JSON.stringify({ ...saved, current: pag.current || 1 }));
history.replace({ pathname: location.pathname, search: setPageInSearch(location.search, pag.current || 1) });
}}
loading={loading}
dataSource={filterData()}
Expand Down
17 changes: 14 additions & 3 deletions src/pages/alertRules/List/MoreOperations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface MoreOperationsProps {
selectRowKeys: React.Key[];
selectedRows: any[];
getAlertRules: () => void;
clearSelection?: () => void;
}

const ignoreFields = [
Expand Down Expand Up @@ -67,7 +68,7 @@ const ignoreFields = [

export default function MoreOperations(props: MoreOperationsProps) {
const { t } = useTranslation('alertRules');
const { bgid, isLeaf, selectRowKeys, selectedRows, getAlertRules } = props;
const { bgid, isLeaf, selectRowKeys, selectedRows, getAlertRules, clearSelection } = props;
const [isModalVisible, setisModalVisible] = useState<boolean>(false);
const { isPlus, busiGroups } = useContext(CommonStateContext);

Expand Down Expand Up @@ -103,6 +104,7 @@ export default function MoreOperations(props: MoreOperationsProps) {
onOk: () => {
deleteStrategy(selectRowKeys as number[], bgid!).then(() => {
message.success(t('batch.delete_success'));
clearSelection?.();
getAlertRules();
});
},
Expand Down Expand Up @@ -140,7 +142,10 @@ export default function MoreOperations(props: MoreOperationsProps) {
CloneToBgids({
ids: selectRowKeys,
busiGroups,
onOk: getAlertRules,
onOk: () => {
clearSelection?.();
getAlertRules();
},
});
}}
>
Expand All @@ -159,7 +164,10 @@ export default function MoreOperations(props: MoreOperationsProps) {
gid: bgid!,
ids: selectRowKeys,
busiGroups,
onOk: getAlertRules,
onOk: () => {
clearSelection?.();
getAlertRules();
},
});
}}
>
Expand Down Expand Up @@ -211,6 +219,7 @@ export default function MoreOperations(props: MoreOperationsProps) {
);
if (!res.err) {
message.success(t('common:success.modify'));
clearSelection?.();
getAlertRules();
setisModalVisible(false);
} else {
Expand All @@ -227,6 +236,7 @@ export default function MoreOperations(props: MoreOperationsProps) {
);
if (!res.err) {
message.success(t('common:success.modify'));
clearSelection?.();
getAlertRules();
setisModalVisible(false);
} else {
Expand All @@ -245,6 +255,7 @@ export default function MoreOperations(props: MoreOperationsProps) {
);
if (!res.err) {
message.success(t('common:success.modify'));
clearSelection?.();
getAlertRules();
setisModalVisible(false);
} else {
Expand Down
1 change: 1 addition & 0 deletions src/pages/alertRules/List/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import i18next from 'i18next';
*
*/
export const LOCAL_STORAGE_KEY = 'alertRules_columns_configs';
export const FILTER_SESSION_STORAGE_KEY = 'alert-rules-filter';
export const defaultColumnsConfigs = [
{
name: 'cur_event_count',
Expand Down
9 changes: 7 additions & 2 deletions src/pages/alertRules/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@ import ListNG from './ListNG';

interface ListProps {
gids?: string;
groupSwitchCount?: number;
}

function HeaderExtra(
props: ListProps & {
selectRowKeys?: React.Key[];
selectedRows?: AlertRuleType<any>[];
getList?: () => void;
clearSelection?: () => void;
},
) {
const { t } = useTranslation('alertRules');
const { businessGroup, groupedDatasourceList, reloadGroupedDatasourceList, datasourceCateOptions } = useContext(CommonStateContext);
const history = useHistory();
const { gids, selectRowKeys = [], selectedRows = [], getList } = props;
const { gids, selectRowKeys = [], selectedRows = [], getList, clearSelection } = props;

return (
<Space>
Expand Down Expand Up @@ -67,6 +69,7 @@ function HeaderExtra(
selectRowKeys={selectRowKeys}
selectedRows={selectedRows}
getAlertRules={getList}
clearSelection={clearSelection}
/>
)}
</Space>
Expand All @@ -77,7 +80,7 @@ export default function List(props: ListProps) {
const { t } = useTranslation('alertRules');
const { businessGroup, groupedDatasourceList, reloadGroupedDatasourceList, datasourceCateOptions } = useContext(CommonStateContext);
const history = useHistory();
const { gids } = props;
const { gids, groupSwitchCount } = props;
const [refreshFlag, setRefreshFlag] = useState<string>(_.uniqueId('refresh_'));
const [data, setData] = useState<AlertRuleType<any>[]>([]);
const [loading, setLoading] = useState(false);
Expand Down Expand Up @@ -107,6 +110,8 @@ export default function List(props: ListProps) {
<ListNG
hideBusinessGroupColumn={businessGroup.isLeaf && gids !== '-2'}
showRowSelection
gids={gids}
groupSwitchCount={groupSwitchCount}
headerExtra={<HeaderExtra gids={gids} />}
data={data}
loading={loading}
Expand Down
10 changes: 8 additions & 2 deletions src/pages/alertRules/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ export default function index() {
const { businessGroup } = useContext(CommonStateContext);
const { t } = useTranslation('alertRules');
const [gids, setGids] = useState<string | undefined>(getDefaultGids(N9E_GIDS_LOCALKEY, businessGroup));
const [groupSwitchCount, setGroupSwitchCount] = useState(0);
// 切换业务组时通知列表重置到第一页(在业务组选择源头触发,不依赖 gids 变化时序)
const handleSelectGids = (ids: string) => {
setGids(ids);
setGroupSwitchCount((count) => count + 1);
};

return (
<PageLayout
Expand All @@ -47,8 +53,8 @@ export default function index() {
headerCenter={IS_ENT ? <ObsLoopAlertRulesTip /> : undefined}
>
<div className='alert-rules-container'>
<BusinessGroupSideBarWithAll gids={gids} setGids={setGids} localeKey={N9E_GIDS_LOCALKEY} />
{businessGroup.ids ? <List gids={gids} /> : <BlankBusinessPlaceholder text={t('title')} />}
<BusinessGroupSideBarWithAll gids={gids} setGids={handleSelectGids} localeKey={N9E_GIDS_LOCALKEY} />
{businessGroup.ids ? <List gids={gids} groupSwitchCount={groupSwitchCount} /> : <BlankBusinessPlaceholder text={t('title')} />}
</div>
</PageLayout>
);
Expand Down
7 changes: 5 additions & 2 deletions src/pages/dashboard/Detail/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
import React, { useContext, useEffect, useRef, useState } from 'react';
import { useHistory, useLocation, Link } from 'react-router-dom';
import { getPageFromSearch } from '@/utils/urlPage';
import querystring from 'query-string';
import _ from 'lodash';
import moment from 'moment';
Expand Down Expand Up @@ -105,6 +106,8 @@ export default function Title(props: IProps) {
const [variablesWithOptions] = useGlobalState('variablesWithOptions');
const query = querystring.parse(location.search);
const { viewMode, __public__ } = query;
// 从列表进入详情时 URL 带 page 参数,返回列表时回到原页;其他入口回列表第一页
const goListPath = props.gobackPath || (getPageFromSearch(location.search) > 1 ? `/dashboards?page=${getPageFromSearch(location.search)}` : '/dashboards');
Comment on lines 107 to +110
// AI 分析仅在正常已保存的仪表盘下展示:匿名公开、模板预览、内置组件场景要么调不通 assistant 接口,要么没有真实 dashboard_id
const showAiAnalysis = !isPreview && !isBuiltin && __public__ !== 'true' && !!dashboard.id;
const isClickTrigger = useRef(false);
Expand Down Expand Up @@ -193,7 +196,7 @@ export default function Title(props: IProps) {
onClick={() => {
if (allowedLeave) {
goBack(history).catch(() => {
history.push(props.gobackPath || '/dashboards');
history.push(goListPath);
});
} else {
routerPromptRef.current.showPrompt();
Expand All @@ -204,7 +207,7 @@ export default function Title(props: IProps) {
)}
{!hideGoList && (
<Space className='pr-2'>
<Link to={props.gobackPath || '/dashboards'} style={{ fontSize: 14 }}>
<Link to={goListPath} style={{ fontSize: 14 }}>
{isBuiltin ? t('builtInComponents:title') : t('list')}
</Link>
{'/'}
Expand Down
4 changes: 3 additions & 1 deletion src/pages/dashboard/List/BatchClone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ import { boardsClones } from '@/services/dashboardV2';
interface IProps {
board_ids: number[];
busiGroups: any[];
onOk?: () => void;
}

function BatchClone(props: IProps & ModalWrapProps) {
const { t } = useTranslation('dashboard');
const { visible, destroy, board_ids, busiGroups } = props;
const { visible, destroy, board_ids, busiGroups, onOk } = props;
const [importResult, setImportResult] = useState<{ name: string; msg: string }[]>();

return (
Expand Down Expand Up @@ -60,6 +61,7 @@ function BatchClone(props: IProps & ModalWrapProps) {
setImportResult(dataSource);
if (_.every(dataSource, (item) => !item.msg)) {
message.success(t('common:success.clone'));
onOk?.();
destroy();
}
})
Expand Down
Loading