mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-18 05:55:57 +08:00
fix: pipeline change history: update config deployment status without having to reload (#3284)
* fix: specify rowKey for pipeline ChangeHistory table * fix: pipeline change history: refetch pipelines until latest config deployment is finished * fix: typo: verison -> version * chore: some code clean up * fix: get tests passing * fix: use refetchInterval to specify pipeline data polling strategy --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
parent
3d03ad52b1
commit
7ad489ebb4
@ -5,12 +5,13 @@ import { changeHistoryColumns } from '../../PipelineListsView/config';
|
|||||||
import { HistoryTableWrapper } from '../../styles';
|
import { HistoryTableWrapper } from '../../styles';
|
||||||
import { historyPagination } from '../config';
|
import { historyPagination } from '../config';
|
||||||
|
|
||||||
function ChangeHistory({ piplineData }: ChangeHistoryProps): JSX.Element {
|
function ChangeHistory({ pipelineData }: ChangeHistoryProps): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<HistoryTableWrapper>
|
<HistoryTableWrapper>
|
||||||
<Table
|
<Table
|
||||||
columns={changeHistoryColumns}
|
columns={changeHistoryColumns}
|
||||||
dataSource={piplineData?.history ?? []}
|
dataSource={pipelineData?.history ?? []}
|
||||||
|
rowKey="id"
|
||||||
pagination={historyPagination}
|
pagination={historyPagination}
|
||||||
/>
|
/>
|
||||||
</HistoryTableWrapper>
|
</HistoryTableWrapper>
|
||||||
@ -18,7 +19,7 @@ function ChangeHistory({ piplineData }: ChangeHistoryProps): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ChangeHistoryProps {
|
interface ChangeHistoryProps {
|
||||||
piplineData: Pipeline;
|
pipelineData: Pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ChangeHistory;
|
export default ChangeHistory;
|
||||||
|
@ -11,13 +11,13 @@ function CreatePipelineButton({
|
|||||||
setActionType,
|
setActionType,
|
||||||
isActionMode,
|
isActionMode,
|
||||||
setActionMode,
|
setActionMode,
|
||||||
piplineData,
|
pipelineData,
|
||||||
}: CreatePipelineButtonProps): JSX.Element {
|
}: CreatePipelineButtonProps): JSX.Element {
|
||||||
const { t } = useTranslation(['pipeline']);
|
const { t } = useTranslation(['pipeline']);
|
||||||
|
|
||||||
const isAddNewPipelineVisible = useMemo(
|
const isAddNewPipelineVisible = useMemo(
|
||||||
() => checkDataLength(piplineData?.pipelines),
|
() => checkDataLength(pipelineData?.pipelines),
|
||||||
[piplineData?.pipelines],
|
[pipelineData?.pipelines],
|
||||||
);
|
);
|
||||||
const isDisabled = isActionMode === ActionMode.Editing;
|
const isDisabled = isActionMode === ActionMode.Editing;
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ interface CreatePipelineButtonProps {
|
|||||||
setActionType: (actionType: string) => void;
|
setActionType: (actionType: string) => void;
|
||||||
isActionMode: string;
|
isActionMode: string;
|
||||||
setActionMode: (actionMode: string) => void;
|
setActionMode: (actionMode: string) => void;
|
||||||
piplineData: Pipeline;
|
pipelineData: Pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CreatePipelineButton;
|
export default CreatePipelineButton;
|
||||||
|
@ -7,7 +7,7 @@ import PipelinesSearchSection from './PipelinesSearchSection';
|
|||||||
|
|
||||||
function PipelinePageLayout({
|
function PipelinePageLayout({
|
||||||
refetchPipelineLists,
|
refetchPipelineLists,
|
||||||
piplineData,
|
pipelineData,
|
||||||
}: 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');
|
||||||
@ -19,7 +19,7 @@ function PipelinePageLayout({
|
|||||||
setActionType={setActionType}
|
setActionType={setActionType}
|
||||||
setActionMode={setActionMode}
|
setActionMode={setActionMode}
|
||||||
isActionMode={isActionMode}
|
isActionMode={isActionMode}
|
||||||
piplineData={piplineData}
|
pipelineData={pipelineData}
|
||||||
/>
|
/>
|
||||||
<PipelinesSearchSection setPipelineSearchValue={setPipelineSearchValue} />
|
<PipelinesSearchSection setPipelineSearchValue={setPipelineSearchValue} />
|
||||||
<PipelineListsView
|
<PipelineListsView
|
||||||
@ -27,7 +27,7 @@ function PipelinePageLayout({
|
|||||||
setActionType={setActionType}
|
setActionType={setActionType}
|
||||||
setActionMode={setActionMode}
|
setActionMode={setActionMode}
|
||||||
isActionMode={isActionMode}
|
isActionMode={isActionMode}
|
||||||
piplineData={piplineData}
|
pipelineData={pipelineData}
|
||||||
refetchPipelineLists={refetchPipelineLists}
|
refetchPipelineLists={refetchPipelineLists}
|
||||||
pipelineSearchValue={pipelineSearchValue}
|
pipelineSearchValue={pipelineSearchValue}
|
||||||
/>
|
/>
|
||||||
@ -37,7 +37,7 @@ function PipelinePageLayout({
|
|||||||
|
|
||||||
interface PipelinePageLayoutProps {
|
interface PipelinePageLayoutProps {
|
||||||
refetchPipelineLists: VoidFunction;
|
refetchPipelineLists: VoidFunction;
|
||||||
piplineData: Pipeline;
|
pipelineData: Pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PipelinePageLayout;
|
export default PipelinePageLayout;
|
||||||
|
@ -4,21 +4,21 @@ import { ModeAndConfigWrapper } from './styles';
|
|||||||
|
|
||||||
function ModeAndConfiguration({
|
function ModeAndConfiguration({
|
||||||
isActionMode,
|
isActionMode,
|
||||||
verison,
|
version,
|
||||||
}: ModeAndConfigurationType): JSX.Element {
|
}: ModeAndConfigurationType): JSX.Element {
|
||||||
const actionMode = isActionMode === ActionMode.Editing;
|
const actionMode = isActionMode === ActionMode.Editing;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModeAndConfigWrapper>
|
<ModeAndConfigWrapper>
|
||||||
Mode: <span>{actionMode ? 'Editing' : 'Viewing'}</span>
|
Mode: <span>{actionMode ? 'Editing' : 'Viewing'}</span>
|
||||||
<div>Configuration Version: {verison}</div>
|
<div>Configuration Version: {version}</div>
|
||||||
</ModeAndConfigWrapper>
|
</ModeAndConfigWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModeAndConfigurationType {
|
export interface ModeAndConfigurationType {
|
||||||
isActionMode: string;
|
isActionMode: string;
|
||||||
verison: string | number;
|
version: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ModeAndConfiguration;
|
export default ModeAndConfiguration;
|
||||||
|
@ -47,7 +47,7 @@ function PipelineListsView({
|
|||||||
setActionType,
|
setActionType,
|
||||||
isActionMode,
|
isActionMode,
|
||||||
setActionMode,
|
setActionMode,
|
||||||
piplineData,
|
pipelineData,
|
||||||
refetchPipelineLists,
|
refetchPipelineLists,
|
||||||
pipelineSearchValue,
|
pipelineSearchValue,
|
||||||
}: PipelineListsViewProps): JSX.Element {
|
}: PipelineListsViewProps): JSX.Element {
|
||||||
@ -55,10 +55,10 @@ function PipelineListsView({
|
|||||||
const [modal, contextHolder] = Modal.useModal();
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
const [prevPipelineData, setPrevPipelineData] = useState<Array<PipelineData>>(
|
const [prevPipelineData, setPrevPipelineData] = useState<Array<PipelineData>>(
|
||||||
cloneDeep(piplineData?.pipelines),
|
cloneDeep(pipelineData?.pipelines),
|
||||||
);
|
);
|
||||||
const [currPipelineData, setCurrPipelineData] = useState<Array<PipelineData>>(
|
const [currPipelineData, setCurrPipelineData] = useState<Array<PipelineData>>(
|
||||||
cloneDeep(piplineData?.pipelines),
|
cloneDeep(pipelineData?.pipelines),
|
||||||
);
|
);
|
||||||
const [
|
const [
|
||||||
expandedPipelineData,
|
expandedPipelineData,
|
||||||
@ -77,14 +77,14 @@ function PipelineListsView({
|
|||||||
const isEditingActionMode = isActionMode === ActionMode.Editing;
|
const isEditingActionMode = isActionMode === ActionMode.Editing;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pipelineSearchValue === '') setCurrPipelineData(piplineData?.pipelines);
|
if (pipelineSearchValue === '') setCurrPipelineData(pipelineData?.pipelines);
|
||||||
if (pipelineSearchValue !== '') {
|
if (pipelineSearchValue !== '') {
|
||||||
const filterData = piplineData?.pipelines.filter((data: PipelineData) =>
|
const filterData = pipelineData?.pipelines.filter((data: PipelineData) =>
|
||||||
getDataOnSearch(data as never, pipelineSearchValue),
|
getDataOnSearch(data as never, pipelineSearchValue),
|
||||||
);
|
);
|
||||||
setCurrPipelineData(filterData);
|
setCurrPipelineData(filterData);
|
||||||
}
|
}
|
||||||
}, [pipelineSearchValue, piplineData?.pipelines]);
|
}, [pipelineSearchValue, pipelineData?.pipelines]);
|
||||||
|
|
||||||
const handleAlert = useCallback(
|
const handleAlert = useCallback(
|
||||||
({ title, descrition, buttontext, onCancel, onOk }: AlertMessage) => {
|
({ title, descrition, buttontext, onCancel, onOk }: AlertMessage) => {
|
||||||
@ -414,7 +414,7 @@ function PipelineListsView({
|
|||||||
<Container>
|
<Container>
|
||||||
<ModeAndConfiguration
|
<ModeAndConfiguration
|
||||||
isActionMode={isActionMode}
|
isActionMode={isActionMode}
|
||||||
verison={piplineData?.version}
|
version={pipelineData?.version}
|
||||||
/>
|
/>
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<Table
|
<Table
|
||||||
@ -445,7 +445,7 @@ interface PipelineListsViewProps {
|
|||||||
setActionType: (actionType?: ActionType) => void;
|
setActionType: (actionType?: ActionType) => void;
|
||||||
isActionMode: string;
|
isActionMode: string;
|
||||||
setActionMode: (actionMode: ActionMode) => void;
|
setActionMode: (actionMode: ActionMode) => void;
|
||||||
piplineData: Pipeline;
|
pipelineData: Pipeline;
|
||||||
refetchPipelineLists: VoidFunction;
|
refetchPipelineLists: VoidFunction;
|
||||||
pipelineSearchValue: string;
|
pipelineSearchValue: string;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Pipeline, PipelineData } from 'types/api/pipeline/def';
|
import { Pipeline, PipelineData } from 'types/api/pipeline/def';
|
||||||
|
|
||||||
export const configurationVerison = '1.0';
|
export const configurationVersion = '1.0';
|
||||||
|
|
||||||
export const pipelineMockData: Array<PipelineData> = [
|
export const pipelineMockData: Array<PipelineData> = [
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@ describe('PipelinePage container test', () => {
|
|||||||
setActionType={jest.fn()}
|
setActionType={jest.fn()}
|
||||||
isActionMode="viewing-mode"
|
isActionMode="viewing-mode"
|
||||||
setActionMode={jest.fn()}
|
setActionMode={jest.fn()}
|
||||||
piplineData={pipelineApiResponseMockData}
|
pipelineData={pipelineApiResponseMockData}
|
||||||
/>
|
/>
|
||||||
</I18nextProvider>
|
</I18nextProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
@ -49,7 +49,7 @@ describe('PipelinePage container test', () => {
|
|||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<I18nextProvider i18n={i18n}>
|
<I18nextProvider i18n={i18n}>
|
||||||
<PipelinePageLayout
|
<PipelinePageLayout
|
||||||
piplineData={pipelinedata}
|
pipelineData={pipelinedata}
|
||||||
refetchPipelineLists={refetchPipelineLists}
|
refetchPipelineLists={refetchPipelineLists}
|
||||||
/>
|
/>
|
||||||
</I18nextProvider>
|
</I18nextProvider>
|
||||||
|
@ -8,14 +8,30 @@ import { useNotifications } from 'hooks/useNotifications';
|
|||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
|
import { SuccessResponse } from 'types/api';
|
||||||
import { Pipeline } from 'types/api/pipeline/def';
|
import { Pipeline } from 'types/api/pipeline/def';
|
||||||
|
|
||||||
|
const pipelineRefetchInterval = (
|
||||||
|
pipelineResponse: SuccessResponse<Pipeline> | undefined,
|
||||||
|
): number | false => {
|
||||||
|
// Refetch pipeline data periodically if deployment of
|
||||||
|
// its latest changes is not complete yet.
|
||||||
|
const latestVersion = pipelineResponse?.payload?.history?.[0];
|
||||||
|
const isLatestDeploymentFinished = ['DEPLOYED', 'FAILED'].includes(
|
||||||
|
latestVersion?.deployStatus || '',
|
||||||
|
);
|
||||||
|
if (latestVersion && !isLatestDeploymentFinished) {
|
||||||
|
return 3000;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
function Pipelines(): JSX.Element {
|
function Pipelines(): JSX.Element {
|
||||||
const { t } = useTranslation('common');
|
const { t } = useTranslation('common');
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
data: piplineData,
|
data: pipelineData,
|
||||||
isError,
|
isError,
|
||||||
refetch: refetchPipelineLists,
|
refetch: refetchPipelineLists,
|
||||||
} = useQuery(['version', 'latest', 'pipeline'], {
|
} = useQuery(['version', 'latest', 'pipeline'], {
|
||||||
@ -23,6 +39,7 @@ function Pipelines(): JSX.Element {
|
|||||||
getPipeline({
|
getPipeline({
|
||||||
version: 'latest',
|
version: 'latest',
|
||||||
}),
|
}),
|
||||||
|
refetchInterval: pipelineRefetchInterval,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tabItems: TabsProps['items'] = useMemo(
|
const tabItems: TabsProps['items'] = useMemo(
|
||||||
@ -33,26 +50,28 @@ function Pipelines(): JSX.Element {
|
|||||||
children: (
|
children: (
|
||||||
<PipelinePage
|
<PipelinePage
|
||||||
refetchPipelineLists={refetchPipelineLists}
|
refetchPipelineLists={refetchPipelineLists}
|
||||||
piplineData={piplineData?.payload as Pipeline}
|
pipelineData={pipelineData?.payload as Pipeline}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'change-history',
|
key: 'change-history',
|
||||||
label: `Change History`,
|
label: `Change History`,
|
||||||
children: <ChangeHistory piplineData={piplineData?.payload as Pipeline} />,
|
children: (
|
||||||
|
<ChangeHistory pipelineData={pipelineData?.payload as Pipeline} />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[piplineData?.payload, refetchPipelineLists],
|
[pipelineData?.payload, refetchPipelineLists],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (piplineData?.error && isError) {
|
if (pipelineData?.error && isError) {
|
||||||
notifications.error({
|
notifications.error({
|
||||||
message: piplineData?.error || t('something_went_wrong'),
|
message: pipelineData?.error || t('something_went_wrong'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [isError, notifications, piplineData?.error, t]);
|
}, [isError, notifications, pipelineData?.error, t]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Spinner height="75vh" tip="Loading Pipelines..." />;
|
return <Spinner height="75vh" tip="Loading Pipelines..." />;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user