Compare commits
14 Commits
feat/meter
...
feat/logs-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a959328411 | ||
|
|
8452b69d1c | ||
|
|
85beee876c | ||
|
|
19c42bf5ee | ||
|
|
a40fae85b8 | ||
|
|
3d83872196 | ||
|
|
6e41f900dc | ||
|
|
c5dbac793b | ||
|
|
8b2f8c5b1e | ||
|
|
b7dc7d519b | ||
|
|
58d63695d8 | ||
|
|
b1133bf812 | ||
|
|
065d064ac1 | ||
|
|
4ec7dc550b |
@@ -42,5 +42,7 @@
|
|||||||
"processor_span_id_placeholder": "Parse Span ID from",
|
"processor_span_id_placeholder": "Parse Span ID from",
|
||||||
"processor_trace_flags_placeholder": "Parse Trace flags from",
|
"processor_trace_flags_placeholder": "Parse Trace flags from",
|
||||||
"processor_from_placeholder": "From",
|
"processor_from_placeholder": "From",
|
||||||
"processor_to_placeholder": "To"
|
"processor_to_placeholder": "To",
|
||||||
|
"share_pipelines": "Share Pipelines",
|
||||||
|
"import_pipelines": "Import Pipelines"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ function Editor({
|
|||||||
readOnly,
|
readOnly,
|
||||||
height,
|
height,
|
||||||
options,
|
options,
|
||||||
|
beforeMount,
|
||||||
|
onValidate,
|
||||||
}: MEditorProps): JSX.Element {
|
}: MEditorProps): JSX.Element {
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
@@ -31,6 +33,8 @@ function Editor({
|
|||||||
options={editorOptions}
|
options={editorOptions}
|
||||||
height={height}
|
height={height}
|
||||||
onChange={onChangeHandler}
|
onChange={onChangeHandler}
|
||||||
|
beforeMount={beforeMount}
|
||||||
|
onValidate={onValidate}
|
||||||
data-testid="monaco-editor"
|
data-testid="monaco-editor"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -43,6 +47,8 @@ interface MEditorProps {
|
|||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
height?: string;
|
height?: string;
|
||||||
options?: EditorProps['options'];
|
options?: EditorProps['options'];
|
||||||
|
beforeMount?: EditorProps['beforeMount'];
|
||||||
|
onValidate?: EditorProps['onValidate'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Editor.defaultProps = {
|
Editor.defaultProps = {
|
||||||
@@ -51,6 +57,8 @@ Editor.defaultProps = {
|
|||||||
height: '40vh',
|
height: '40vh',
|
||||||
options: {},
|
options: {},
|
||||||
onChange: (): void => {},
|
onChange: (): void => {},
|
||||||
|
beforeMount: (): void => {},
|
||||||
|
onValidate: (): void => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Editor;
|
export default Editor;
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
import { EditFilled, PlusOutlined } from '@ant-design/icons';
|
|
||||||
import TextToolTip from 'components/TextToolTip';
|
|
||||||
import useAnalytics from 'hooks/analytics/useAnalytics';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { ActionMode, ActionType, Pipeline } from 'types/api/pipeline/def';
|
|
||||||
|
|
||||||
import { ButtonContainer, CustomButton } from '../../styles';
|
|
||||||
import { checkDataLength } from '../utils';
|
|
||||||
|
|
||||||
function CreatePipelineButton({
|
|
||||||
setActionType,
|
|
||||||
isActionMode,
|
|
||||||
setActionMode,
|
|
||||||
pipelineData,
|
|
||||||
}: CreatePipelineButtonProps): JSX.Element {
|
|
||||||
const { t } = useTranslation(['pipeline']);
|
|
||||||
const { trackEvent } = useAnalytics();
|
|
||||||
|
|
||||||
const isAddNewPipelineVisible = useMemo(
|
|
||||||
() => checkDataLength(pipelineData?.pipelines),
|
|
||||||
[pipelineData?.pipelines],
|
|
||||||
);
|
|
||||||
const isDisabled = isActionMode === ActionMode.Editing;
|
|
||||||
|
|
||||||
const onEnterEditMode = (): void => {
|
|
||||||
setActionMode(ActionMode.Editing);
|
|
||||||
|
|
||||||
trackEvent('Logs: Pipelines: Entered Edit Mode', {
|
|
||||||
source: 'signoz-ui',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const onAddNewPipeline = (): void => {
|
|
||||||
setActionMode(ActionMode.Editing);
|
|
||||||
setActionType(ActionType.AddPipeline);
|
|
||||||
|
|
||||||
trackEvent('Logs: Pipelines: Clicked Add New Pipeline', {
|
|
||||||
source: 'signoz-ui',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ButtonContainer>
|
|
||||||
<TextToolTip
|
|
||||||
text={t('learn_more')}
|
|
||||||
url="https://signoz.io/docs/logs-pipelines/introduction/"
|
|
||||||
/>
|
|
||||||
{isAddNewPipelineVisible && (
|
|
||||||
<CustomButton
|
|
||||||
icon={<EditFilled />}
|
|
||||||
onClick={onEnterEditMode}
|
|
||||||
disabled={isDisabled}
|
|
||||||
>
|
|
||||||
{t('enter_edit_mode')}
|
|
||||||
</CustomButton>
|
|
||||||
)}
|
|
||||||
{!isAddNewPipelineVisible && (
|
|
||||||
<CustomButton
|
|
||||||
icon={<PlusOutlined />}
|
|
||||||
onClick={onAddNewPipeline}
|
|
||||||
type="primary"
|
|
||||||
>
|
|
||||||
{t('new_pipeline')}
|
|
||||||
</CustomButton>
|
|
||||||
)}
|
|
||||||
</ButtonContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CreatePipelineButtonProps {
|
|
||||||
setActionType: (actionType: string) => void;
|
|
||||||
isActionMode: string;
|
|
||||||
setActionMode: (actionMode: string) => void;
|
|
||||||
pipelineData: Pipeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CreatePipelineButton;
|
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import {
|
||||||
|
EditFilled,
|
||||||
|
ImportOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
ShareAltOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import TextToolTip from 'components/TextToolTip';
|
||||||
|
import useAnalytics from 'hooks/analytics/useAnalytics';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
ActionMode,
|
||||||
|
ActionType,
|
||||||
|
Pipeline,
|
||||||
|
PipelineData,
|
||||||
|
} from 'types/api/pipeline/def';
|
||||||
|
|
||||||
|
import { ButtonContainer, CustomButton } from '../../styles';
|
||||||
|
import PipelinesExportModal from './PipelinesExportModal';
|
||||||
|
import PipelinesImportModal from './PipelinesImportModal/PipelinesImportModal';
|
||||||
|
|
||||||
|
function PipelinesActions({
|
||||||
|
setActionType,
|
||||||
|
isActionMode,
|
||||||
|
setActionMode,
|
||||||
|
pipelineData,
|
||||||
|
setCurrentPipelines,
|
||||||
|
}: PipelinesActionsProps): JSX.Element {
|
||||||
|
const { t } = useTranslation(['pipeline']);
|
||||||
|
const { trackEvent } = useAnalytics();
|
||||||
|
|
||||||
|
const [isExportModalVisible, setIsExportModalVisible] = useState(false);
|
||||||
|
const [isImportModalVisible, setIsImportModalVisible] = useState(false);
|
||||||
|
|
||||||
|
const pipelinesExist = useMemo(() => pipelineData?.pipelines?.length > 0, [
|
||||||
|
pipelineData?.pipelines,
|
||||||
|
]);
|
||||||
|
const inEditMode = isActionMode === ActionMode.Editing;
|
||||||
|
|
||||||
|
const onEnterEditMode = (): void => {
|
||||||
|
setActionMode(ActionMode.Editing);
|
||||||
|
|
||||||
|
trackEvent('Logs: Pipelines: Entered Edit Mode', {
|
||||||
|
source: 'signoz-ui',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const onAddNewPipeline = (): void => {
|
||||||
|
setActionMode(ActionMode.Editing);
|
||||||
|
setActionType(ActionType.AddPipeline);
|
||||||
|
|
||||||
|
trackEvent('Logs: Pipelines: Clicked Add New Pipeline', {
|
||||||
|
source: 'signoz-ui',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ButtonContainer>
|
||||||
|
<TextToolTip
|
||||||
|
text={t('learn_more')}
|
||||||
|
url="https://signoz.io/docs/logs-pipelines/introduction/"
|
||||||
|
/>
|
||||||
|
{pipelinesExist && !inEditMode && (
|
||||||
|
<CustomButton
|
||||||
|
onClick={(): void => setIsExportModalVisible(true)}
|
||||||
|
icon={<ShareAltOutlined />}
|
||||||
|
>
|
||||||
|
{t('share_pipelines')}
|
||||||
|
</CustomButton>
|
||||||
|
)}
|
||||||
|
{(inEditMode || !pipelinesExist) && (
|
||||||
|
<CustomButton
|
||||||
|
onClick={(): void => {
|
||||||
|
onEnterEditMode();
|
||||||
|
setIsImportModalVisible(true);
|
||||||
|
}}
|
||||||
|
icon={<ImportOutlined />}
|
||||||
|
>
|
||||||
|
{t('import_pipelines')}
|
||||||
|
</CustomButton>
|
||||||
|
)}
|
||||||
|
{pipelinesExist && (
|
||||||
|
<CustomButton
|
||||||
|
icon={<EditFilled />}
|
||||||
|
onClick={onEnterEditMode}
|
||||||
|
disabled={inEditMode}
|
||||||
|
>
|
||||||
|
{t('enter_edit_mode')}
|
||||||
|
</CustomButton>
|
||||||
|
)}
|
||||||
|
{!pipelinesExist && (
|
||||||
|
<CustomButton
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={onAddNewPipeline}
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
{t('new_pipeline')}
|
||||||
|
</CustomButton>
|
||||||
|
)}
|
||||||
|
</ButtonContainer>
|
||||||
|
<PipelinesExportModal
|
||||||
|
open={isExportModalVisible}
|
||||||
|
onClose={(): void => setIsExportModalVisible(false)}
|
||||||
|
pipelines={pipelineData.pipelines}
|
||||||
|
/>
|
||||||
|
<PipelinesImportModal
|
||||||
|
open={isImportModalVisible}
|
||||||
|
onClose={(): void => setIsImportModalVisible(false)}
|
||||||
|
setCurrentPipelines={setCurrentPipelines}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PipelinesActionsProps {
|
||||||
|
setActionType: (actionType: string) => void;
|
||||||
|
isActionMode: string;
|
||||||
|
setActionMode: (actionMode: string) => void;
|
||||||
|
pipelineData: Pipeline;
|
||||||
|
setCurrentPipelines: (
|
||||||
|
value: React.SetStateAction<Array<PipelineData>>,
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PipelinesActions;
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import { CopyFilled, DownloadOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Modal } from 'antd';
|
||||||
|
import Editor from 'components/Editor';
|
||||||
|
import { downloadObjectAsJson } from 'container/NewDashboard/DashboardDescription/utils';
|
||||||
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useCopyToClipboard } from 'react-use';
|
||||||
|
import { PipelineData } from 'types/api/pipeline/def';
|
||||||
|
|
||||||
|
export default function PipelinesExportModal({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
pipelines,
|
||||||
|
}: PipelinesExportModalProps): JSX.Element {
|
||||||
|
const { t } = useTranslation(['pipeline']);
|
||||||
|
const postablePipelines = pipelines.map((p) =>
|
||||||
|
Object.fromEntries(
|
||||||
|
Object.entries(p).filter((e) => !['createdBy', 'createdAt'].includes(e[0])),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const pipelinesPropJson = JSON.stringify(postablePipelines, null, 2);
|
||||||
|
const [pipelinesJson, setPipelinesJson] = useState(pipelinesPropJson);
|
||||||
|
useEffect(() => {
|
||||||
|
setPipelinesJson(pipelinesPropJson);
|
||||||
|
}, [open, pipelinesPropJson]);
|
||||||
|
|
||||||
|
const { notifications } = useNotifications();
|
||||||
|
const [clipboardContent, setClipboardContent] = useCopyToClipboard();
|
||||||
|
useEffect(() => {
|
||||||
|
if (clipboardContent.error) {
|
||||||
|
notifications.error({
|
||||||
|
message: t('something_went_wrong', {
|
||||||
|
ns: 'common',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clipboardContent.value) {
|
||||||
|
notifications.success({
|
||||||
|
message: t('success', {
|
||||||
|
ns: 'common',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [clipboardContent.error, clipboardContent.value, t, notifications]);
|
||||||
|
|
||||||
|
const footer = useMemo(
|
||||||
|
() => (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
marginTop: '16px',
|
||||||
|
}}
|
||||||
|
onClick={(): void => setClipboardContent(pipelinesJson)}
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<CopyFilled /> {t('copy_to_clipboard')}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
onClick={(): void => {
|
||||||
|
downloadObjectAsJson(JSON.parse(pipelinesJson), 'pipelines');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DownloadOutlined /> {t('download_json')}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[pipelinesJson, t, setClipboardContent],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onCancel={onClose}
|
||||||
|
width="80vw"
|
||||||
|
centered
|
||||||
|
title={t('share')}
|
||||||
|
destroyOnClose
|
||||||
|
footer={footer}
|
||||||
|
>
|
||||||
|
<Editor
|
||||||
|
height="70vh"
|
||||||
|
onChange={(value): void => setPipelinesJson(value)}
|
||||||
|
value={pipelinesJson}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PipelinesExportModalProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: VoidFunction;
|
||||||
|
pipelines: Array<PipelineData>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import './styles.scss';
|
||||||
|
|
||||||
|
import { ImportOutlined } from '@ant-design/icons';
|
||||||
|
import { Monaco } from '@monaco-editor/react';
|
||||||
|
import { Button, Modal } from 'antd';
|
||||||
|
import Editor from 'components/Editor';
|
||||||
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { PipelineData } from 'types/api/pipeline/def';
|
||||||
|
|
||||||
|
import { PipelinesJSONSchema } from '../schema';
|
||||||
|
|
||||||
|
export default function PipelinesImportModal({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
setCurrentPipelines,
|
||||||
|
}: PipelinesImportModalProps): JSX.Element {
|
||||||
|
const { t } = useTranslation(['pipeline']);
|
||||||
|
const [pipelinesJson, setPipelinesJson] = useState('');
|
||||||
|
const [editorErrors, setEditorErrors] = useState<string[]>([]);
|
||||||
|
const isEmpty = pipelinesJson.trim().length < 1;
|
||||||
|
const isInvalid = (editorErrors || []).length > 0;
|
||||||
|
|
||||||
|
const firstError = editorErrors?.[0];
|
||||||
|
const onImport = useCallback((): void => {
|
||||||
|
try {
|
||||||
|
const pipelines = JSON.parse(pipelinesJson);
|
||||||
|
setCurrentPipelines(pipelines);
|
||||||
|
onClose();
|
||||||
|
} catch (error) {
|
||||||
|
setEditorErrors([String(error)]);
|
||||||
|
}
|
||||||
|
}, [pipelinesJson, setCurrentPipelines, onClose]);
|
||||||
|
const footer = useMemo(
|
||||||
|
() => (
|
||||||
|
<div className="pipelines-import-modal-footer">
|
||||||
|
<div className="pipelines-import-modal-error">{firstError || ''}</div>
|
||||||
|
<Button
|
||||||
|
disabled={isEmpty || isInvalid}
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
onClick={onImport}
|
||||||
|
>
|
||||||
|
<ImportOutlined /> {t('import')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
[t, isEmpty, isInvalid, firstError, onImport],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onCancel={onClose}
|
||||||
|
width="80vw"
|
||||||
|
centered
|
||||||
|
title={t('import')}
|
||||||
|
destroyOnClose
|
||||||
|
footer={footer}
|
||||||
|
>
|
||||||
|
<Editor
|
||||||
|
height="70vh"
|
||||||
|
onChange={(value): void => setPipelinesJson(value)}
|
||||||
|
value={pipelinesJson}
|
||||||
|
language="json"
|
||||||
|
beforeMount={(monaco: Monaco): void => {
|
||||||
|
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
|
||||||
|
validate: true,
|
||||||
|
schemas: [
|
||||||
|
{
|
||||||
|
fileMatch: ['*'],
|
||||||
|
schema: PipelinesJSONSchema,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onValidate={(markers): void =>
|
||||||
|
setEditorErrors(
|
||||||
|
markers.map(
|
||||||
|
(m) => `Ln ${m.startLineNumber}, Col ${m.startColumn}: ${m.message}`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PipelinesImportModalProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: VoidFunction;
|
||||||
|
setCurrentPipelines: (
|
||||||
|
value: React.SetStateAction<Array<PipelineData>>,
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import PipelinesImportModal from './PipelinesImportModal';
|
||||||
|
|
||||||
|
export default PipelinesImportModal;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
.pipelines-import-modal-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipelines-import-modal-error {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import cloneDeep from 'lodash-es/cloneDeep';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Pipeline } from 'types/api/pipeline/def';
|
import { Pipeline, PipelineData } from 'types/api/pipeline/def';
|
||||||
|
|
||||||
import PipelineListsView from '../../PipelineListsView';
|
import PipelineListsView from '../../PipelineListsView';
|
||||||
import CreatePipelineButton from './CreatePipelineButton';
|
import PipelinesActions from './PipelinesActions';
|
||||||
|
|
||||||
function PipelinePageLayout({
|
function PipelinePageLayout({
|
||||||
refetchPipelineLists,
|
refetchPipelineLists,
|
||||||
@@ -10,21 +11,32 @@ function PipelinePageLayout({
|
|||||||
}: PipelinePageLayoutProps): JSX.Element {
|
}: PipelinePageLayoutProps): JSX.Element {
|
||||||
const [isActionType, setActionType] = useState<string>();
|
const [isActionType, setActionType] = useState<string>();
|
||||||
const [isActionMode, setActionMode] = useState<string>('viewing-mode');
|
const [isActionMode, setActionMode] = useState<string>('viewing-mode');
|
||||||
|
const [savedPipelines, setSavedPipelines] = useState<Array<PipelineData>>(
|
||||||
|
cloneDeep(pipelineData?.pipelines || []),
|
||||||
|
);
|
||||||
|
const [currentPipelines, setCurrentPipelines] = useState<Array<PipelineData>>(
|
||||||
|
cloneDeep(pipelineData?.pipelines || []),
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreatePipelineButton
|
<PipelinesActions
|
||||||
setActionType={setActionType}
|
setActionType={setActionType}
|
||||||
setActionMode={setActionMode}
|
setActionMode={setActionMode}
|
||||||
isActionMode={isActionMode}
|
isActionMode={isActionMode}
|
||||||
pipelineData={pipelineData}
|
pipelineData={pipelineData}
|
||||||
|
setCurrentPipelines={setCurrentPipelines}
|
||||||
/>
|
/>
|
||||||
<PipelineListsView
|
<PipelineListsView
|
||||||
isActionType={String(isActionType)}
|
isActionType={String(isActionType)}
|
||||||
setActionType={setActionType}
|
setActionType={setActionType}
|
||||||
setActionMode={setActionMode}
|
setActionMode={setActionMode}
|
||||||
isActionMode={isActionMode}
|
isActionMode={isActionMode}
|
||||||
pipelineData={pipelineData}
|
savedPipelinesVersion={pipelineData?.version}
|
||||||
|
savedPipelines={savedPipelines}
|
||||||
|
setSavedPipelines={setSavedPipelines}
|
||||||
|
currentPipelines={currentPipelines}
|
||||||
|
setCurrentPipelines={setCurrentPipelines}
|
||||||
refetchPipelineLists={refetchPipelineLists}
|
refetchPipelineLists={refetchPipelineLists}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
247
frontend/src/container/PipelinePage/Layouts/Pipeline/schema.ts
Normal file
247
frontend/src/container/PipelinePage/Layouts/Pipeline/schema.ts
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
// JSON schema for pipelines payload.
|
||||||
|
|
||||||
|
export const PipelinesJSONSchema = JSON.parse(`
|
||||||
|
{
|
||||||
|
"items": {
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"orderId": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"alias": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"properties": {
|
||||||
|
"op": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"items": {
|
||||||
|
"properties": {
|
||||||
|
"key": {
|
||||||
|
"properties": {
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dataType": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isColumn": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isJSON": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"key",
|
||||||
|
"dataType",
|
||||||
|
"type",
|
||||||
|
"isColumn",
|
||||||
|
"isJSON"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"value": true,
|
||||||
|
"op": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"key",
|
||||||
|
"value",
|
||||||
|
"op"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"op",
|
||||||
|
"items"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"items": {
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"on_error": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"if": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"orderId": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"parse_to": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pattern": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"regex": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"parse_from": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"trace_id": {
|
||||||
|
"properties": {
|
||||||
|
"parse_from": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"parse_from"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"span_id": {
|
||||||
|
"properties": {
|
||||||
|
"parse_from": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"parse_from"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trace_flags": {
|
||||||
|
"properties": {
|
||||||
|
"parse_from": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"parse_from"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"field": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"expr": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"routes": {
|
||||||
|
"items": {
|
||||||
|
"properties": {
|
||||||
|
"output": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"expr": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"output",
|
||||||
|
"expr"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"layout_type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"mapping": {
|
||||||
|
"additionalProperties": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"overwrite_text": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"orderId",
|
||||||
|
"enabled"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"orderId",
|
||||||
|
"name",
|
||||||
|
"alias",
|
||||||
|
"description",
|
||||||
|
"enabled",
|
||||||
|
"filter",
|
||||||
|
"config"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
`);
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Button, Divider, Form, Modal } from 'antd';
|
import { Button, Divider, Form, Modal } from 'antd';
|
||||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { ActionMode, ActionType, PipelineData } from 'types/api/pipeline/def';
|
import { ActionType, PipelineData } from 'types/api/pipeline/def';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
@@ -15,7 +15,6 @@ function AddNewPipeline({
|
|||||||
isActionType,
|
isActionType,
|
||||||
setActionType,
|
setActionType,
|
||||||
selectedPipelineData,
|
selectedPipelineData,
|
||||||
setShowSaveButton,
|
|
||||||
setCurrPipelineData,
|
setCurrPipelineData,
|
||||||
currPipelineData,
|
currPipelineData,
|
||||||
}: AddNewPipelineProps): JSX.Element {
|
}: AddNewPipelineProps): JSX.Element {
|
||||||
@@ -90,11 +89,6 @@ function AddNewPipeline({
|
|||||||
[isEdit, selectedPipelineData?.name, t],
|
[isEdit, selectedPipelineData?.name, t],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onOkModalHandler = useCallback(
|
|
||||||
() => setShowSaveButton(ActionMode.Editing),
|
|
||||||
[setShowSaveButton],
|
|
||||||
);
|
|
||||||
|
|
||||||
const isOpen = useMemo(() => isEdit || isAdd, [isAdd, isEdit]);
|
const isOpen = useMemo(() => isEdit || isAdd, [isAdd, isEdit]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -122,7 +116,7 @@ function AddNewPipeline({
|
|||||||
key="submit"
|
key="submit"
|
||||||
type="primary"
|
type="primary"
|
||||||
htmlType="submit"
|
htmlType="submit"
|
||||||
onClick={onOkModalHandler}
|
onClick={(): void => {}}
|
||||||
>
|
>
|
||||||
{isEdit ? t('update') : t('create')}
|
{isEdit ? t('update') : t('create')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -140,7 +134,6 @@ interface AddNewPipelineProps {
|
|||||||
isActionType: string;
|
isActionType: string;
|
||||||
setActionType: (actionType?: ActionType) => void;
|
setActionType: (actionType?: ActionType) => void;
|
||||||
selectedPipelineData: PipelineData | undefined;
|
selectedPipelineData: PipelineData | undefined;
|
||||||
setShowSaveButton: (actionMode: ActionMode) => void;
|
|
||||||
setCurrPipelineData: (
|
setCurrPipelineData: (
|
||||||
value: React.SetStateAction<Array<PipelineData>>,
|
value: React.SetStateAction<Array<PipelineData>>,
|
||||||
) => void;
|
) => void;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { Button, Divider, Form, Modal } from 'antd';
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
ActionMode,
|
|
||||||
ActionType,
|
ActionType,
|
||||||
PipelineData,
|
PipelineData,
|
||||||
ProcessorData,
|
ProcessorData,
|
||||||
@@ -19,7 +18,6 @@ function AddNewProcessor({
|
|||||||
isActionType,
|
isActionType,
|
||||||
setActionType,
|
setActionType,
|
||||||
selectedProcessorData,
|
selectedProcessorData,
|
||||||
setShowSaveButton,
|
|
||||||
expandedPipelineData,
|
expandedPipelineData,
|
||||||
setExpandedPipelineData,
|
setExpandedPipelineData,
|
||||||
}: AddNewProcessorProps): JSX.Element {
|
}: AddNewProcessorProps): JSX.Element {
|
||||||
@@ -134,11 +132,6 @@ function AddNewProcessor({
|
|||||||
[isEdit, selectedProcessorData?.name, t],
|
[isEdit, selectedProcessorData?.name, t],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onOkModalHandler = useCallback(
|
|
||||||
() => setShowSaveButton(ActionMode.Editing),
|
|
||||||
[setShowSaveButton],
|
|
||||||
);
|
|
||||||
|
|
||||||
const isOpen = useMemo(() => isEdit || isAdd, [isAdd, isEdit]);
|
const isOpen = useMemo(() => isEdit || isAdd, [isAdd, isEdit]);
|
||||||
|
|
||||||
const onFormValuesChanged = useCallback(
|
const onFormValuesChanged = useCallback(
|
||||||
@@ -179,7 +172,7 @@ function AddNewProcessor({
|
|||||||
key="submit"
|
key="submit"
|
||||||
type="primary"
|
type="primary"
|
||||||
htmlType="submit"
|
htmlType="submit"
|
||||||
onClick={onOkModalHandler}
|
onClick={(): void => {}}
|
||||||
>
|
>
|
||||||
{isEdit ? t('update') : t('create')}
|
{isEdit ? t('update') : t('create')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -202,7 +195,6 @@ interface AddNewProcessorProps {
|
|||||||
isActionType: string;
|
isActionType: string;
|
||||||
setActionType: (actionType?: ActionType) => void;
|
setActionType: (actionType?: ActionType) => void;
|
||||||
selectedProcessorData?: ProcessorData;
|
selectedProcessorData?: ProcessorData;
|
||||||
setShowSaveButton: (actionMode: ActionMode) => void;
|
|
||||||
expandedPipelineData?: PipelineData;
|
expandedPipelineData?: PipelineData;
|
||||||
setExpandedPipelineData: (data: PipelineData) => void;
|
setExpandedPipelineData: (data: PipelineData) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ function PipelineExpandView({
|
|||||||
setActionType,
|
setActionType,
|
||||||
processorEditAction,
|
processorEditAction,
|
||||||
isActionMode,
|
isActionMode,
|
||||||
setShowSaveButton,
|
|
||||||
expandedPipelineData,
|
expandedPipelineData,
|
||||||
setExpandedPipelineData,
|
setExpandedPipelineData,
|
||||||
prevPipelineData,
|
prevPipelineData,
|
||||||
@@ -44,7 +43,6 @@ function PipelineExpandView({
|
|||||||
|
|
||||||
const deleteProcessorHandler = useCallback(
|
const deleteProcessorHandler = useCallback(
|
||||||
(record: ProcessorData) => (): void => {
|
(record: ProcessorData) => (): void => {
|
||||||
setShowSaveButton(ActionMode.Editing);
|
|
||||||
if (expandedPipelineData && expandedPipelineData?.config) {
|
if (expandedPipelineData && expandedPipelineData?.config) {
|
||||||
const filteredData = expandedPipelineData?.config.filter(
|
const filteredData = expandedPipelineData?.config.filter(
|
||||||
(item: ProcessorData) => item.id !== record.id,
|
(item: ProcessorData) => item.id !== record.id,
|
||||||
@@ -62,7 +60,7 @@ function PipelineExpandView({
|
|||||||
setExpandedPipelineData(pipelineData);
|
setExpandedPipelineData(pipelineData);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[expandedPipelineData, setShowSaveButton, setExpandedPipelineData],
|
[expandedPipelineData, setExpandedPipelineData],
|
||||||
);
|
);
|
||||||
|
|
||||||
const processorDeleteAction = useCallback(
|
const processorDeleteAction = useCallback(
|
||||||
@@ -80,7 +78,6 @@ function PipelineExpandView({
|
|||||||
const onSwitchProcessorChange = useCallback(
|
const onSwitchProcessorChange = useCallback(
|
||||||
(checked: boolean, record: ProcessorData): void => {
|
(checked: boolean, record: ProcessorData): void => {
|
||||||
if (expandedPipelineData && expandedPipelineData?.config) {
|
if (expandedPipelineData && expandedPipelineData?.config) {
|
||||||
setShowSaveButton(ActionMode.Editing);
|
|
||||||
const findRecordIndex = getRecordIndex(
|
const findRecordIndex = getRecordIndex(
|
||||||
expandedPipelineData?.config,
|
expandedPipelineData?.config,
|
||||||
record,
|
record,
|
||||||
@@ -102,7 +99,7 @@ function PipelineExpandView({
|
|||||||
setExpandedPipelineData(modifiedProcessorData);
|
setExpandedPipelineData(modifiedProcessorData);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[expandedPipelineData, setExpandedPipelineData, setShowSaveButton],
|
[expandedPipelineData, setExpandedPipelineData],
|
||||||
);
|
);
|
||||||
|
|
||||||
const columns = useMemo(() => {
|
const columns = useMemo(() => {
|
||||||
@@ -145,14 +142,13 @@ function PipelineExpandView({
|
|||||||
|
|
||||||
const reorderProcessorRow = useCallback(
|
const reorderProcessorRow = useCallback(
|
||||||
(updatedRow: ProcessorData[]) => (): void => {
|
(updatedRow: ProcessorData[]) => (): void => {
|
||||||
setShowSaveButton(ActionMode.Editing);
|
|
||||||
if (expandedPipelineData) {
|
if (expandedPipelineData) {
|
||||||
const modifiedProcessorData = { ...expandedPipelineData };
|
const modifiedProcessorData = { ...expandedPipelineData };
|
||||||
modifiedProcessorData.config = updatedRow;
|
modifiedProcessorData.config = updatedRow;
|
||||||
setExpandedPipelineData(modifiedProcessorData);
|
setExpandedPipelineData(modifiedProcessorData);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[expandedPipelineData, setShowSaveButton, setExpandedPipelineData],
|
[expandedPipelineData, setExpandedPipelineData],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onCancelReorderProcessorRow = useCallback(
|
const onCancelReorderProcessorRow = useCallback(
|
||||||
@@ -267,7 +263,6 @@ interface PipelineExpandViewProps {
|
|||||||
setActionType: (actionType?: ActionType) => void;
|
setActionType: (actionType?: ActionType) => void;
|
||||||
processorEditAction: (record: ProcessorData) => () => void;
|
processorEditAction: (record: ProcessorData) => () => void;
|
||||||
isActionMode: string;
|
isActionMode: string;
|
||||||
setShowSaveButton: (actionMode: ActionMode) => void;
|
|
||||||
expandedPipelineData?: PipelineData;
|
expandedPipelineData?: PipelineData;
|
||||||
setExpandedPipelineData: (data: PipelineData) => void;
|
setExpandedPipelineData: (data: PipelineData) => void;
|
||||||
prevPipelineData: Array<PipelineData>;
|
prevPipelineData: Array<PipelineData>;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import savePipeline from 'api/pipeline/post';
|
|||||||
import useAnalytics from 'hooks/analytics/useAnalytics';
|
import useAnalytics from 'hooks/analytics/useAnalytics';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import cloneDeep from 'lodash-es/cloneDeep';
|
import cloneDeep from 'lodash-es/cloneDeep';
|
||||||
|
import isEqual from 'lodash-es/isEqual';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
@@ -14,7 +15,6 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import {
|
import {
|
||||||
ActionMode,
|
ActionMode,
|
||||||
ActionType,
|
ActionType,
|
||||||
Pipeline,
|
|
||||||
PipelineData,
|
PipelineData,
|
||||||
ProcessorData,
|
ProcessorData,
|
||||||
} from 'types/api/pipeline/def';
|
} from 'types/api/pipeline/def';
|
||||||
@@ -85,7 +85,11 @@ function PipelineListsView({
|
|||||||
setActionType,
|
setActionType,
|
||||||
isActionMode,
|
isActionMode,
|
||||||
setActionMode,
|
setActionMode,
|
||||||
pipelineData,
|
savedPipelinesVersion,
|
||||||
|
savedPipelines,
|
||||||
|
setSavedPipelines,
|
||||||
|
currentPipelines,
|
||||||
|
setCurrentPipelines,
|
||||||
refetchPipelineLists,
|
refetchPipelineLists,
|
||||||
}: PipelineListsViewProps): JSX.Element {
|
}: PipelineListsViewProps): JSX.Element {
|
||||||
const { t } = useTranslation(['pipeline', 'common']);
|
const { t } = useTranslation(['pipeline', 'common']);
|
||||||
@@ -93,34 +97,28 @@ function PipelineListsView({
|
|||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
const [pipelineSearchValue, setPipelineSearchValue] = useState<string>('');
|
const [pipelineSearchValue, setPipelineSearchValue] = useState<string>('');
|
||||||
const { trackEvent } = useAnalytics();
|
const { trackEvent } = useAnalytics();
|
||||||
const [prevPipelineData, setPrevPipelineData] = useState<Array<PipelineData>>(
|
|
||||||
cloneDeep(pipelineData?.pipelines || []),
|
|
||||||
);
|
|
||||||
const [currPipelineData, setCurrPipelineData] = useState<Array<PipelineData>>(
|
|
||||||
cloneDeep(pipelineData?.pipelines || []),
|
|
||||||
);
|
|
||||||
|
|
||||||
const [expandedPipelineId, setExpandedPipelineId] = useState<
|
const [expandedPipelineId, setExpandedPipelineId] = useState<
|
||||||
string | undefined
|
string | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
const expandedPipelineData = useCallback(
|
const expandedPipelineData = useCallback(
|
||||||
() => currPipelineData?.find((p) => p.id === expandedPipelineId),
|
() => currentPipelines?.find((p) => p.id === expandedPipelineId),
|
||||||
[currPipelineData, expandedPipelineId],
|
[currentPipelines, expandedPipelineId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const setExpandedPipelineData = useCallback(
|
const setExpandedPipelineData = useCallback(
|
||||||
(newData: PipelineData): void => {
|
(newData: PipelineData): void => {
|
||||||
if (expandedPipelineId) {
|
if (expandedPipelineId) {
|
||||||
const pipelineIdx = currPipelineData?.findIndex(
|
const pipelineIdx = currentPipelines?.findIndex(
|
||||||
(p) => p.id === expandedPipelineId,
|
(p) => p.id === expandedPipelineId,
|
||||||
);
|
);
|
||||||
if (pipelineIdx >= 0) {
|
if (pipelineIdx >= 0) {
|
||||||
const newPipelineData = [...currPipelineData];
|
const newPipelineData = cloneDeep(currentPipelines);
|
||||||
newPipelineData[pipelineIdx] = newData;
|
newPipelineData[pipelineIdx] = newData;
|
||||||
setCurrPipelineData(newPipelineData);
|
setCurrentPipelines(newPipelineData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[expandedPipelineId, currPipelineData],
|
[expandedPipelineId, currentPipelines, setCurrentPipelines],
|
||||||
);
|
);
|
||||||
|
|
||||||
const [
|
const [
|
||||||
@@ -134,17 +132,16 @@ function PipelineListsView({
|
|||||||
] = useState<PipelineData>();
|
] = useState<PipelineData>();
|
||||||
|
|
||||||
const [expandedRowKeys, setExpandedRowKeys] = useState<Array<string>>();
|
const [expandedRowKeys, setExpandedRowKeys] = useState<Array<string>>();
|
||||||
const [showSaveButton, setShowSaveButton] = useState<string>();
|
|
||||||
const isEditingActionMode = isActionMode === ActionMode.Editing;
|
const isEditingActionMode = isActionMode === ActionMode.Editing;
|
||||||
|
|
||||||
const visibleCurrPipelines = useMemo((): Array<PipelineData> => {
|
const visibleCurrPipelines = useMemo((): Array<PipelineData> => {
|
||||||
if (pipelineSearchValue === '') {
|
if (pipelineSearchValue === '') {
|
||||||
return currPipelineData;
|
return currentPipelines;
|
||||||
}
|
}
|
||||||
return currPipelineData.filter((data) =>
|
return currentPipelines.filter((data) =>
|
||||||
getDataOnSearch(data as never, pipelineSearchValue),
|
getDataOnSearch(data as never, pipelineSearchValue),
|
||||||
);
|
);
|
||||||
}, [currPipelineData, pipelineSearchValue]);
|
}, [currentPipelines, pipelineSearchValue]);
|
||||||
|
|
||||||
const handleAlert = useCallback(
|
const handleAlert = useCallback(
|
||||||
({ title, descrition, buttontext, onCancel, onOk }: AlertMessage) => {
|
({ title, descrition, buttontext, onCancel, onOk }: AlertMessage) => {
|
||||||
@@ -171,15 +168,18 @@ function PipelineListsView({
|
|||||||
|
|
||||||
const pipelineDeleteHandler = useCallback(
|
const pipelineDeleteHandler = useCallback(
|
||||||
(record: PipelineData) => (): void => {
|
(record: PipelineData) => (): void => {
|
||||||
setShowSaveButton(ActionMode.Editing);
|
const filteredData = getElementFromArray(
|
||||||
const filteredData = getElementFromArray(currPipelineData, record, 'id');
|
cloneDeep(currentPipelines),
|
||||||
|
record,
|
||||||
|
'id',
|
||||||
|
);
|
||||||
filteredData.forEach((item, index) => {
|
filteredData.forEach((item, index) => {
|
||||||
const obj = item;
|
const obj = item;
|
||||||
obj.orderId = index + 1;
|
obj.orderId = index + 1;
|
||||||
});
|
});
|
||||||
setCurrPipelineData(filteredData);
|
setCurrentPipelines(filteredData);
|
||||||
},
|
},
|
||||||
[currPipelineData],
|
[currentPipelines, setCurrentPipelines],
|
||||||
);
|
);
|
||||||
|
|
||||||
const pipelineDeleteAction = useCallback(
|
const pipelineDeleteAction = useCallback(
|
||||||
@@ -204,21 +204,20 @@ function PipelineListsView({
|
|||||||
|
|
||||||
const onSwitchPipelineChange = useCallback(
|
const onSwitchPipelineChange = useCallback(
|
||||||
(checked: boolean, record: PipelineData): void => {
|
(checked: boolean, record: PipelineData): void => {
|
||||||
setShowSaveButton(ActionMode.Editing);
|
const findRecordIndex = getRecordIndex(currentPipelines, record, 'id');
|
||||||
const findRecordIndex = getRecordIndex(currPipelineData, record, 'id');
|
|
||||||
const updateSwitch = {
|
const updateSwitch = {
|
||||||
...currPipelineData[findRecordIndex],
|
...currentPipelines[findRecordIndex],
|
||||||
enabled: checked,
|
enabled: checked,
|
||||||
};
|
};
|
||||||
const editedPipelineData = getEditedDataSource(
|
const editedPipelineData = getEditedDataSource(
|
||||||
currPipelineData,
|
cloneDeep(currentPipelines),
|
||||||
record,
|
record,
|
||||||
'id',
|
'id',
|
||||||
updateSwitch,
|
updateSwitch,
|
||||||
);
|
);
|
||||||
setCurrPipelineData(editedPipelineData);
|
setCurrentPipelines(editedPipelineData);
|
||||||
},
|
},
|
||||||
[currPipelineData],
|
[currentPipelines, setCurrentPipelines],
|
||||||
);
|
);
|
||||||
|
|
||||||
const columns = useMemo(() => {
|
const columns = useMemo(() => {
|
||||||
@@ -271,28 +270,13 @@ function PipelineListsView({
|
|||||||
onSwitchPipelineChange,
|
onSwitchPipelineChange,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const updatePipelineSequence = useCallback(
|
|
||||||
(updatedRow: PipelineData[]) => (): void => {
|
|
||||||
setShowSaveButton(ActionMode.Editing);
|
|
||||||
setCurrPipelineData(updatedRow);
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onCancelPipelineSequence = useCallback(
|
|
||||||
(rawData: PipelineData[]) => (): void => {
|
|
||||||
setCurrPipelineData(rawData);
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const movePipelineRow = useCallback(
|
const movePipelineRow = useCallback(
|
||||||
(dragIndex: number, hoverIndex: number) => {
|
(dragIndex: number, hoverIndex: number) => {
|
||||||
if (currPipelineData && isEditingActionMode) {
|
if (currentPipelines && isEditingActionMode) {
|
||||||
const rawData = currPipelineData;
|
const rawData = currentPipelines;
|
||||||
|
|
||||||
const updatedRows = getUpdatedRow(
|
const updatedRows = getUpdatedRow(
|
||||||
currPipelineData,
|
cloneDeep(currentPipelines),
|
||||||
visibleCurrPipelines[dragIndex].orderId - 1,
|
visibleCurrPipelines[dragIndex].orderId - 1,
|
||||||
visibleCurrPipelines[hoverIndex].orderId - 1,
|
visibleCurrPipelines[hoverIndex].orderId - 1,
|
||||||
);
|
);
|
||||||
@@ -305,19 +289,18 @@ function PipelineListsView({
|
|||||||
title: t('reorder_pipeline'),
|
title: t('reorder_pipeline'),
|
||||||
descrition: t('reorder_pipeline_description'),
|
descrition: t('reorder_pipeline_description'),
|
||||||
buttontext: t('reorder'),
|
buttontext: t('reorder'),
|
||||||
onOk: updatePipelineSequence(updatedRows),
|
onOk: (): void => setCurrentPipelines(updatedRows),
|
||||||
onCancel: onCancelPipelineSequence(rawData),
|
onCancel: (): void => setCurrentPipelines(rawData),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
currPipelineData,
|
currentPipelines,
|
||||||
isEditingActionMode,
|
isEditingActionMode,
|
||||||
visibleCurrPipelines,
|
visibleCurrPipelines,
|
||||||
handleAlert,
|
handleAlert,
|
||||||
t,
|
t,
|
||||||
updatePipelineSequence,
|
setCurrentPipelines,
|
||||||
onCancelPipelineSequence,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -328,10 +311,9 @@ function PipelineListsView({
|
|||||||
isActionMode={isActionMode}
|
isActionMode={isActionMode}
|
||||||
setActionType={setActionType}
|
setActionType={setActionType}
|
||||||
processorEditAction={processorEditAction}
|
processorEditAction={processorEditAction}
|
||||||
setShowSaveButton={setShowSaveButton}
|
|
||||||
expandedPipelineData={expandedPipelineData()}
|
expandedPipelineData={expandedPipelineData()}
|
||||||
setExpandedPipelineData={setExpandedPipelineData}
|
setExpandedPipelineData={setExpandedPipelineData}
|
||||||
prevPipelineData={prevPipelineData}
|
prevPipelineData={savedPipelines}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
@@ -340,7 +322,7 @@ function PipelineListsView({
|
|||||||
isActionMode,
|
isActionMode,
|
||||||
expandedPipelineData,
|
expandedPipelineData,
|
||||||
setActionType,
|
setActionType,
|
||||||
prevPipelineData,
|
savedPipelines,
|
||||||
setExpandedPipelineData,
|
setExpandedPipelineData,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -390,7 +372,7 @@ function PipelineListsView({
|
|||||||
}, [isEditingActionMode, addNewPipelineHandler, t]);
|
}, [isEditingActionMode, addNewPipelineHandler, t]);
|
||||||
|
|
||||||
const onSaveConfigurationHandler = useCallback(async () => {
|
const onSaveConfigurationHandler = useCallback(async () => {
|
||||||
const modifiedPipelineData = currPipelineData.map((item: PipelineData) => {
|
const modifiedPipelineData = currentPipelines.map((item: PipelineData) => {
|
||||||
const pipelineData = { ...item };
|
const pipelineData = { ...item };
|
||||||
delete pipelineData?.id;
|
delete pipelineData?.id;
|
||||||
return pipelineData;
|
return pipelineData;
|
||||||
@@ -401,11 +383,10 @@ function PipelineListsView({
|
|||||||
if (response.statusCode === 200) {
|
if (response.statusCode === 200) {
|
||||||
refetchPipelineLists();
|
refetchPipelineLists();
|
||||||
setActionMode(ActionMode.Viewing);
|
setActionMode(ActionMode.Viewing);
|
||||||
setShowSaveButton(undefined);
|
|
||||||
|
|
||||||
const pipelinesInDB = response.payload?.pipelines || [];
|
const pipelinesInDB = response.payload?.pipelines || [];
|
||||||
setCurrPipelineData(pipelinesInDB);
|
setCurrentPipelines(cloneDeep(pipelinesInDB));
|
||||||
setPrevPipelineData(pipelinesInDB);
|
setSavedPipelines(cloneDeep(pipelinesInDB));
|
||||||
|
|
||||||
trackEvent('Logs: Pipelines: Saved Pipelines', {
|
trackEvent('Logs: Pipelines: Saved Pipelines', {
|
||||||
count: pipelinesInDB.length,
|
count: pipelinesInDB.length,
|
||||||
@@ -419,21 +400,19 @@ function PipelineListsView({
|
|||||||
return pipelineData;
|
return pipelineData;
|
||||||
});
|
});
|
||||||
setActionMode(ActionMode.Editing);
|
setActionMode(ActionMode.Editing);
|
||||||
setShowSaveButton(ActionMode.Editing);
|
|
||||||
notifications.error({
|
notifications.error({
|
||||||
message: 'Error',
|
message: 'Error',
|
||||||
description: response.error || t('something_went_wrong'),
|
description: response.error || t('something_went_wrong'),
|
||||||
});
|
});
|
||||||
setCurrPipelineData(modifiedPipelineData);
|
setCurrentPipelines(cloneDeep(modifiedPipelineData));
|
||||||
setPrevPipelineData(modifiedPipelineData);
|
setSavedPipelines(cloneDeep(modifiedPipelineData));
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [currPipelineData, notifications, refetchPipelineLists, setActionMode, t]);
|
}, [currentPipelines, notifications, refetchPipelineLists, setActionMode, t]);
|
||||||
|
|
||||||
const onCancelConfigurationHandler = useCallback((): void => {
|
const onCancelConfigurationHandler = useCallback((): void => {
|
||||||
setActionMode(ActionMode.Viewing);
|
setActionMode(ActionMode.Viewing);
|
||||||
setShowSaveButton(undefined);
|
savedPipelines.forEach((item, index) => {
|
||||||
prevPipelineData.forEach((item, index) => {
|
|
||||||
const obj = item;
|
const obj = item;
|
||||||
obj.orderId = index + 1;
|
obj.orderId = index + 1;
|
||||||
if (obj.config) {
|
if (obj.config) {
|
||||||
@@ -446,9 +425,9 @@ function PipelineListsView({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setCurrPipelineData(prevPipelineData);
|
setCurrentPipelines(cloneDeep(savedPipelines));
|
||||||
setExpandedRowKeys([]);
|
setExpandedRowKeys([]);
|
||||||
}, [prevPipelineData, setActionMode]);
|
}, [savedPipelines, setCurrentPipelines, setActionMode]);
|
||||||
|
|
||||||
const onRowHandler = (
|
const onRowHandler = (
|
||||||
_data: PipelineData,
|
_data: PipelineData,
|
||||||
@@ -473,25 +452,23 @@ function PipelineListsView({
|
|||||||
isActionType={isActionType}
|
isActionType={isActionType}
|
||||||
setActionType={setActionType}
|
setActionType={setActionType}
|
||||||
selectedPipelineData={selectedPipelineData}
|
selectedPipelineData={selectedPipelineData}
|
||||||
setShowSaveButton={setShowSaveButton}
|
setCurrPipelineData={setCurrentPipelines}
|
||||||
setCurrPipelineData={setCurrPipelineData}
|
currPipelineData={currentPipelines}
|
||||||
currPipelineData={currPipelineData}
|
|
||||||
/>
|
/>
|
||||||
<AddNewProcessor
|
<AddNewProcessor
|
||||||
isActionType={isActionType}
|
isActionType={isActionType}
|
||||||
setActionType={setActionType}
|
setActionType={setActionType}
|
||||||
selectedProcessorData={selectedProcessorData}
|
selectedProcessorData={selectedProcessorData}
|
||||||
setShowSaveButton={setShowSaveButton}
|
|
||||||
expandedPipelineData={expandedPipelineData()}
|
expandedPipelineData={expandedPipelineData()}
|
||||||
setExpandedPipelineData={setExpandedPipelineData}
|
setExpandedPipelineData={setExpandedPipelineData}
|
||||||
/>
|
/>
|
||||||
{prevPipelineData?.length > 0 || currPipelineData?.length > 0 ? (
|
{savedPipelines?.length > 0 || currentPipelines?.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<PipelinesSearchSection setPipelineSearchValue={setPipelineSearchValue} />
|
<PipelinesSearchSection setPipelineSearchValue={setPipelineSearchValue} />
|
||||||
<Container>
|
<Container>
|
||||||
<ModeAndConfiguration
|
<ModeAndConfiguration
|
||||||
isActionMode={isActionMode}
|
isActionMode={isActionMode}
|
||||||
version={pipelineData?.version}
|
version={savedPipelinesVersion}
|
||||||
/>
|
/>
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<Table
|
<Table
|
||||||
@@ -508,7 +485,7 @@ function PipelineListsView({
|
|||||||
</DndProvider>
|
</DndProvider>
|
||||||
{isEditingActionMode && (
|
{isEditingActionMode && (
|
||||||
<SaveConfigButton
|
<SaveConfigButton
|
||||||
showSaveButton={Boolean(showSaveButton)}
|
showSaveButton={!isEqual(currentPipelines, savedPipelines)}
|
||||||
onSaveConfigurationHandler={onSaveConfigurationHandler}
|
onSaveConfigurationHandler={onSaveConfigurationHandler}
|
||||||
onCancelConfigurationHandler={onCancelConfigurationHandler}
|
onCancelConfigurationHandler={onCancelConfigurationHandler}
|
||||||
/>
|
/>
|
||||||
@@ -529,7 +506,13 @@ interface PipelineListsViewProps {
|
|||||||
setActionType: (actionType?: ActionType) => void;
|
setActionType: (actionType?: ActionType) => void;
|
||||||
isActionMode: string;
|
isActionMode: string;
|
||||||
setActionMode: (actionMode: ActionMode) => void;
|
setActionMode: (actionMode: ActionMode) => void;
|
||||||
pipelineData: Pipeline;
|
savedPipelinesVersion: number | string;
|
||||||
|
savedPipelines: Array<PipelineData>;
|
||||||
|
setSavedPipelines: (value: React.SetStateAction<Array<PipelineData>>) => void;
|
||||||
|
currentPipelines: Array<PipelineData>;
|
||||||
|
setCurrentPipelines: (
|
||||||
|
value: React.SetStateAction<Array<PipelineData>>,
|
||||||
|
) => void;
|
||||||
refetchPipelineLists: VoidFunction;
|
refetchPipelineLists: VoidFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const ButtonContainer = styled.div`
|
|||||||
|
|
||||||
export const CustomButton = styled(Button)`
|
export const CustomButton = styled(Button)`
|
||||||
&&& {
|
&&& {
|
||||||
margin-left: 1rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|||||||
import i18n from 'ReactI18';
|
import i18n from 'ReactI18';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
|
|
||||||
import CreatePipelineButton from '../Layouts/Pipeline/CreatePipelineButton';
|
import PipelinesActions from '../Layouts/Pipeline/PipelinesActions';
|
||||||
import { pipelineApiResponseMockData } from '../mocks/pipeline';
|
import { pipelineApiResponseMockData } from '../mocks/pipeline';
|
||||||
|
|
||||||
describe('PipelinePage container test', () => {
|
describe('PipelinePage container test', () => {
|
||||||
@@ -14,7 +14,7 @@ describe('PipelinePage container test', () => {
|
|||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<I18nextProvider i18n={i18n}>
|
<I18nextProvider i18n={i18n}>
|
||||||
<CreatePipelineButton
|
<PipelinesActions
|
||||||
setActionType={jest.fn()}
|
setActionType={jest.fn()}
|
||||||
isActionMode="viewing-mode"
|
isActionMode="viewing-mode"
|
||||||
setActionMode={jest.fn()}
|
setActionMode={jest.fn()}
|
||||||
|
|||||||
Reference in New Issue
Block a user