mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-20 05:44:29 +08:00

* feat: add pipeline preview API * chore: separate PipelineActions and ProcessorActions components * feat: add pipeline preview action * chore: extract useSampleLogs hook and move SampleLogs to filter preview components * chore: extract SampleLogsResponseDisplay for reuse * feat: bring together pipeline preview modal content * chore: generalize SampleLogsResponse to LogsResponse * feat: finish wiring up pipeline preview flow * chore: separate response models for useSampleLogs and usePipelinePreview * chore: require explicit action for simulation after changing logs sample search interval * feat: error and empty state for pipeline simulation result * chore: look for error in sample logs response data too * chore: remove tests for deleted component & update snapshot for PipelineAction tests * chore: minor cleanup * chore: address feedback: move timestamp normalization out of api file * chore: address feedback: use axios directly in pipeline preview API call * chore: address feedback: use REACT_QUERY_KEY constant for useQuery key * chore: minor cleanup --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com>
270 lines
7.3 KiB
TypeScript
270 lines
7.3 KiB
TypeScript
import { PlusCircleOutlined } from '@ant-design/icons';
|
|
import { TableLocale } from 'antd/es/table/interface';
|
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
|
import React, { useCallback, useMemo } from 'react';
|
|
import { DndProvider } from 'react-dnd';
|
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
import { useTranslation } from 'react-i18next';
|
|
import {
|
|
ActionMode,
|
|
ActionType,
|
|
PipelineData,
|
|
ProcessorData,
|
|
} from 'types/api/pipeline/def';
|
|
|
|
import { tableComponents } from '../config';
|
|
import { ModalFooterTitle } from '../styles';
|
|
import { AlertMessage } from '.';
|
|
import { processorColumns } from './config';
|
|
import { FooterButton, StyledTable } from './styles';
|
|
import DragAction from './TableComponents/DragAction';
|
|
import ProcessorActions from './TableComponents/ProcessorActions';
|
|
import {
|
|
getEditedDataSource,
|
|
getProcessorUpdatedRow,
|
|
getRecordIndex,
|
|
getTableColumn,
|
|
} from './utils';
|
|
|
|
function PipelineExpandView({
|
|
handleAlert,
|
|
setActionType,
|
|
processorEditAction,
|
|
isActionMode,
|
|
setShowSaveButton,
|
|
expandedPipelineData,
|
|
setExpandedPipelineData,
|
|
prevPipelineData,
|
|
}: PipelineExpandViewProps): JSX.Element {
|
|
const { t } = useTranslation(['pipeline']);
|
|
const isDarkMode = useIsDarkMode();
|
|
const isEditingActionMode = isActionMode === ActionMode.Editing;
|
|
|
|
const deleteProcessorHandler = useCallback(
|
|
(record: ProcessorData) => (): void => {
|
|
setShowSaveButton(ActionMode.Editing);
|
|
if (expandedPipelineData && expandedPipelineData?.config) {
|
|
const filteredData = expandedPipelineData?.config.filter(
|
|
(item: ProcessorData) => item.id !== record.id,
|
|
);
|
|
const pipelineData = { ...expandedPipelineData };
|
|
pipelineData.config = filteredData;
|
|
pipelineData.config.forEach((item, index) => {
|
|
const obj = item;
|
|
obj.orderId = index + 1;
|
|
});
|
|
for (let i = 0; i < pipelineData.config.length - 1; i += 1) {
|
|
pipelineData.config[i].output = pipelineData.config[i + 1].id;
|
|
}
|
|
delete pipelineData.config[pipelineData.config.length - 1]?.output;
|
|
setExpandedPipelineData(pipelineData);
|
|
}
|
|
},
|
|
[expandedPipelineData, setShowSaveButton, setExpandedPipelineData],
|
|
);
|
|
|
|
const processorDeleteAction = useCallback(
|
|
(record: ProcessorData) => (): void => {
|
|
handleAlert({
|
|
title: `${t('delete_processor')} : ${record.name}?`,
|
|
descrition: t('delete_processor_description'),
|
|
buttontext: t('delete'),
|
|
onOk: deleteProcessorHandler(record),
|
|
});
|
|
},
|
|
[handleAlert, deleteProcessorHandler, t],
|
|
);
|
|
|
|
const onSwitchProcessorChange = useCallback(
|
|
(checked: boolean, record: ProcessorData): void => {
|
|
if (expandedPipelineData && expandedPipelineData?.config) {
|
|
setShowSaveButton(ActionMode.Editing);
|
|
const findRecordIndex = getRecordIndex(
|
|
expandedPipelineData?.config,
|
|
record,
|
|
'id',
|
|
);
|
|
const updateSwitch = {
|
|
...expandedPipelineData?.config[findRecordIndex],
|
|
enabled: checked,
|
|
};
|
|
const editedData = getEditedDataSource(
|
|
expandedPipelineData?.config,
|
|
record,
|
|
'id',
|
|
updateSwitch,
|
|
);
|
|
const modifiedProcessorData = { ...expandedPipelineData };
|
|
modifiedProcessorData.config = editedData;
|
|
|
|
setExpandedPipelineData(modifiedProcessorData);
|
|
}
|
|
},
|
|
[expandedPipelineData, setExpandedPipelineData, setShowSaveButton],
|
|
);
|
|
|
|
const columns = useMemo(() => {
|
|
const fieldColumns = getTableColumn(processorColumns);
|
|
if (isEditingActionMode) {
|
|
fieldColumns.push(
|
|
{
|
|
title: '',
|
|
dataIndex: 'action',
|
|
key: 'action',
|
|
render: (_value, record): JSX.Element => (
|
|
<ProcessorActions
|
|
editAction={processorEditAction(record)}
|
|
deleteAction={processorDeleteAction(record)}
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
title: '',
|
|
dataIndex: 'enabled',
|
|
key: 'enabled',
|
|
render: (value, record) => (
|
|
<DragAction
|
|
isEnabled={value}
|
|
onChange={(checked: boolean): void =>
|
|
onSwitchProcessorChange(checked, record)
|
|
}
|
|
/>
|
|
),
|
|
},
|
|
);
|
|
}
|
|
return fieldColumns;
|
|
}, [
|
|
isEditingActionMode,
|
|
processorEditAction,
|
|
processorDeleteAction,
|
|
onSwitchProcessorChange,
|
|
]);
|
|
|
|
const reorderProcessorRow = useCallback(
|
|
(updatedRow: ProcessorData[]) => (): void => {
|
|
setShowSaveButton(ActionMode.Editing);
|
|
if (expandedPipelineData) {
|
|
const modifiedProcessorData = { ...expandedPipelineData };
|
|
modifiedProcessorData.config = updatedRow;
|
|
setExpandedPipelineData(modifiedProcessorData);
|
|
}
|
|
},
|
|
[expandedPipelineData, setShowSaveButton, setExpandedPipelineData],
|
|
);
|
|
|
|
const onCancelReorderProcessorRow = useCallback(
|
|
() => (): void => {
|
|
if (expandedPipelineData) setExpandedPipelineData(expandedPipelineData);
|
|
},
|
|
[expandedPipelineData, setExpandedPipelineData],
|
|
);
|
|
|
|
const moveProcessorRow = useCallback(
|
|
(dragIndex: number, hoverIndex: number) => {
|
|
if (expandedPipelineData?.config && isEditingActionMode) {
|
|
const updatedRow = getProcessorUpdatedRow(
|
|
expandedPipelineData?.config,
|
|
dragIndex,
|
|
hoverIndex,
|
|
);
|
|
handleAlert({
|
|
title: t('reorder_processor'),
|
|
descrition: t('reorder_processor_description'),
|
|
buttontext: t('reorder'),
|
|
onOk: reorderProcessorRow(updatedRow),
|
|
onCancel: onCancelReorderProcessorRow(),
|
|
});
|
|
}
|
|
},
|
|
[
|
|
expandedPipelineData?.config,
|
|
isEditingActionMode,
|
|
handleAlert,
|
|
t,
|
|
reorderProcessorRow,
|
|
onCancelReorderProcessorRow,
|
|
],
|
|
);
|
|
|
|
const addNewProcessorHandler = useCallback((): void => {
|
|
setActionType(ActionType.AddProcessor);
|
|
}, [setActionType]);
|
|
|
|
const footer = useCallback((): JSX.Element | undefined => {
|
|
const prevPipelinesCount = prevPipelineData?.length || 0;
|
|
if (prevPipelinesCount === 0 || isEditingActionMode) {
|
|
return (
|
|
<FooterButton type="link" onClick={addNewProcessorHandler}>
|
|
<PlusCircleOutlined />
|
|
<ModalFooterTitle>{t('add_new_processor')}</ModalFooterTitle>
|
|
</FooterButton>
|
|
);
|
|
}
|
|
return undefined;
|
|
}, [isEditingActionMode, prevPipelineData, addNewProcessorHandler, t]);
|
|
|
|
const onRowHandler = (
|
|
_data: ProcessorData,
|
|
index?: number,
|
|
): React.HTMLAttributes<unknown> =>
|
|
({
|
|
index,
|
|
moveRow: moveProcessorRow,
|
|
} as React.HTMLAttributes<unknown>);
|
|
|
|
const processorData = useMemo(
|
|
() =>
|
|
expandedPipelineData?.config &&
|
|
expandedPipelineData?.config.map(
|
|
(item: ProcessorData): ProcessorData => ({
|
|
id: item.id,
|
|
orderId: item.orderId,
|
|
type: item.type,
|
|
name: item.name,
|
|
enabled: item.enabled,
|
|
}),
|
|
),
|
|
[expandedPipelineData],
|
|
);
|
|
|
|
const getLocales = (): TableLocale => ({
|
|
emptyText: <span />,
|
|
});
|
|
|
|
return (
|
|
<DndProvider backend={HTML5Backend}>
|
|
<StyledTable
|
|
locale={getLocales()}
|
|
isDarkMode={isDarkMode}
|
|
showHeader={false}
|
|
columns={columns}
|
|
rowKey="name"
|
|
size="small"
|
|
components={tableComponents}
|
|
dataSource={processorData}
|
|
pagination={false}
|
|
onRow={onRowHandler}
|
|
footer={footer}
|
|
/>
|
|
</DndProvider>
|
|
);
|
|
}
|
|
|
|
PipelineExpandView.defaultProps = {
|
|
expandedPipelineData: {},
|
|
};
|
|
|
|
interface PipelineExpandViewProps {
|
|
handleAlert: (props: AlertMessage) => void;
|
|
setActionType: (actionType?: ActionType) => void;
|
|
processorEditAction: (record: ProcessorData) => () => void;
|
|
isActionMode: string;
|
|
setShowSaveButton: (actionMode: ActionMode) => void;
|
|
expandedPipelineData?: PipelineData;
|
|
setExpandedPipelineData: (data: PipelineData) => void;
|
|
prevPipelineData: Array<PipelineData>;
|
|
}
|
|
|
|
export default PipelineExpandView;
|