feat: delete pipeline stage (#1412)
* feat: delete pipeline stage Closes #1396 * refactor: code review - Use string literal instead of enum * docs: disable CircularProgressBar Chromatic snapshots
This commit is contained in:
@ -1016,6 +1016,7 @@ export type Mutation = {
|
||||
deleteManyView: AffectedRows;
|
||||
deleteManyViewFilter: AffectedRows;
|
||||
deleteManyViewSort: AffectedRows;
|
||||
deleteOnePipelineStage: PipelineStage;
|
||||
deleteOneView: View;
|
||||
deleteUserAccount: User;
|
||||
deleteWorkspaceMember: WorkspaceMember;
|
||||
@ -1186,6 +1187,11 @@ export type MutationDeleteManyViewSortArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteOnePipelineStageArgs = {
|
||||
where: PipelineStageWhereUniqueInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteOneViewArgs = {
|
||||
where: ViewWhereUniqueInput;
|
||||
};
|
||||
@ -3325,6 +3331,13 @@ export type DeleteManyPipelineProgressMutationVariables = Exact<{
|
||||
|
||||
export type DeleteManyPipelineProgressMutation = { __typename?: 'Mutation', deleteManyPipelineProgress: { __typename?: 'AffectedRows', count: number } };
|
||||
|
||||
export type DeletePipelineStageMutationVariables = Exact<{
|
||||
where: PipelineStageWhereUniqueInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type DeletePipelineStageMutation = { __typename?: 'Mutation', pipelineStage: { __typename?: 'PipelineStage', id: string, name: string, color: string } };
|
||||
|
||||
export type UpdateOnePipelineProgressMutationVariables = Exact<{
|
||||
data: PipelineProgressUpdateInput;
|
||||
where: PipelineProgressWhereUniqueInput;
|
||||
@ -5554,6 +5567,41 @@ export function useDeleteManyPipelineProgressMutation(baseOptions?: Apollo.Mutat
|
||||
export type DeleteManyPipelineProgressMutationHookResult = ReturnType<typeof useDeleteManyPipelineProgressMutation>;
|
||||
export type DeleteManyPipelineProgressMutationResult = Apollo.MutationResult<DeleteManyPipelineProgressMutation>;
|
||||
export type DeleteManyPipelineProgressMutationOptions = Apollo.BaseMutationOptions<DeleteManyPipelineProgressMutation, DeleteManyPipelineProgressMutationVariables>;
|
||||
export const DeletePipelineStageDocument = gql`
|
||||
mutation DeletePipelineStage($where: PipelineStageWhereUniqueInput!) {
|
||||
pipelineStage: deleteOnePipelineStage(where: $where) {
|
||||
id
|
||||
name
|
||||
color
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type DeletePipelineStageMutationFn = Apollo.MutationFunction<DeletePipelineStageMutation, DeletePipelineStageMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useDeletePipelineStageMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useDeletePipelineStageMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useDeletePipelineStageMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [deletePipelineStageMutation, { data, loading, error }] = useDeletePipelineStageMutation({
|
||||
* variables: {
|
||||
* where: // value for 'where'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDeletePipelineStageMutation(baseOptions?: Apollo.MutationHookOptions<DeletePipelineStageMutation, DeletePipelineStageMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<DeletePipelineStageMutation, DeletePipelineStageMutationVariables>(DeletePipelineStageDocument, options);
|
||||
}
|
||||
export type DeletePipelineStageMutationHookResult = ReturnType<typeof useDeletePipelineStageMutation>;
|
||||
export type DeletePipelineStageMutationResult = Apollo.MutationResult<DeletePipelineStageMutation>;
|
||||
export type DeletePipelineStageMutationOptions = Apollo.BaseMutationOptions<DeletePipelineStageMutation, DeletePipelineStageMutationVariables>;
|
||||
export const UpdateOnePipelineProgressDocument = gql`
|
||||
mutation UpdateOnePipelineProgress($data: PipelineProgressUpdateInput!, $where: PipelineProgressWhereUniqueInput!) {
|
||||
updateOnePipelineProgress(where: $where, data: $data) {
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const DELETE_PIPELINE_STAGE = gql`
|
||||
mutation DeletePipelineStage($where: PipelineStageWhereUniqueInput!) {
|
||||
pipelineStage: deleteOnePipelineStage(where: $where) {
|
||||
id
|
||||
name
|
||||
color
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -2,7 +2,10 @@ import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import type { BoardColumnDefinition } from '@/ui/board/types/BoardColumnDefinition';
|
||||
import { useCreatePipelineStageMutation } from '~/generated/graphql';
|
||||
import {
|
||||
useCreatePipelineStageMutation,
|
||||
useDeletePipelineStageMutation,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
import { GET_PIPELINES } from '../graphql/queries/getPipelines';
|
||||
import { currentPipelineState } from '../states/currentPipelineState';
|
||||
@ -11,6 +14,7 @@ export const usePipelineStages = () => {
|
||||
const currentPipeline = useRecoilValue(currentPipelineState);
|
||||
|
||||
const [createPipelineStageMutation] = useCreatePipelineStageMutation();
|
||||
const [deletePipelineStageMutation] = useDeletePipelineStageMutation();
|
||||
|
||||
const handlePipelineStageAdd = async (boardColumn: BoardColumnDefinition) => {
|
||||
if (!currentPipeline?.id) return;
|
||||
@ -30,5 +34,14 @@ export const usePipelineStages = () => {
|
||||
});
|
||||
};
|
||||
|
||||
return { handlePipelineStageAdd };
|
||||
const handlePipelineStageDelete = async (boardColumnId: string) => {
|
||||
if (!currentPipeline?.id) return;
|
||||
|
||||
return deletePipelineStageMutation({
|
||||
variables: { where: { id: boardColumnId } },
|
||||
refetchQueries: [getOperationName(GET_PIPELINES) ?? ''],
|
||||
});
|
||||
};
|
||||
|
||||
return { handlePipelineStageAdd, handlePipelineStageDelete };
|
||||
};
|
||||
|
||||
@ -54,6 +54,7 @@ const StyledNumChildren = styled.div`
|
||||
export type BoardColumnProps = {
|
||||
color: string;
|
||||
title: string;
|
||||
onDelete?: (id: string) => void;
|
||||
onTitleEdit: (title: string, color: string) => void;
|
||||
totalAmount?: number;
|
||||
children: React.ReactNode;
|
||||
@ -65,6 +66,7 @@ export type BoardColumnProps = {
|
||||
export function BoardColumn({
|
||||
color,
|
||||
title,
|
||||
onDelete,
|
||||
onTitleEdit,
|
||||
totalAmount,
|
||||
children,
|
||||
@ -102,6 +104,7 @@ export function BoardColumn({
|
||||
{isBoardColumnMenuOpen && (
|
||||
<BoardColumnMenu
|
||||
onClose={handleClose}
|
||||
onDelete={onDelete}
|
||||
onTitleEdit={onTitleEdit}
|
||||
title={title}
|
||||
color={color}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useCreateCompanyProgress } from '@/companies/hooks/useCreateCompanyProgress';
|
||||
@ -7,7 +8,7 @@ import { useFilteredSearchCompanyQuery } from '@/companies/hooks/useFilteredSear
|
||||
import { DropdownMenuSelectableItem } from '@/ui/dropdown/components/DropdownMenuSelectableItem';
|
||||
import { StyledDropdownMenu } from '@/ui/dropdown/components/StyledDropdownMenu';
|
||||
import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer';
|
||||
import { IconPencil, IconPlus } from '@/ui/icon';
|
||||
import { IconPencil, IconPlus, IconTrash } from '@/ui/icon';
|
||||
import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect';
|
||||
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||
@ -19,6 +20,7 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { boardColumnsState } from '../states/boardColumnsState';
|
||||
import { BoardColumnHotkeyScope } from '../types/BoardColumnHotkeyScope';
|
||||
|
||||
import { BoardColumnEditTitleMenu } from './BoardColumnEditTitleMenu';
|
||||
@ -30,22 +32,30 @@ const StyledMenuContainer = styled.div`
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
onClose: () => void;
|
||||
title: string;
|
||||
color: string;
|
||||
onClose: () => void;
|
||||
onDelete?: (id: string) => void;
|
||||
onTitleEdit: (title: string, color: string) => void;
|
||||
stageId: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
type Menu = 'actions' | 'add' | 'title';
|
||||
|
||||
export function BoardColumnMenu({
|
||||
onClose,
|
||||
onTitleEdit,
|
||||
title,
|
||||
color,
|
||||
onClose,
|
||||
onDelete,
|
||||
onTitleEdit,
|
||||
stageId,
|
||||
title,
|
||||
}: OwnProps) {
|
||||
const [openMenu, setOpenMenu] = useState('actions');
|
||||
const [currentMenu, setCurrentMenu] = useState('actions');
|
||||
|
||||
const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState);
|
||||
|
||||
const boardColumnMenuRef = useRef(null);
|
||||
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
const createCompanyProgress = useCreateCompanyProgress();
|
||||
|
||||
@ -70,23 +80,31 @@ export function BoardColumnMenu({
|
||||
closeMenu();
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
goBackToPreviousHotkeyScope();
|
||||
onClose();
|
||||
}
|
||||
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
function setMenu(menu: string) {
|
||||
const closeMenu = useCallback(() => {
|
||||
goBackToPreviousHotkeyScope();
|
||||
onClose();
|
||||
}, [goBackToPreviousHotkeyScope, onClose]);
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
setBoardColumns((previousBoardColumns) =>
|
||||
previousBoardColumns.filter((column) => column.id !== stageId),
|
||||
);
|
||||
onDelete?.(stageId);
|
||||
closeMenu();
|
||||
}, [closeMenu, onDelete, setBoardColumns, stageId]);
|
||||
|
||||
function setMenu(menu: Menu) {
|
||||
if (menu === 'add') {
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
RelationPickerHotkeyScope.RelationPicker,
|
||||
);
|
||||
}
|
||||
setOpenMenu(menu);
|
||||
setCurrentMenu(menu);
|
||||
}
|
||||
const [searchFilter] = useRecoilScopedState(
|
||||
relationPickerSearchFilterScopedState,
|
||||
@ -108,19 +126,26 @@ export function BoardColumnMenu({
|
||||
return (
|
||||
<StyledMenuContainer ref={boardColumnMenuRef}>
|
||||
<StyledDropdownMenu>
|
||||
{openMenu === 'actions' && (
|
||||
{currentMenu === 'actions' && (
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
<DropdownMenuSelectableItem onClick={() => setMenu('title')}>
|
||||
<IconPencil size={icon.size.md} stroke={icon.stroke.sm} />
|
||||
Rename
|
||||
</DropdownMenuSelectableItem>
|
||||
<DropdownMenuSelectableItem
|
||||
disabled={boardColumns.length <= 1}
|
||||
onClick={handleDelete}
|
||||
>
|
||||
<IconTrash size={icon.size.md} stroke={icon.stroke.sm} />
|
||||
Delete
|
||||
</DropdownMenuSelectableItem>
|
||||
<DropdownMenuSelectableItem onClick={() => setMenu('add')}>
|
||||
<IconPlus size={icon.size.md} stroke={icon.stroke.sm} />
|
||||
New opportunity
|
||||
</DropdownMenuSelectableItem>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
)}
|
||||
{openMenu === 'title' && (
|
||||
{currentMenu === 'title' && (
|
||||
<BoardColumnEditTitleMenu
|
||||
color={color}
|
||||
onClose={closeMenu}
|
||||
@ -128,8 +153,7 @@ export function BoardColumnMenu({
|
||||
title={title}
|
||||
/>
|
||||
)}
|
||||
|
||||
{openMenu === 'add' && (
|
||||
{currentMenu === 'add' && (
|
||||
<SingleEntitySelect
|
||||
onEntitySelected={(value) => handleCompanySelected(value)}
|
||||
onCancel={closeMenu}
|
||||
|
||||
@ -43,16 +43,18 @@ const StyledWrapper = styled.div`
|
||||
|
||||
export function EntityBoard({
|
||||
boardOptions,
|
||||
updateSorts,
|
||||
onColumnAdd,
|
||||
onColumnDelete,
|
||||
onEditColumnTitle,
|
||||
onStageAdd,
|
||||
updateSorts,
|
||||
}: {
|
||||
boardOptions: BoardOptions;
|
||||
onColumnAdd?: (boardColumn: BoardColumnDefinition) => void;
|
||||
onColumnDelete?: (boardColumnId: string) => void;
|
||||
onEditColumnTitle: (columnId: string, title: string, color: string) => void;
|
||||
updateSorts: (
|
||||
sorts: Array<SelectedSortType<PipelineProgressOrderByWithRelationInput>>,
|
||||
) => void;
|
||||
onEditColumnTitle: (columnId: string, title: string, color: string) => void;
|
||||
onStageAdd?: (boardColumn: BoardColumnDefinition) => void;
|
||||
}) {
|
||||
const [boardColumns] = useRecoilState(boardColumnsState);
|
||||
const setCardSelected = useSetCardSelected();
|
||||
@ -133,7 +135,7 @@ export function EntityBoard({
|
||||
viewIcon={<IconList size={theme.icon.size.md} />}
|
||||
availableSorts={boardOptions.sorts}
|
||||
onSortsUpdate={updateSorts}
|
||||
onStageAdd={onStageAdd}
|
||||
onStageAdd={onColumnAdd}
|
||||
context={CompanyBoardRecoilScopeContext}
|
||||
/>
|
||||
<ScrollWrapper>
|
||||
@ -148,7 +150,8 @@ export function EntityBoard({
|
||||
<EntityBoardColumn
|
||||
boardOptions={boardOptions}
|
||||
column={column}
|
||||
onEditColumnTitle={onEditColumnTitle}
|
||||
onTitleEdit={onEditColumnTitle}
|
||||
onDelete={onColumnDelete}
|
||||
/>
|
||||
</RecoilScope>
|
||||
</BoardColumnIdContext.Provider>
|
||||
|
||||
@ -50,11 +50,13 @@ const BoardColumnCardsContainer = ({
|
||||
export function EntityBoardColumn({
|
||||
column,
|
||||
boardOptions,
|
||||
onEditColumnTitle,
|
||||
onDelete,
|
||||
onTitleEdit,
|
||||
}: {
|
||||
column: BoardColumnDefinition;
|
||||
boardOptions: BoardOptions;
|
||||
onEditColumnTitle: (columnId: string, title: string, color: string) => void;
|
||||
onDelete?: (columnId: string) => void;
|
||||
onTitleEdit: (columnId: string, title: string, color: string) => void;
|
||||
}) {
|
||||
const boardColumnId = useContext(BoardColumnIdContext) ?? '';
|
||||
|
||||
@ -66,15 +68,16 @@ export function EntityBoardColumn({
|
||||
boardCardIdsByColumnIdFamilyState(boardColumnId ?? ''),
|
||||
);
|
||||
|
||||
function handleEditColumnTitle(title: string, color: string) {
|
||||
onEditColumnTitle(boardColumnId, title, color);
|
||||
function handleTitleEdit(title: string, color: string) {
|
||||
onTitleEdit(boardColumnId, title, color);
|
||||
}
|
||||
|
||||
return (
|
||||
<Droppable droppableId={column.id}>
|
||||
{(droppableProvided) => (
|
||||
<BoardColumn
|
||||
onTitleEdit={handleEditColumnTitle}
|
||||
onTitleEdit={handleTitleEdit}
|
||||
onDelete={onDelete}
|
||||
title={column.title}
|
||||
color={column.colorCode}
|
||||
totalAmount={boardColumnTotal}
|
||||
|
||||
@ -11,27 +11,23 @@ const meta: Meta<typeof CircularProgressBar> = {
|
||||
args: {
|
||||
size: 50,
|
||||
},
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof CircularProgressBar>;
|
||||
const args = {};
|
||||
const defaultArgTypes = {
|
||||
control: false,
|
||||
};
|
||||
|
||||
export const Default: Story = {
|
||||
args,
|
||||
decorators: [ComponentDecorator],
|
||||
};
|
||||
|
||||
export const Catalog = {
|
||||
args: {
|
||||
...args,
|
||||
},
|
||||
argTypes: {
|
||||
strokeWidth: defaultArgTypes,
|
||||
segmentColor: defaultArgTypes,
|
||||
strokeWidth: { control: false },
|
||||
segmentColor: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
catalog: {
|
||||
|
||||
@ -44,7 +44,8 @@ export function Opportunities() {
|
||||
[],
|
||||
);
|
||||
|
||||
const { handlePipelineStageAdd } = usePipelineStages();
|
||||
const { handlePipelineStageAdd, handlePipelineStageDelete } =
|
||||
usePipelineStages();
|
||||
|
||||
const [updatePipelineStage] = useUpdatePipelineStageMutation();
|
||||
|
||||
@ -89,7 +90,8 @@ export function Opportunities() {
|
||||
boardOptions={opportunitiesBoardOptions}
|
||||
updateSorts={updateSorts}
|
||||
onEditColumnTitle={handleEditColumnTitle}
|
||||
onStageAdd={handlePipelineStageAdd}
|
||||
onColumnAdd={handlePipelineStageAdd}
|
||||
onColumnDelete={handlePipelineStageDelete}
|
||||
/>
|
||||
<EntityBoardActionBar />
|
||||
<EntityBoardContextMenu />
|
||||
|
||||
@ -128,6 +128,7 @@ export class AbilityFactory {
|
||||
can(AbilityAction.Read, 'PipelineStage', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Create, 'PipelineStage', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Update, 'PipelineStage', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Delete, 'PipelineStage', { workspaceId: workspace.id });
|
||||
|
||||
// PipelineProgress
|
||||
can(AbilityAction.Read, 'PipelineProgress', { workspaceId: workspace.id });
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
import { Resolver, Args, Query, Mutation } from '@nestjs/graphql';
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import {
|
||||
ForbiddenException,
|
||||
NotFoundException,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { accessibleBy } from '@casl/prisma';
|
||||
import { Prisma, Workspace } from '@prisma/client';
|
||||
@ -12,6 +16,7 @@ import { AbilityGuard } from 'src/guards/ability.guard';
|
||||
import { CheckAbilities } from 'src/decorators/check-abilities.decorator';
|
||||
import {
|
||||
CreatePipelineStageAbilityHandler,
|
||||
DeletePipelineStageAbilityHandler,
|
||||
ReadPipelineStageAbilityHandler,
|
||||
UpdatePipelineStageAbilityHandler,
|
||||
} from 'src/ability/handlers/pipeline-stage.ability-handler';
|
||||
@ -24,6 +29,7 @@ import {
|
||||
import { UpdateOnePipelineStageArgs } from 'src/core/@generated/pipeline-stage/update-one-pipeline-stage.args';
|
||||
import { CreateOnePipelineStageArgs } from 'src/core/@generated/pipeline-stage/create-one-pipeline-stage.args';
|
||||
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
||||
import { DeleteOnePipelineStageArgs } from 'src/core/@generated/pipeline-stage/delete-one-pipeline-stage.args';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => PipelineStage)
|
||||
@ -90,4 +96,54 @@ export class PipelineStageResolver {
|
||||
select: prismaSelect.value,
|
||||
} as Prisma.PipelineProgressUpdateArgs);
|
||||
}
|
||||
|
||||
@Mutation(() => PipelineStage, {
|
||||
nullable: false,
|
||||
})
|
||||
@UseGuards(AbilityGuard)
|
||||
@CheckAbilities(DeletePipelineStageAbilityHandler)
|
||||
async deleteOnePipelineStage(
|
||||
@Args() args: DeleteOnePipelineStageArgs,
|
||||
): Promise<PipelineStage> {
|
||||
const pipelineStageToDelete = await this.pipelineStageService.findUnique({
|
||||
where: args.where,
|
||||
});
|
||||
|
||||
if (!pipelineStageToDelete) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
const { pipelineId } = pipelineStageToDelete;
|
||||
|
||||
const remainingPipelineStages = await this.pipelineStageService.findMany({
|
||||
orderBy: { index: 'asc' },
|
||||
where: {
|
||||
pipelineId,
|
||||
NOT: { id: pipelineStageToDelete.id },
|
||||
},
|
||||
});
|
||||
|
||||
if (!remainingPipelineStages.length) {
|
||||
throw new ForbiddenException(
|
||||
`Deleting last pipeline stage is not allowed`,
|
||||
);
|
||||
}
|
||||
|
||||
const deletedPipelineStage = await this.pipelineStageService.delete({
|
||||
where: args.where,
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
remainingPipelineStages.map((pipelineStage, index) => {
|
||||
if (pipelineStage.index === index) return;
|
||||
|
||||
return this.pipelineStageService.update({
|
||||
data: { index },
|
||||
where: { id: pipelineStage.id },
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
return deletedPipelineStage;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user