Skip to content

Commit a22e219

Browse files
authored
feat: adds unpublish release pipeline action (#5797)
1 parent 51ce137 commit a22e219

4 files changed

Lines changed: 178 additions & 59 deletions

File tree

frontend/common/services/useReleasePipelines.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ export const releasePipelinesService = service
8989
url: `projects/${query.projectId}/release-pipelines/${query.pipelineId}/remove-feature/`,
9090
}),
9191
}),
92+
unpublishReleasePipeline: builder.mutation<
93+
Res['releasePipeline'],
94+
Req['publishReleasePipeline']
95+
>({
96+
invalidatesTags: [{ id: 'LIST', type: 'ReleasePipelines' }],
97+
query: (query: Req['publishReleasePipeline']) => ({
98+
method: 'POST',
99+
url: `projects/${query.projectId}/release-pipelines/${query.pipelineId}/unpublish-pipeline/`,
100+
}),
101+
}),
92102
updateReleasePipeline: builder.mutation<
93103
Res['releasePipeline'],
94104
Req['updateReleasePipeline']
@@ -164,6 +174,7 @@ export const {
164174
useGetReleasePipelinesQuery,
165175
usePublishReleasePipelineMutation,
166176
useRemoveFeatureMutation,
177+
useUnpublishReleasePipelineMutation,
167178
useUpdateReleasePipelineMutation,
168179
// END OF EXPORTS
169180
} = releasePipelinesService

frontend/web/components/pages/ReleasePipelinesPage.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
import PageTitle from 'components/PageTitle'
22
import { useGetReleasePipelinesQuery } from 'common/services/useReleasePipelines'
33
import { Button } from 'components/base/forms/Button'
4-
import { useHistory, useRouteMatch } from 'react-router-dom'
4+
import { useHistory } from 'react-router-dom'
55
import ConfigProvider from 'common/providers/ConfigProvider'
66
import ReleasePipelinesList from 'components/release-pipelines/ReleasePipelinesList'
77
import { useState } from 'react'
88
import PlanBasedAccess from 'components/PlanBasedAccess'
9-
10-
interface RouteParams {
11-
projectId: string
12-
}
9+
import { useRouteContext } from 'components/providers/RouteContext'
1310

