mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-30 04:31:59 +08:00

* feat: pipeline page (#2168) * feat: Added POC of drag row table * fix: resolved eslint issue * fix: resolved webpack issue * fix: config changes * fix: removed unwanted code of antd table * feat: added icon on expand row * feat: ui of modal, alertbox & drag table * feat: added DraggableTableRow component * fix: issue on row reorder alert message * fix: styling & dynamic name when delete pipeline * feat: added edit modal ui * fix: modal on create or edit open issue * fix: types issue * fix: text change & styled component * fix: added react-i18next to translate constant * fix: removed webpack change * fix: webpack change * feat: added processor expand row poc * fix: linting issue * fix: sonar gate issues * fix: processor expand ui break issue * fix: added missing types * feat: added create & delete logic * fix: types issue * feat: added edit pipeline & processor logic * fix: added diff. local file for pipeline * fix: suggested changes for pipeline * fix: order of key name on useTranslation * test: added test cases * fix: code level changes * fix: code level changes * fix: edit tags issue * fix: changed inline function to handler * test: resolved test cases issue * fix: code level changes * fix: changed file structure * fix: added required styled component * feat: added common utils functions * fix: code level changes * test: added test cases * test: added more test cases * fix: abstracted code of pipeline column * fix: added utils for DraggableTableRow * fix: issue on drag at DraggableTableRow * test: added more test case * fix: abstracted code of processor column * fix: removed playwrite test * fix: abstracted code render method * fix: text correction pipline -> pipeline * test: added more test cases * fix: add pipeline form restructure * fix: add processor form restructure * fix: processor type issue * fix: forms abstraction * fix: on finish form abstraction * test: additional test cases of utils * feat: added new ui as per save config * fix: test cases issue * feat: added redux for data set managment * fix: updated logic of redux * fix: removed unused code * fix: modified pipeline data onchangeof processor data * fix: removed redux from pipeline * fix: test cases prop issue resolved * fix: reset field on add data * fix: sonar gate code smell * fix: sonar gate code duplicated issue * fix: code level changes * fix: add processor issue * fix: code level changes * chore: some of the types are updated * fix: inline css into styled component * fix: jsx element & type * fix: username, email object issue * fix: username, email object issue * fix: types issues * fix: inline condition removed * fix: code level changes * feat: integrated listing of pipeline & processor api * feat: integrated post api of pipeline & processor poc * feat: integrated delete api of pipeline & processor * fix: create pipeline api payload issue * fix: updated jest test cases * fix: processor order id ui issue * fix: create pipeline issue on payload * fix: add processor payload issue resolved * fix: added missing field on add pipeline * fix: processor type selection issue * fix: test cases updated * fix: sonar gate failed issue * fix: removed inline function * fix: enable switch logic at pipeline & processor level * fix: retain removed from type list * fix: build issue on jest * fix: test cases updated * chore: config is updated * chore: test snapshot is updated * fix: test cases updated * chore: test snapshot is updated * chore: test snapshot is updated * fix: api & ui integration of change history tab * chore: webpack is updated * test: test is updated * chore: build is fixed * chore: react-dnd is downgraded * chore: process is added * chore: build is fixed * chore: react-dnd is updated * fix: suggested changes * fix: tab pane issue * fix: build issue * fix: code level changes * fix: code level changes * fix: added types in def file * fix: code level changes * fix: test cases updated * fix: error message notification * fix: after reorder pipeline expand is not working * fix: on add of processor added optional field * feat: added search pipeline feature * fix: sonar gate failed issue * fix: processor reorder issue * fix: processor reorder output property issue * feat: added json_parser processor * fix: scalable code of component of column * fix: processor reorder issue * fix: search pipeline issue * fix: creating a pipeline description is an optional field * fix: nitya's suggested changes * fix: test cases updated * fix: edit data pipeline & processor * fix: pipeline cancel issue * fix: edit processor wrong payload * fix: processor reorder issue at payload * fix: pipeline undefined handle * fix: pipeline no data case * fix: updated test case * fix: resolved pipeline undefined issue * fix: processor data case * feat: added submenu system for pipeline * fix: pipeline suggested changes * fix: updated test case * fix: pipeline suggested changes * fix: test cases updated * test: updated test cases * chore: build issue * fix: pipeline level changes * fix: pipeline page access issue * fix: resolved issue on add operator when pipeline is empty * test: jest test cases updated * chore: try signoz cloud link is updated (#2928) * fix: solve history page issue --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com> Co-authored-by: Vishal Sharma <makeavish786@gmail.com> Co-authored-by: Pranay Prateek <pranay@signoz.io> * chore: merge conflicts is resolved * test: snaps are updated * fix: remove unused dependency on process^0.11.10 --------- Co-authored-by: Chintan Sudani <46838508+techchintan@users.noreply.github.com> Co-authored-by: Vishal Sharma <makeavish786@gmail.com> Co-authored-by: Pranay Prateek <pranay@signoz.io> Co-authored-by: Raj <rkssisodiya@gmail.com>
468 lines
12 KiB
TypeScript
468 lines
12 KiB
TypeScript
import { ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
|
|
import { Modal, Table } from 'antd';
|
|
import { ExpandableConfig } from 'antd/es/table/interface';
|
|
import savePipeline from 'api/pipeline/post';
|
|
import { useNotifications } from 'hooks/useNotifications';
|
|
import { cloneDeep } from 'lodash-es';
|
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
import { DndProvider } from 'react-dnd';
|
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
import { useTranslation } from 'react-i18next';
|
|
import {
|
|
ActionMode,
|
|
ActionType,
|
|
Pipeline,
|
|
PipelineData,
|
|
ProcessorData,
|
|
} from 'types/api/pipeline/def';
|
|
import { v4 } from 'uuid';
|
|
|
|
import { tableComponents } from '../config';
|
|
import AddNewPipeline from './AddNewPipeline';
|
|
import AddNewProcessor from './AddNewProcessor';
|
|
import { pipelineColumns } from './config';
|
|
import ModeAndConfiguration from './ModeAndConfiguration';
|
|
import PipelineExpanView from './PipelineExpandView';
|
|
import SaveConfigButton from './SaveConfigButton';
|
|
import {
|
|
AlertContentWrapper,
|
|
AlertModalTitle,
|
|
Container,
|
|
FooterButton,
|
|
} from './styles';
|
|
import DragAction from './TableComponents/DragAction';
|
|
import PipelineActions from './TableComponents/PipelineActions';
|
|
import TableExpandIcon from './TableComponents/TableExpandIcon';
|
|
import {
|
|
getDataOnSearch,
|
|
getEditedDataSource,
|
|
getElementFromArray,
|
|
getRecordIndex,
|
|
getTableColumn,
|
|
getUpdatedRow,
|
|
} from './utils';
|
|
|
|
function PipelineListsView({
|
|
isActionType,
|
|
setActionType,
|
|
isActionMode,
|
|
setActionMode,
|
|
piplineData,
|
|
refetchPipelineLists,
|
|
pipelineSearchValue,
|
|
}: PipelineListsViewProps): JSX.Element {
|
|
const { t } = useTranslation(['pipeline', 'common']);
|
|
const [modal, contextHolder] = Modal.useModal();
|
|
const { notifications } = useNotifications();
|
|
const [prevPipelineData, setPrevPipelineData] = useState<Array<PipelineData>>(
|
|
cloneDeep(piplineData?.pipelines),
|
|
);
|
|
const [currPipelineData, setCurrPipelineData] = useState<Array<PipelineData>>(
|
|
cloneDeep(piplineData?.pipelines),
|
|
);
|
|
const [
|
|
expandedPipelineData,
|
|
setExpandedPipelineData,
|
|
] = useState<PipelineData>();
|
|
const [
|
|
selectedProcessorData,
|
|
setSelectedProcessorData,
|
|
] = useState<ProcessorData>();
|
|
const [
|
|
selectedPipelineData,
|
|
setSelectedPipelineData,
|
|
] = useState<PipelineData>();
|
|
const [expandedRowKeys, setExpandedRowKeys] = useState<Array<string>>();
|
|
const [showSaveButton, setShowSaveButton] = useState<string>();
|
|
const isEditingActionMode = isActionMode === ActionMode.Editing;
|
|
|
|
useEffect(() => {
|
|
if (pipelineSearchValue === '') setCurrPipelineData(piplineData?.pipelines);
|
|
if (pipelineSearchValue !== '') {
|
|
const filterData = piplineData?.pipelines.filter((data: PipelineData) =>
|
|
getDataOnSearch(data as never, pipelineSearchValue),
|
|
);
|
|
setCurrPipelineData(filterData);
|
|
}
|
|
}, [pipelineSearchValue, piplineData?.pipelines]);
|
|
|
|
const handleAlert = useCallback(
|
|
({ title, descrition, buttontext, onCancel, onOk }: AlertMessage) => {
|
|
modal.confirm({
|
|
title: <AlertModalTitle>{title}</AlertModalTitle>,
|
|
icon: <ExclamationCircleOutlined />,
|
|
content: <AlertContentWrapper>{descrition}</AlertContentWrapper>,
|
|
okText: <span>{buttontext}</span>,
|
|
cancelText: <span>{t('cancel')}</span>,
|
|
onOk,
|
|
onCancel,
|
|
});
|
|
},
|
|
[modal, t],
|
|
);
|
|
|
|
const pipelineEditAction = useCallback(
|
|
(record: PipelineData) => (): void => {
|
|
setActionType(ActionType.EditPipeline);
|
|
setSelectedPipelineData(record);
|
|
},
|
|
[setActionType],
|
|
);
|
|
|
|
const pipelineDeleteHandler = useCallback(
|
|
(record: PipelineData) => (): void => {
|
|
setShowSaveButton(ActionMode.Editing);
|
|
const filteredData = getElementFromArray(currPipelineData, record, 'id');
|
|
filteredData.forEach((item, index) => {
|
|
const obj = item;
|
|
obj.orderId = index + 1;
|
|
});
|
|
setCurrPipelineData(filteredData);
|
|
},
|
|
[currPipelineData],
|
|
);
|
|
|
|
const pipelineDeleteAction = useCallback(
|
|
(record: PipelineData) => (): void => {
|
|
handleAlert({
|
|
title: `${t('delete_pipeline')} : ${record.name}?`,
|
|
descrition: t('delete_pipeline_description'),
|
|
buttontext: t('delete'),
|
|
onOk: pipelineDeleteHandler(record),
|
|
});
|
|
},
|
|
[handleAlert, pipelineDeleteHandler, t],
|
|
);
|
|
|
|
const processorEditAction = useCallback(
|
|
(record: ProcessorData) => (): void => {
|
|
setActionType(ActionType.EditProcessor);
|
|
setSelectedProcessorData(record);
|
|
},
|
|
[setActionType],
|
|
);
|
|
|
|
const onSwitchPipelineChange = useCallback(
|
|
(checked: boolean, record: PipelineData): void => {
|
|
setShowSaveButton(ActionMode.Editing);
|
|
const findRecordIndex = getRecordIndex(currPipelineData, record, 'id');
|
|
const updateSwitch = {
|
|
...currPipelineData[findRecordIndex],
|
|
enabled: checked,
|
|
};
|
|
const editedPipelineData = getEditedDataSource(
|
|
currPipelineData,
|
|
record,
|
|
'id',
|
|
updateSwitch,
|
|
);
|
|
setCurrPipelineData(editedPipelineData);
|
|
},
|
|
[currPipelineData],
|
|
);
|
|
|
|
const columns = useMemo(() => {
|
|
const fieldColumns = getTableColumn(pipelineColumns);
|
|
if (isEditingActionMode) {
|
|
fieldColumns.push(
|
|
{
|
|
title: 'Actions',
|
|
dataIndex: 'smartAction',
|
|
key: 'smartAction',
|
|
align: 'center',
|
|
render: (_value, record): JSX.Element => (
|
|
<PipelineActions
|
|
isPipelineAction
|
|
editAction={pipelineEditAction(record)}
|
|
deleteAction={pipelineDeleteAction(record)}
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
title: '',
|
|
dataIndex: 'enabled',
|
|
key: 'enabled',
|
|
render: (value, record) => (
|
|
<DragAction
|
|
isEnabled={value}
|
|
onChange={(checked: boolean): void =>
|
|
onSwitchPipelineChange(checked, record)
|
|
}
|
|
/>
|
|
),
|
|
},
|
|
);
|
|
}
|
|
return fieldColumns;
|
|
}, [
|
|
isEditingActionMode,
|
|
pipelineEditAction,
|
|
pipelineDeleteAction,
|
|
onSwitchPipelineChange,
|
|
]);
|
|
|
|
const updatePipelineSequence = useCallback(
|
|
(updatedRow: PipelineData[]) => (): void => {
|
|
setShowSaveButton(ActionMode.Editing);
|
|
setCurrPipelineData(updatedRow);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const onCancelPipelineSequence = useCallback(
|
|
(rawData: PipelineData[]) => (): void => {
|
|
setCurrPipelineData(rawData);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const movePipelineRow = useCallback(
|
|
(dragIndex: number, hoverIndex: number) => {
|
|
if (currPipelineData && isEditingActionMode) {
|
|
const rawData = currPipelineData;
|
|
const updatedRow = getUpdatedRow(currPipelineData, dragIndex, hoverIndex);
|
|
updatedRow.forEach((item, index) => {
|
|
const obj = item;
|
|
obj.orderId = index + 1;
|
|
});
|
|
handleAlert({
|
|
title: t('reorder_pipeline'),
|
|
descrition: t('reorder_pipeline_description'),
|
|
buttontext: t('reorder'),
|
|
onOk: updatePipelineSequence(updatedRow),
|
|
onCancel: onCancelPipelineSequence(rawData),
|
|
});
|
|
}
|
|
},
|
|
[
|
|
currPipelineData,
|
|
isEditingActionMode,
|
|
handleAlert,
|
|
t,
|
|
updatePipelineSequence,
|
|
onCancelPipelineSequence,
|
|
],
|
|
);
|
|
|
|
const expandedRowView = useCallback(
|
|
(): JSX.Element => (
|
|
<PipelineExpanView
|
|
handleAlert={handleAlert}
|
|
isActionMode={isActionMode}
|
|
setActionType={setActionType}
|
|
processorEditAction={processorEditAction}
|
|
setShowSaveButton={setShowSaveButton}
|
|
expandedPipelineData={expandedPipelineData}
|
|
setExpandedPipelineData={setExpandedPipelineData}
|
|
prevPipelineData={prevPipelineData}
|
|
/>
|
|
),
|
|
[
|
|
handleAlert,
|
|
processorEditAction,
|
|
isActionMode,
|
|
expandedPipelineData,
|
|
setActionType,
|
|
prevPipelineData,
|
|
],
|
|
);
|
|
|
|
const onExpand = useCallback(
|
|
(expanded: boolean, record: PipelineData): void => {
|
|
const keys = [];
|
|
if (expanded && record.id) {
|
|
keys.push(record?.id);
|
|
}
|
|
setExpandedRowKeys(keys);
|
|
setExpandedPipelineData(record);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const getExpandIcon = (
|
|
expanded: boolean,
|
|
onExpand: (record: PipelineData, e: React.MouseEvent<HTMLElement>) => void,
|
|
record: PipelineData,
|
|
): JSX.Element => (
|
|
<TableExpandIcon expanded={expanded} onExpand={onExpand} record={record} />
|
|
);
|
|
|
|
const addNewPipelineHandler = useCallback((): void => {
|
|
setActionType(ActionType.AddPipeline);
|
|
}, [setActionType]);
|
|
|
|
const footer = useCallback((): JSX.Element | undefined => {
|
|
if (isEditingActionMode) {
|
|
return (
|
|
<FooterButton
|
|
type="link"
|
|
onClick={addNewPipelineHandler}
|
|
icon={<PlusOutlined />}
|
|
>
|
|
{t('add_new_pipeline')}
|
|
</FooterButton>
|
|
);
|
|
}
|
|
return undefined;
|
|
}, [isEditingActionMode, addNewPipelineHandler, t]);
|
|
|
|
const onSaveConfigurationHandler = useCallback(async () => {
|
|
const modifiedPipelineData = currPipelineData.map((item: PipelineData) => {
|
|
const pipelineData = item;
|
|
if (
|
|
expandedPipelineData !== undefined &&
|
|
item.id === expandedPipelineData?.id
|
|
) {
|
|
pipelineData.config = expandedPipelineData?.config;
|
|
}
|
|
pipelineData.config = item.config;
|
|
return pipelineData;
|
|
});
|
|
modifiedPipelineData.forEach((item: PipelineData) => {
|
|
const pipelineData = item;
|
|
delete pipelineData?.id;
|
|
return pipelineData;
|
|
});
|
|
const response = await savePipeline({
|
|
data: { pipelines: modifiedPipelineData },
|
|
});
|
|
if (response.statusCode === 200) {
|
|
refetchPipelineLists();
|
|
setActionMode(ActionMode.Viewing);
|
|
setShowSaveButton(undefined);
|
|
setCurrPipelineData(response.payload?.pipelines);
|
|
setPrevPipelineData(response.payload?.pipelines);
|
|
} else {
|
|
modifiedPipelineData.forEach((item: PipelineData) => {
|
|
const pipelineData = item;
|
|
pipelineData.id = v4();
|
|
return pipelineData;
|
|
});
|
|
setActionMode(ActionMode.Editing);
|
|
setShowSaveButton(ActionMode.Editing);
|
|
notifications.error({
|
|
message: 'Error',
|
|
description: response.error || t('something_went_wrong'),
|
|
});
|
|
setCurrPipelineData(modifiedPipelineData);
|
|
setPrevPipelineData(modifiedPipelineData);
|
|
}
|
|
}, [
|
|
currPipelineData,
|
|
expandedPipelineData,
|
|
notifications,
|
|
refetchPipelineLists,
|
|
setActionMode,
|
|
t,
|
|
]);
|
|
|
|
const onCancelConfigurationHandler = useCallback((): void => {
|
|
setActionMode(ActionMode.Viewing);
|
|
setShowSaveButton(undefined);
|
|
prevPipelineData.forEach((item, index) => {
|
|
const obj = item;
|
|
obj.orderId = index + 1;
|
|
if (obj.config) {
|
|
obj.config?.forEach((configItem, index) => {
|
|
const config = configItem;
|
|
config.orderId = index + 1;
|
|
});
|
|
for (let i = 0; i < obj.config.length - 1; i += 1) {
|
|
obj.config[i].output = obj.config[i + 1].id;
|
|
}
|
|
}
|
|
});
|
|
setCurrPipelineData(prevPipelineData);
|
|
setExpandedRowKeys([]);
|
|
}, [prevPipelineData, setActionMode]);
|
|
|
|
const onRowHandler = (
|
|
_data: PipelineData,
|
|
index?: number,
|
|
): React.HTMLAttributes<unknown> =>
|
|
({
|
|
index,
|
|
moveRow: movePipelineRow,
|
|
} as React.HTMLAttributes<unknown>);
|
|
|
|
const expandableConfig: ExpandableConfig<PipelineData> = {
|
|
expandedRowKeys,
|
|
onExpand,
|
|
expandIcon: ({ expanded, onExpand, record }: ExpandRowConfig) =>
|
|
getExpandIcon(expanded, onExpand, record),
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{contextHolder}
|
|
<AddNewPipeline
|
|
isActionType={isActionType}
|
|
setActionType={setActionType}
|
|
selectedPipelineData={selectedPipelineData}
|
|
setShowSaveButton={setShowSaveButton}
|
|
setCurrPipelineData={setCurrPipelineData}
|
|
currPipelineData={currPipelineData}
|
|
/>
|
|
<AddNewProcessor
|
|
isActionType={isActionType}
|
|
setActionType={setActionType}
|
|
selectedProcessorData={selectedProcessorData}
|
|
setShowSaveButton={setShowSaveButton}
|
|
expandedPipelineData={expandedPipelineData}
|
|
setExpandedPipelineData={setExpandedPipelineData}
|
|
/>
|
|
<Container>
|
|
<ModeAndConfiguration
|
|
isActionMode={isActionMode}
|
|
verison={piplineData?.version}
|
|
/>
|
|
<DndProvider backend={HTML5Backend}>
|
|
<Table
|
|
rowKey="id"
|
|
columns={columns}
|
|
expandedRowRender={expandedRowView}
|
|
expandable={expandableConfig}
|
|
components={tableComponents}
|
|
dataSource={currPipelineData}
|
|
onRow={onRowHandler}
|
|
footer={footer}
|
|
pagination={false}
|
|
/>
|
|
</DndProvider>
|
|
{showSaveButton && (
|
|
<SaveConfigButton
|
|
onSaveConfigurationHandler={onSaveConfigurationHandler}
|
|
onCancelConfigurationHandler={onCancelConfigurationHandler}
|
|
/>
|
|
)}
|
|
</Container>
|
|
</>
|
|
);
|
|
}
|
|
|
|
interface PipelineListsViewProps {
|
|
isActionType: string;
|
|
setActionType: (actionType?: ActionType) => void;
|
|
isActionMode: string;
|
|
setActionMode: (actionMode: ActionMode) => void;
|
|
piplineData: Pipeline;
|
|
refetchPipelineLists: VoidFunction;
|
|
pipelineSearchValue: string;
|
|
}
|
|
|
|
interface ExpandRowConfig {
|
|
expanded: boolean;
|
|
onExpand: (record: PipelineData, e: React.MouseEvent<HTMLElement>) => void;
|
|
record: PipelineData;
|
|
}
|
|
|
|
export interface AlertMessage {
|
|
title: string;
|
|
descrition: string;
|
|
buttontext: string;
|
|
onOk: VoidFunction;
|
|
onCancel?: VoidFunction;
|
|
}
|
|
|
|
export default PipelineListsView;
|