Skip to content

Commit 64f7f29

Browse files
authored
feat: Edit Release Pipeline Feature (#5650)
1 parent 58b9ac6 commit 64f7f29

16 files changed

Lines changed: 430 additions & 158 deletions

frontend/common/services/useReleasePipelines.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,24 @@ export const releasePipelinesService = service
7474
url: `projects/${query.projectId}/release-pipelines/${query.pipelineId}/publish-pipeline/`,
7575
}),
7676
}),
77+
updateReleasePipeline: builder.mutation<
78+
Res['releasePipeline'],
79+
Req['updateReleasePipeline']
80+
>({
81+
invalidatesTags: (res) => [
82+
{ id: 'LIST', type: 'ReleasePipelines' },
83+
{ id: res?.id, type: 'ReleasePipelines' },
84+
],
85+
query: (query: Req['updateReleasePipeline']) => ({
86+
body: {
87+
description: query.description,
88+
name: query.name,
89+
stages: query.stages,
90+
},
91+
method: 'PUT',
92+
url: `projects/${query.project}/release-pipelines/${query.id}/`,
93+
}),
94+
}),
7795
// END OF ENDPOINTS
7896
}),
7997
})
@@ -117,6 +135,7 @@ export const {
117135
useGetReleasePipelineQuery,
118136
useGetReleasePipelinesQuery,
119137
usePublishReleasePipelineMutation,
138+
useUpdateReleasePipelineMutation,
120139
// END OF EXPORTS
121140
} = releasePipelinesService
122141

frontend/common/types/requests.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,17 @@ export interface StageActionRequest {
7777
action_body: { enabled: boolean; segment_id?: number }
7878
}
7979