1411
const ReleasePipelinesPage = () => {
1512
const history = useHistory()
16-
const match = useRouteMatch<RouteParams>()
13+
14+
const { projectId } = useRouteContext()
1715
const [page, setPage] = useState(1)
1816
const pageSize = 10
19-
const { projectId } = match.params
2017
const { data, isLoading } = useGetReleasePipelinesQuery({
2118
page,
2219
page_size: pageSize,
@@ -48,7 +45,7 @@ const ReleasePipelinesPage = () => {
4845
<ReleasePipelinesList
4946
data={data}
5047
isLoading={isLoading}
51-
projectId={projectId}
48+
projectId={projectId ?? NaN}
5249
page={page}
5350
pageSize={pageSize}
5451
onPageChange={setPage}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { useEffect } from 'react'
2+
import {
3+
usePublishReleasePipelineMutation,
4+
useUnpublishReleasePipelineMutation,
5+
} from 'common/services/useReleasePipelines'
6+
import Button from 'components/base/forms/Button'
7+
8+
type ChangeReleasePipelineStatusModalProps = {
9+
projectId: number
10+
isPublished: boolean
11+
pipelineId: number
12+
}
13+
14+
const ChangeReleasePipelineStatusModal = ({
15+
isPublished,
16+
pipelineId,
17+
projectId,
18+
}: ChangeReleasePipelineStatusModalProps) => {
19+
const [
20+
publishReleasePipeline,
21+
{
22+
error: publishReleasePipelineError,
23+
isError: isPublishingError,
24+
isLoading: isPublishing,
25+
isSuccess: isPublishingSuccess,
26+
},
27+
] = usePublishReleasePipelineMutation()
28+
29+
const [
30+
unpublishReleasePipeline,
31+
{
32+
error: unpublishReleasePipelineError,
33+
isError: isUnpublishingError,
34+
isLoading: isUnpublishing,
35+
isSuccess: isUnpublishingSuccess,
36+
},
37+
] = useUnpublishReleasePipelineMutation()
38+
39+
useEffect(() => {
40+
if (isPublishingSuccess) {
41+
closeModal2()
42+
toast('Release pipeline published successfully')
43+
return
44+
}
45+
46+
if (isPublishingError) {
47+
toast('Error publishing release pipeline', 'danger')
48+
return
49+
}
50+
}, [isPublishingSuccess, isPublishingError, publishReleasePipelineError])
51+
52+
useEffect(() => {
53+
if (isUnpublishingSuccess) {
54+
closeModal2()
55+
toast('Release pipeline unpublished successfully')
56+
return
57+
}
58+
59+
if (isUnpublishingError) {
60+
toast('Error unpublishing release pipeline', 'danger')
61+
return
62+
}
63+
}, [
64+
isUnpublishingSuccess,
65+
isUnpublishingError,
66+
unpublishReleasePipelineError,
67+
])
68+
69+
const handleConfirm = () => {
70+
if (isPublished) {
71+
unpublishReleasePipeline({
72+
pipelineId,
73+
projectId,
74+
})
75+
76+
return
77+
}
78+
79+
publishReleasePipeline({
80+
pipelineId,
81+
projectId,
82+
})
83+
}
84+
85+
const isLoading = isPublishing || isUnpublishing
86+
87+
return (
88+
<div className='p-0'>
89+
<p>
90+
Are you sure you want to{' '}
91+
<strong>{isPublished ? 'unpublish' : 'publish'}</strong> this release
92+
pipeline?
93+
</p>
94+
<div className='text-right mt-5'>
95+
<Button
96+
theme='secondary'
97+
className='mr-2'
98+
onClick={() => closeModal2()}
99+
>
100+
Cancel
101+
</Button>
102+
<Button onClick={handleConfirm} disabled={isLoading}>
103+
{isPublished ? 'Unpublish' : 'Publish'}
104+
</Button>
105+
</div>
106+
</div>
107+
)
108+
}
109+
110+
export type { ChangeReleasePipelineStatusModalProps }
111+
export default ChangeReleasePipelineStatusModal

frontend/web/components/release-pipelines/ReleasePipelinesList.tsx

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import {
2-
useDeleteReleasePipelineMutation,
3-
usePublishReleasePipelineMutation,
4-
} from 'common/services/useReleasePipelines'
1+
import { useDeleteReleasePipelineMutation } from 'common/services/useReleasePipelines'
52
import { PagedResponse, ReleasePipeline } from 'common/types/responses'
63
import { useHistory } from 'react-router-dom'
74
import Button from 'components/base/forms/Button'
@@ -10,8 +7,9 @@ import DropdownMenu from 'components/base/DropdownMenu'
107
import PanelSearch from 'components/PanelSearch'
118
import Tag from 'components/tags/Tag'
129
import { useEffect } from 'react'
10+
import ChangeReleasePipelineStatusModal from './ChangeReleasePipelineStatusModal'
1311

14-
const NoReleasePipelines = ({ projectId }: { projectId: string }) => {
12+
const NoReleasePipelines = ({ projectId }: { projectId: number }) => {
1513
const history = useHistory()
1614

1715
return (
@@ -50,7 +48,7 @@ const NoReleasePipelines = ({ projectId }: { projectId: string }) => {
5048
type ReleasePipelinesListProps = {
5149
data: PagedResponse<ReleasePipeline> | undefined
5250
isLoading: boolean
53-
projectId: string
51+
projectId: number
5452
page: number
5553
pageSize: number
5654
onPageChange: (page: number) => void
@@ -74,30 +72,8 @@ const ReleasePipelinesList = ({
7472
isSuccess: isDeletingSuccess,
7573
},
7674
] = useDeleteReleasePipelineMutation()
77-
const [
78-
publishReleasePipeline,
79-
{
80-
error: publishReleasePipelineError,
81-
isError: isPublishingError,
82-
isLoading: isPublishing,
83-
isSuccess: isPublishingSuccess,
84-
},
85-
] = usePublishReleasePipelineMutation()
86-
const pipelinesList = data?.results
87-
88-
useEffect(() => {
89-
if (isPublishingSuccess) {
90-
return toast('Release pipeline published successfully')
91-
}
9275

93-
if (isPublishingError) {
94-
return toast(
95-
publishReleasePipelineError?.data?.detail ??
96-
'Something went wrong while publishing the release pipeline',
97-
'danger',
98-
)
99-
}
100-
}, [isPublishingSuccess, isPublishingError, publishReleasePipelineError])
76+
const pipelinesList = data?.results
10177

10278
useEffect(() => {
10379
if (isDeletingSuccess) {
@@ -113,6 +89,21 @@ const ReleasePipelinesList = ({
11389
}
11490
}, [isDeletingSuccess, isDeletingError, deleteReleasePipelineError])
11591

92+
const openChangeReleasePipelineStatusModal = (
93+
projectId: number,
94+
pipelineId: number,
95+
isPublished: boolean,
96+
) => {
97+
openModal2(
98+
isPublished ? 'Unpublish Release Pipeline' : 'Publish Release Pipeline',
99+
<ChangeReleasePipelineStatusModal
100+
isPublished={isPublished}
101+
pipelineId={pipelineId}
102+
projectId={projectId}
103+
/>,
104+
)
105+
}
106+
116107
if (isLoading) {
117108
return (
118109
<div className='text-center'>
@@ -150,6 +141,14 @@ const ReleasePipelinesList = ({
150141
stages_count,
151142
}: ReleasePipeline) => {
152143
const isPublished = !!published_at
144+
const canUnpublish = isPublished && !features?.length
145+
146+
const getTooltip = (action: string) => {
147+
if (isPublished) {
148+
return `Cannot ${action} a published release pipeline`
149+
}
150+
return undefined
151+
}
153152

154153
return (
155154
<Row key={id} className='list-item'>
@@ -182,43 +181,44 @@ const ReleasePipelinesList = ({
182181
<DropdownMenu
183182
items={[
184183
{
185-
disabled: isPublishing || !!published_at,
184+
disabled: isPublished,
186185
icon: 'edit' as IconName,
187-
label: 'Edit Release Pipeline',
186+
label: 'Edit',
188187
onClick: () => {
189188
history.push(
190189
`/project/${projectId}/release-pipelines/${id}/edit`,
191190
)
192191
},
193-
tooltip: published_at
194-
? 'Cannot edit a published release pipeline'
195-
: undefined,
192+
tooltip: getTooltip('edit'),
193+
},
194+
{
195+
disabled: isPublished && !canUnpublish,
196+
icon: isPublished
197+
? 'minus-circle'
198+
: ('checkmark-circle' as IconName),
199+
label: isPublished ? 'Unpublish' : 'Publish',
200+
onClick: () =>
201+
openChangeReleasePipelineStatusModal(
202+
projectId,
203+
id,
204+
isPublished,
205+
),
206+
tooltip:
207+
isPublished && !canUnpublish
208+
? 'Cannot unpublish a release pipeline with in-flight features'
209+
: undefined,
196210
},
197-
...(!isPublished
198-
? [
199-
{
200-
disabled: isPublishing,
201-
icon: 'checkmark-circle' as IconName,
202-
label: 'Publish Release Pipeline',
203-
onClick: () => {
204-
publishReleasePipeline({
205-
pipelineId: id,
206-
projectId: Number(projectId),
207-
})
208-
},
209-
},
210-
]
211-
: []),
212211
{
213-
disabled: isDeleting,
212+
disabled: isDeleting || isPublished,
214213
icon: 'trash-2',
215-
label: 'Remove Release Pipeline',
214+
label: 'Remove',
216215
onClick: () => {
217216
deleteReleasePipeline({
218217
pipelineId: id,
219218
projectId: Number(projectId),
220219
})
221220
},
221+
tooltip: getTooltip('remove'),
222222
},
223223
]}
224224
/>

0 commit comments

Comments
 (0)