diff --git a/frontend/public/locales/en/titles.json b/frontend/public/locales/en/titles.json index bea44d8a18..24b0f45269 100644 --- a/frontend/public/locales/en/titles.json +++ b/frontend/public/locales/en/titles.json @@ -32,6 +32,7 @@ "LOGS": "SigNoz | Logs", "LOGS_EXPLORER": "SigNoz | Logs Explorer", "LIVE_LOGS": "SigNoz | Live Logs", + "LOGS_PIPELINES": "SigNoz | Logs Pipelines", "HOME_PAGE": "Open source Observability Platform | SigNoz", "PASSWORD_RESET": "SigNoz | Password Reset", "LIST_LICENSES": "SigNoz | List of Licenses", diff --git a/frontend/src/AppRoutes/routes.ts b/frontend/src/AppRoutes/routes.ts index dda9d68e1d..2f4142c809 100644 --- a/frontend/src/AppRoutes/routes.ts +++ b/frontend/src/AppRoutes/routes.ts @@ -282,10 +282,10 @@ const routes: AppRoutes[] = [ isPrivate: false, }, { - path: ROUTES.PIPELINES, + path: ROUTES.LOGS_PIPELINES, exact: true, component: PipelinePage, - key: 'PIPELINES', + key: 'LOGS_PIPELINES', isPrivate: true, }, { diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts index 80c032a1be..208e83e525 100644 --- a/frontend/src/constants/routes.ts +++ b/frontend/src/constants/routes.ts @@ -31,13 +31,12 @@ const ROUTES = { LOGS: '/logs', LOGS_EXPLORER: '/logs-explorer', LIVE_LOGS: '/logs-explorer/live', + LOGS_PIPELINES: '/pipelines', HOME_PAGE: '/', PASSWORD_RESET: '/password-reset', LIST_LICENSES: '/licenses', LOGS_INDEX_FIELDS: '/logs-explorer/index-fields', - LOGS_PIPELINE: '/logs-explorer/pipeline', TRACE_EXPLORER: '/trace-explorer', - PIPELINES: '/pipelines', BILLING: '/billing', SUPPORT: '/support', WORKSPACE_LOCKED: '/workspace-locked', diff --git a/frontend/src/container/PipelinePage/Layouts/Pipeline/PipelinesSearchSection.tsx b/frontend/src/container/PipelinePage/Layouts/Pipeline/PipelinesSearchSection.tsx index ae830cae7f..40d8570212 100644 --- a/frontend/src/container/PipelinePage/Layouts/Pipeline/PipelinesSearchSection.tsx +++ b/frontend/src/container/PipelinePage/Layouts/Pipeline/PipelinesSearchSection.tsx @@ -1,5 +1,6 @@ import { Input } from 'antd'; -import React, { Dispatch, SetStateAction, useCallback } from 'react'; +import { debounce } from 'lodash-es'; +import { BaseSyntheticEvent, Dispatch, SetStateAction } from 'react'; import { useTranslation } from 'react-i18next'; function PipelinesSearchSection({ @@ -7,18 +8,18 @@ function PipelinesSearchSection({ }: PipelinesSearchSectionProps): JSX.Element { const { t } = useTranslation(['pipeline']); - const onSeachHandler = useCallback( - (event: React.SetStateAction) => { - setPipelineSearchValue(event); - }, - [setPipelineSearchValue], - ); + const handleSearch = (searchEv: BaseSyntheticEvent): void => { + setPipelineSearchValue(searchEv?.target?.value || ''); + }; + + const debouncedHandleSearch = debounce(handleSearch, 300); return ( - ); } diff --git a/frontend/src/container/PipelinePage/PipelineListsView/PipelineExpandView.tsx b/frontend/src/container/PipelinePage/PipelineListsView/PipelineExpandView.tsx index e839a10225..1e5b1add33 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/PipelineExpandView.tsx +++ b/frontend/src/container/PipelinePage/PipelineListsView/PipelineExpandView.tsx @@ -14,8 +14,8 @@ import { import { tableComponents } from '../config'; import { ModalFooterTitle } from '../styles'; -import { AlertMessage } from '.'; import { processorColumns } from './config'; +import { AlertMessage } from './PipelineListsView'; import { FooterButton, StyledTable } from './styles'; import DragAction from './TableComponents/DragAction'; import ProcessorActions from './TableComponents/ProcessorActions'; diff --git a/frontend/src/container/PipelinePage/PipelineListsView/PipelineListsView.tsx b/frontend/src/container/PipelinePage/PipelineListsView/PipelineListsView.tsx new file mode 100644 index 0000000000..e7211c059c --- /dev/null +++ b/frontend/src/container/PipelinePage/PipelineListsView/PipelineListsView.tsx @@ -0,0 +1,489 @@ +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/cloneDeep'; +import React, { useCallback, 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 PreviewAction from './TableComponents/PipelineActions/components/PreviewAction'; +import TableExpandIcon from './TableComponents/TableExpandIcon'; +import { + getDataOnSearch, + getEditedDataSource, + getElementFromArray, + getRecordIndex, + getTableColumn, + getUpdatedRow, +} from './utils'; + +function PipelineListsView({ + isActionType, + setActionType, + isActionMode, + setActionMode, + pipelineData, + refetchPipelineLists, + pipelineSearchValue, +}: PipelineListsViewProps): JSX.Element { + const { t } = useTranslation(['pipeline', 'common']); + const [modal, contextHolder] = Modal.useModal(); + const { notifications } = useNotifications(); + const [prevPipelineData, setPrevPipelineData] = useState>( + cloneDeep(pipelineData?.pipelines || []), + ); + const [currPipelineData, setCurrPipelineData] = useState>( + cloneDeep(pipelineData?.pipelines || []), + ); + + const [expandedPipelineId, setExpandedPipelineId] = useState< + string | undefined + >(undefined); + const expandedPipelineData = useCallback( + () => currPipelineData?.find((p) => p.id === expandedPipelineId), + [currPipelineData, expandedPipelineId], + ); + const setExpandedPipelineData = useCallback( + (newData: PipelineData): void => { + if (expandedPipelineId) { + const pipelineIdx = currPipelineData?.findIndex( + (p) => p.id === expandedPipelineId, + ); + if (pipelineIdx >= 0) { + const newPipelineData = [...currPipelineData]; + newPipelineData[pipelineIdx] = newData; + setCurrPipelineData(newPipelineData); + } + } + }, + [expandedPipelineId, currPipelineData], + ); + + const [ + selectedProcessorData, + setSelectedProcessorData, + ] = useState(); + + const [ + selectedPipelineData, + setSelectedPipelineData, + ] = useState(); + + const [expandedRowKeys, setExpandedRowKeys] = useState>(); + const [showSaveButton, setShowSaveButton] = useState(); + const isEditingActionMode = isActionMode === ActionMode.Editing; + + const visibleCurrPipelines = useMemo((): Array => { + if (pipelineSearchValue === '') { + return currPipelineData; + } + return currPipelineData.filter((data) => + getDataOnSearch(data as never, pipelineSearchValue), + ); + }, [currPipelineData, pipelineSearchValue]); + + const handleAlert = useCallback( + ({ title, descrition, buttontext, onCancel, onOk }: AlertMessage) => { + modal.confirm({ + title: {title}, + icon: , + content: {descrition}, + okText: {buttontext}, + cancelText: {t('cancel')}, + 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 => ( + + ), + }, + { + title: '', + dataIndex: 'enabled', + key: 'enabled', + render: (value, record) => ( + + onSwitchPipelineChange(checked, record) + } + /> + ), + }, + ); + } else { + fieldColumns.push({ + title: 'Actions', + dataIndex: 'smartAction', + key: 'smartAction', + align: 'center', + render: (_value, record): JSX.Element => ( + + ), + }); + } + 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 updatedRows = getUpdatedRow( + currPipelineData, + visibleCurrPipelines[dragIndex].orderId - 1, + visibleCurrPipelines[hoverIndex].orderId - 1, + ); + + updatedRows.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(updatedRows), + onCancel: onCancelPipelineSequence(rawData), + }); + } + }, + [ + currPipelineData, + isEditingActionMode, + visibleCurrPipelines, + handleAlert, + t, + updatePipelineSequence, + onCancelPipelineSequence, + ], + ); + + const expandedRowView = useCallback( + (): JSX.Element => ( + + ), + [ + handleAlert, + processorEditAction, + isActionMode, + expandedPipelineData, + setActionType, + prevPipelineData, + setExpandedPipelineData, + ], + ); + + const onExpand = useCallback( + (expanded: boolean, record: PipelineData): void => { + const keys = []; + if (expanded && record.id) { + keys.push(record?.id); + } + setExpandedRowKeys(keys); + setExpandedPipelineId(record.id); + }, + [], + ); + + const getExpandIcon = ( + expanded: boolean, + onExpand: (record: PipelineData, e: React.MouseEvent) => void, + record: PipelineData, + ): JSX.Element => ( + + ); + + const addNewPipelineHandler = useCallback((): void => { + setActionType(ActionType.AddPipeline); + }, [setActionType]); + + const footer = useCallback((): JSX.Element | undefined => { + if (isEditingActionMode) { + return ( + } + > + {t('add_new_pipeline')} + + ); + } + return undefined; + }, [isEditingActionMode, addNewPipelineHandler, t]); + + const onSaveConfigurationHandler = useCallback(async () => { + const modifiedPipelineData = currPipelineData.map((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, 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 => + ({ + index, + moveRow: movePipelineRow, + } as React.HTMLAttributes); + + const expandableConfig: ExpandableConfig = { + expandedRowKeys, + onExpand, + expandIcon: ({ expanded, onExpand, record }: ExpandRowConfig) => + getExpandIcon(expanded, onExpand, record), + }; + + return ( + <> + {contextHolder} + + + + + + + + {showSaveButton && ( + + )} + + + ); +} + +interface PipelineListsViewProps { + isActionType: string; + setActionType: (actionType?: ActionType) => void; + isActionMode: string; + setActionMode: (actionMode: ActionMode) => void; + pipelineData: Pipeline; + refetchPipelineLists: VoidFunction; + pipelineSearchValue: string; +} + +interface ExpandRowConfig { + expanded: boolean; + onExpand: (record: PipelineData, e: React.MouseEvent) => void; + record: PipelineData; +} + +export interface AlertMessage { + title: string; + descrition: string; + buttontext: string; + onOk: VoidFunction; + onCancel?: VoidFunction; +} + +export default PipelineListsView; diff --git a/frontend/src/container/PipelinePage/PipelineListsView/index.tsx b/frontend/src/container/PipelinePage/PipelineListsView/index.tsx index e7211c059c..47d69d0b8a 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/index.tsx +++ b/frontend/src/container/PipelinePage/PipelineListsView/index.tsx @@ -1,489 +1,3 @@ -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/cloneDeep'; -import React, { useCallback, 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 PreviewAction from './TableComponents/PipelineActions/components/PreviewAction'; -import TableExpandIcon from './TableComponents/TableExpandIcon'; -import { - getDataOnSearch, - getEditedDataSource, - getElementFromArray, - getRecordIndex, - getTableColumn, - getUpdatedRow, -} from './utils'; - -function PipelineListsView({ - isActionType, - setActionType, - isActionMode, - setActionMode, - pipelineData, - refetchPipelineLists, - pipelineSearchValue, -}: PipelineListsViewProps): JSX.Element { - const { t } = useTranslation(['pipeline', 'common']); - const [modal, contextHolder] = Modal.useModal(); - const { notifications } = useNotifications(); - const [prevPipelineData, setPrevPipelineData] = useState>( - cloneDeep(pipelineData?.pipelines || []), - ); - const [currPipelineData, setCurrPipelineData] = useState>( - cloneDeep(pipelineData?.pipelines || []), - ); - - const [expandedPipelineId, setExpandedPipelineId] = useState< - string | undefined - >(undefined); - const expandedPipelineData = useCallback( - () => currPipelineData?.find((p) => p.id === expandedPipelineId), - [currPipelineData, expandedPipelineId], - ); - const setExpandedPipelineData = useCallback( - (newData: PipelineData): void => { - if (expandedPipelineId) { - const pipelineIdx = currPipelineData?.findIndex( - (p) => p.id === expandedPipelineId, - ); - if (pipelineIdx >= 0) { - const newPipelineData = [...currPipelineData]; - newPipelineData[pipelineIdx] = newData; - setCurrPipelineData(newPipelineData); - } - } - }, - [expandedPipelineId, currPipelineData], - ); - - const [ - selectedProcessorData, - setSelectedProcessorData, - ] = useState(); - - const [ - selectedPipelineData, - setSelectedPipelineData, - ] = useState(); - - const [expandedRowKeys, setExpandedRowKeys] = useState>(); - const [showSaveButton, setShowSaveButton] = useState(); - const isEditingActionMode = isActionMode === ActionMode.Editing; - - const visibleCurrPipelines = useMemo((): Array => { - if (pipelineSearchValue === '') { - return currPipelineData; - } - return currPipelineData.filter((data) => - getDataOnSearch(data as never, pipelineSearchValue), - ); - }, [currPipelineData, pipelineSearchValue]); - - const handleAlert = useCallback( - ({ title, descrition, buttontext, onCancel, onOk }: AlertMessage) => { - modal.confirm({ - title: {title}, - icon: , - content: {descrition}, - okText: {buttontext}, - cancelText: {t('cancel')}, - 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 => ( - - ), - }, - { - title: '', - dataIndex: 'enabled', - key: 'enabled', - render: (value, record) => ( - - onSwitchPipelineChange(checked, record) - } - /> - ), - }, - ); - } else { - fieldColumns.push({ - title: 'Actions', - dataIndex: 'smartAction', - key: 'smartAction', - align: 'center', - render: (_value, record): JSX.Element => ( - - ), - }); - } - 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 updatedRows = getUpdatedRow( - currPipelineData, - visibleCurrPipelines[dragIndex].orderId - 1, - visibleCurrPipelines[hoverIndex].orderId - 1, - ); - - updatedRows.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(updatedRows), - onCancel: onCancelPipelineSequence(rawData), - }); - } - }, - [ - currPipelineData, - isEditingActionMode, - visibleCurrPipelines, - handleAlert, - t, - updatePipelineSequence, - onCancelPipelineSequence, - ], - ); - - const expandedRowView = useCallback( - (): JSX.Element => ( - - ), - [ - handleAlert, - processorEditAction, - isActionMode, - expandedPipelineData, - setActionType, - prevPipelineData, - setExpandedPipelineData, - ], - ); - - const onExpand = useCallback( - (expanded: boolean, record: PipelineData): void => { - const keys = []; - if (expanded && record.id) { - keys.push(record?.id); - } - setExpandedRowKeys(keys); - setExpandedPipelineId(record.id); - }, - [], - ); - - const getExpandIcon = ( - expanded: boolean, - onExpand: (record: PipelineData, e: React.MouseEvent) => void, - record: PipelineData, - ): JSX.Element => ( - - ); - - const addNewPipelineHandler = useCallback((): void => { - setActionType(ActionType.AddPipeline); - }, [setActionType]); - - const footer = useCallback((): JSX.Element | undefined => { - if (isEditingActionMode) { - return ( - } - > - {t('add_new_pipeline')} - - ); - } - return undefined; - }, [isEditingActionMode, addNewPipelineHandler, t]); - - const onSaveConfigurationHandler = useCallback(async () => { - const modifiedPipelineData = currPipelineData.map((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, 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 => - ({ - index, - moveRow: movePipelineRow, - } as React.HTMLAttributes); - - const expandableConfig: ExpandableConfig = { - expandedRowKeys, - onExpand, - expandIcon: ({ expanded, onExpand, record }: ExpandRowConfig) => - getExpandIcon(expanded, onExpand, record), - }; - - return ( - <> - {contextHolder} - - - - - -
- - {showSaveButton && ( - - )} - - - ); -} - -interface PipelineListsViewProps { - isActionType: string; - setActionType: (actionType?: ActionType) => void; - isActionMode: string; - setActionMode: (actionMode: ActionMode) => void; - pipelineData: Pipeline; - refetchPipelineLists: VoidFunction; - pipelineSearchValue: string; -} - -interface ExpandRowConfig { - expanded: boolean; - onExpand: (record: PipelineData, e: React.MouseEvent) => void; - record: PipelineData; -} - -export interface AlertMessage { - title: string; - descrition: string; - buttontext: string; - onOk: VoidFunction; - onCancel?: VoidFunction; -} +import PipelineListsView from './PipelineListsView'; export default PipelineListsView; diff --git a/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinePageLayout.test.tsx.snap b/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinePageLayout.test.tsx.snap index a6a0bd00fd..14da5913fe 100644 --- a/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinePageLayout.test.tsx.snap +++ b/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinePageLayout.test.tsx.snap @@ -82,78 +82,42 @@ exports[`PipelinePage container test should render PipelinePageLayout section 1` + - - + + - - - .c0 { diff --git a/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinesSearchSection.test.tsx.snap b/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinesSearchSection.test.tsx.snap index 17d488d290..feb2869cd5 100644 --- a/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinesSearchSection.test.tsx.snap +++ b/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinesSearchSection.test.tsx.snap @@ -3,78 +3,42 @@ exports[`PipelinePage container test should render PipelinesSearchSection section 1`] = ` + - - + + - - - diff --git a/frontend/src/container/SideNav/config.ts b/frontend/src/container/SideNav/config.ts index efb221e52f..2fbfa1e244 100644 --- a/frontend/src/container/SideNav/config.ts +++ b/frontend/src/container/SideNav/config.ts @@ -45,6 +45,6 @@ export const routeConfig: Record = { [ROUTES.USAGE_EXPLORER]: [QueryParams.resourceAttributes], [ROUTES.VERSION]: [QueryParams.resourceAttributes], [ROUTES.TRACE_EXPLORER]: [QueryParams.resourceAttributes], - [ROUTES.PIPELINES]: [QueryParams.resourceAttributes], + [ROUTES.LOGS_PIPELINES]: [QueryParams.resourceAttributes], [ROUTES.WORKSPACE_LOCKED]: [QueryParams.resourceAttributes], }; diff --git a/frontend/src/container/SideNav/menuItems.tsx b/frontend/src/container/SideNav/menuItems.tsx index a68cbaf1f4..ae0acdd8c6 100644 --- a/frontend/src/container/SideNav/menuItems.tsx +++ b/frontend/src/container/SideNav/menuItems.tsx @@ -9,6 +9,7 @@ import { LineChartOutlined, MenuOutlined, RocketOutlined, + SearchOutlined, SettingOutlined, } from '@ant-design/icons'; import ROUTES from 'constants/routes'; @@ -35,6 +36,18 @@ const menuItems: SidebarMenu[] = [ key: ROUTES.LOGS_EXPLORER, label: 'Logs', icon: , + children: [ + { + key: ROUTES.LOGS_EXPLORER, + icon: , + label: 'Logs Explorer', + }, + { + key: ROUTES.LOGS_PIPELINES, + icon: , + label: 'Logs Pipelines', + }, + ], }, { key: ROUTES.ALL_DASHBOARD, diff --git a/frontend/src/container/TopNav/Breadcrumbs/index.tsx b/frontend/src/container/TopNav/Breadcrumbs/index.tsx index d749300de8..f7b8bf5f21 100644 --- a/frontend/src/container/TopNav/Breadcrumbs/index.tsx +++ b/frontend/src/container/TopNav/Breadcrumbs/index.tsx @@ -23,7 +23,7 @@ const breadcrumbNameMap = { [ROUTES.LOGS]: 'Logs', [ROUTES.LOGS_EXPLORER]: 'Logs Explorer', [ROUTES.LIVE_LOGS]: 'Live View', - [ROUTES.PIPELINES]: 'Pipelines', + [ROUTES.LOGS_PIPELINES]: 'Logs Pipelines', [ROUTES.BILLING]: 'Billing', [ROUTES.SUPPORT]: 'Support', [ROUTES.WORKSPACE_LOCKED]: 'Workspace Locked', diff --git a/frontend/src/container/TopNav/DateTimeSelection/config.ts b/frontend/src/container/TopNav/DateTimeSelection/config.ts index a9fa99f9be..65f47544a4 100644 --- a/frontend/src/container/TopNav/DateTimeSelection/config.ts +++ b/frontend/src/container/TopNav/DateTimeSelection/config.ts @@ -83,7 +83,7 @@ export const routesToSkip = [ ROUTES.ALERTS_NEW, ROUTES.EDIT_ALERTS, ROUTES.LIST_ALL_ALERT, - ROUTES.PIPELINES, + ROUTES.LOGS_PIPELINES, ROUTES.BILLING, ROUTES.SUPPORT, ROUTES.WORKSPACE_LOCKED, diff --git a/frontend/src/utils/permission/index.ts b/frontend/src/utils/permission/index.ts index b4de0e3110..057eb2adc4 100644 --- a/frontend/src/utils/permission/index.ts +++ b/frontend/src/utils/permission/index.ts @@ -75,9 +75,8 @@ export const routePermission: Record = { LIVE_LOGS: ['ADMIN', 'EDITOR', 'VIEWER'], LIST_LICENSES: ['ADMIN'], LOGS_INDEX_FIELDS: ['ADMIN', 'EDITOR', 'VIEWER'], - LOGS_PIPELINE: ['ADMIN', 'EDITOR', 'VIEWER'], + LOGS_PIPELINES: ['ADMIN', 'EDITOR', 'VIEWER'], TRACE_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'], - PIPELINES: ['ADMIN', 'EDITOR', 'VIEWER'], GET_STARTED: ['ADMIN', 'EDITOR', 'VIEWER'], WORKSPACE_LOCKED: ['ADMIN', 'EDITOR', 'VIEWER'], BILLING: ['ADMIN', 'EDITOR', 'VIEWER'],