80-
export type ReleasePipelineRequest = {
80+
export interface ReleasePipelineRequest {
8181
project: number
8282
name: string
8383
description?: string
8484
stages: PipelineStageRequest[]
8585
}
8686

87+
export interface UpdateReleasePipelineRequest extends ReleasePipelineRequest {
88+
id: number
89+
}
90+
8791
export type PipelineStageRequest = {
8892
name: string
8993
environment: number
@@ -706,6 +710,7 @@ export type Req = {
706710
getReleasePipelines: PagedRequest<{ projectId: number }>
707711
getReleasePipeline: { projectId: number; pipelineId: number }
708712
createReleasePipeline: ReleasePipelineRequest
713+
updateReleasePipeline: UpdateReleasePipelineRequest
709714
getPipelineStages: PagedRequest<{
710715
projectId: number
711716
pipelineId: number

frontend/common/utils/utils.tsx

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { defaultFlags } from 'common/stores/default-flags'
2727
import Color from 'color'
2828
import { selectBuildVersion } from 'common/services/useBuildVersion'
2929
import { getStore } from 'common/store'
30+
import { TimeUnit } from 'components/release-pipelines/constants'
3031

3132
const semver = require('semver')
3233

@@ -599,6 +600,53 @@ const Utils = Object.assign({}, require('./base/_utils'), {
599600
removeElementFromArray(array: any[], index: number) {
600601
return array.slice(0, index).concat(array.slice(index + 1))
601602
},
603+
getExistingWaitForTime: (
604+
waitFor: string | undefined,
605+
): { amountOfTime: number; timeUnit: (typeof TimeUnit)[keyof typeof TimeUnit] } | undefined => {
606+
if (!waitFor) {
607+
return
608+
}
609+
610+
const timeParts = waitFor.split(':')
611+
612+
if (timeParts.length != 3) return
613+
614+
const [hours, minutes, seconds] = timeParts
615+
616+
const amountOfMinutes = Number(minutes)
617+
const amountOfHours = Number(hours)
618+
const amountOfSeconds = Number(seconds)
619+
620+
if (amountOfHours + amountOfMinutes + amountOfSeconds === 0) {
621+
return
622+
}
623+
624+
// Days
625+
if (
626+
amountOfHours % 24 === 0 &&
627+
amountOfMinutes === 0 &&
628+
amountOfSeconds === 0
629+
) {
630+
return {
631+
amountOfTime: amountOfHours / 24,
632+
timeUnit: TimeUnit.DAY,
633+
}
634+
}
635+
636+
// Hours
637+
if (amountOfHours > 0 && amountOfMinutes === 0 && amountOfSeconds === 0) {
638+
return {
639+
amountOfTime: amountOfHours,
640+
timeUnit: TimeUnit.HOUR,
641+
}
642+
}
643+
644+
// Minutes
645+
return {
646+
amountOfTime: amountOfMinutes,
647+
timeUnit: TimeUnit.MINUTE,
648+
}
649+
},
602650
renderWithPermission(permission: boolean, name: string, el: ReactNode) {
603651
return permission ? (
604652
el
@@ -608,6 +656,7 @@ const Utils = Object.assign({}, require('./base/_utils'), {
608656
</Tooltip>
609657
)
610658
},
659+
611660
sanitiseDiffString: (value: FlagsmithValue) => {
612661
if (value === undefined || value == null) {
613662
return ''
@@ -671,11 +720,11 @@ const Utils = Object.assign({}, require('./base/_utils'), {
671720
}
672721
}
673722
},
674-
675723
tagDisabled: (tag: Tag | undefined) => {
676724
const hasStaleFlagsPermission = Utils.getPlansPermission('STALE_FLAGS')
677725
return tag?.type === 'STALE' && !hasStaleFlagsPermission
678726
},
727+
679728
toKebabCase: (string: string) =>
680729
string
681730
.replace(/([a-z])([A-Z])/g, '$1-$2')
@@ -705,7 +754,6 @@ const Utils = Object.assign({}, require('./base/_utils'), {
705754
return true
706755
}
707756
},
708-
709757
validateRule(rule: SegmentCondition) {
710758
if (!rule) return false
711759
if (rule.delete) {
@@ -762,6 +810,7 @@ const Utils = Object.assign({}, require('./base/_utils'), {
762810
)
763811
}
764812
},
813+
765814
valueToFeatureState(value: FlagsmithValue, trimSpaces = true) {
766815
const val = Utils.getTypedValue(value, undefined, trimSpaces)
767816

@@ -790,7 +839,6 @@ const Utils = Object.assign({}, require('./base/_utils'), {
790839
type: 'unicode',
791840
}
792841
},
793-
794842
valueToTrait(value: FlagsmithValue) {
795843
const val = Utils.getTypedValue(value)
796844

frontend/web/components/base/DropdownMenu.tsx

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,25 +68,36 @@ const DropdownMenu: React.FC<DropdownMenuProps> = ({
6868
createPortal(
6969
<div ref={dropDownRef} className='feature-action__list'>
7070
{items.map((item, index) => (
71-
<div
71+
<Tooltip
7272
key={index}
73-
className={classNames('feature-action__item', {
74-
'feature-action__item_disabled': item.disabled,
75-
})}
76-
data-test={item.dataTest}
77-
onClick={(e) => {
78-
e.stopPropagation()
79-
if (!item.disabled) {
80-
item.onClick(e)
81-
setIsOpen(false)
82-
}
83-
}}
73+
title={
74+
<div
75+
className={classNames('feature-action__item', {
76+
'feature-action__item_disabled': item.disabled,
77+
})}
78+
data-test={item.dataTest}
79+
onClick={(e) => {
80+
e.stopPropagation()
81+
if (!item.disabled) {
82+
item.onClick(e)
83+
setIsOpen(false)
84+
}
85+
}}
86+
>
87+
{item.icon && (
88+
<Icon
89+
name={item.icon}
90+
width={iconWidth}
91+
fill={iconFill}
92+
/>
93+
)}
94+
<span>{item.label}</span>
95+
</div>
96+
}
97+
place='right'
8498
>
85-
{item.icon && (
86-
<Icon name={item.icon} width={iconWidth} fill={iconFill} />
87-
)}
88-
<span>{item.label}</span>
89-
</div>
99+
{item.tooltip ?? ''}
100+
</Tooltip>
90101
))}
91102
</div>,
92103
document.body,

frontend/web/components/base/accordion/AccordionCard.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ interface AccordionCardProps {
77
children?: React.ReactNode
88
title?: string
99
className?: string
10+
defaultOpen?: boolean
1011
}
1112

1213
const AccordionCard: FC<AccordionCardProps> = ({
1314
children,
15+
defaultOpen = false,
1416
title = 'Summary',
1517
}) => {
16-
const [open, setOpen] = useState(false)
18+
const [open, setOpen] = useState(defaultOpen)
1719

1820
return (
1921
<div className='d-flex flex-column px-3 py-3 accordion-card m-0'>

frontend/web/components/pages/ReleasePipelinesPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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'
4+
import { useHistory, useRouteMatch } from 'react-router-dom'
55
import ConfigProvider from 'common/providers/ConfigProvider'
66
import ReleasePipelinesList from 'components/release-pipelines/ReleasePipelinesList'
77
import { useState } from 'react'

0 commit comments

Comments
 (0)