Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit e0c78b1

Browse files
author
Noah Lee
authored
Add the DynamicPayloadModal to post the dyanmic_payload (#393)
* Add the `dynamic_payload` field in openapi * Add the `DynamicPayload` type to the api package * Add the `DynamicPayloadModal` component * Fix the condition
1 parent 7c1cdbd commit e0c78b1

File tree

9 files changed

+244
-15
lines changed

9 files changed

+244
-15
lines changed

openapi/v1.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,8 @@ components:
18401840
type: string
18411841
payload:
18421842
type: string
1843+
dynamic_payload:
1844+
$ref: '#/components/schemas/DynamicPayload'
18431845
production_environment:
18441846
type: boolean
18451847
review:
@@ -1861,6 +1863,39 @@ components:
18611863
- auto_merge
18621864
- payload
18631865
- production_environment
1866+
DynamicPayload:
1867+
type: object
1868+
properties:
1869+
enabled:
1870+
type: boolean
1871+
inputs:
1872+
# Dictionaries
1873+
type: object
1874+
additionalProperties:
1875+
type: object
1876+
properties:
1877+
type:
1878+
type: string
1879+
enum:
1880+
- select
1881+
- number
1882+
- string
1883+
- boolean
1884+
required:
1885+
type: boolean
1886+
default:
1887+
anyOf:
1888+
- type: number
1889+
- type: string
1890+
- type: boolean
1891+
description:
1892+
type: string
1893+
options:
1894+
type: array
1895+
items:
1896+
type: string
1897+
required:
1898+
- type
18641899
Reviews:
18651900
type: array
18661901
items:

ui/src/apis/config.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ interface ConfigData {
1111
interface EnvData {
1212
name: string
1313
required_contexts?: string[]
14+
dynamic_payload?: {
15+
enabled: boolean,
16+
inputs: any,
17+
}
1418
review?: {
1519
enabled: boolean
1620
reviewers: string[]
@@ -19,11 +23,15 @@ interface EnvData {
1923

2024
const mapDataToConfig = (data: ConfigData): Config => {
2125
const envs: Env[] = data.envs.map((e: EnvData) => {
22-
const { review } = e
26+
const { dynamic_payload, review } = e
2327

2428
return {
2529
name: e.name,
2630
requiredContexts: e.required_contexts,
31+
dynamicPayload: (dynamic_payload)? {
32+
enabled: dynamic_payload?.enabled,
33+
inputs: dynamic_payload?.inputs,
34+
} : undefined,
2735
review,
2836
}
2937
})

ui/src/apis/deployment.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,13 @@ export const getDeployment = async (namespace: string, name: string, number: num
191191
return deployment
192192
}
193193

194-
export const createDeployment = async (namespace: string, name: string, type: DeploymentType = DeploymentType.Commit, ref: string, env: string): Promise<Deployment> => {
194+
// eslint-disable-next-line
195+
export const createDeployment = async (namespace: string, name: string, type: DeploymentType = DeploymentType.Commit, ref: string, env: string, payload?: any): Promise<Deployment> => {
195196
const body = JSON.stringify({
196197
type,
197198
ref,
198-
env
199+
env,
200+
dynamic_payload: payload
199201
})
200202
const response = await _fetch(`${instance}/api/v1/repos/${namespace}/${name}/deployments`, {
201203
headers,

ui/src/components/DeployForm.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ export default function DeployForm(props: DeployFormProps): JSX.Element {
182182
return (
183183
<Form
184184
onFinish={onClickFinish}
185-
name="deploy">
185+
name="deploy"
186+
>
186187
<Form.Item
187188
{...selectLayout}
188189
rules={[{required: true}]}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { Modal, Form, Select, Input, InputNumber, Checkbox } from "antd"
2+
3+
import { Env, DynamicPayloadInput, DynamicPayloadInputTypeEnum } from "../models"
4+
5+
export interface DynamicPayloadModalProps {
6+
visible: boolean
7+
env: Env
8+
onClickOk(values: any): void
9+
onClickCancel(): void
10+
}
11+
12+
export default function DynamicPayloadModal(props: DynamicPayloadModalProps): JSX.Element {
13+
const [ form ] = Form.useForm()
14+
15+
const onClickOk = () => {
16+
form.validateFields()
17+
.then(values => {
18+
props.onClickOk(values)
19+
})
20+
.catch(info => {
21+
console.log(info)
22+
})
23+
}
24+
25+
const onClickCancel = () => {
26+
props.onClickCancel()
27+
}
28+
29+
// Build items dynamically
30+
const items = new Array<JSX.Element>()
31+
if (props.env.dynamicPayload) {
32+
// Object.entries(props.env.dynamicPayload.inputs).forEach()
33+
Object.entries(props.env.dynamicPayload.inputs).forEach((entry) => {
34+
const [name, input] = entry
35+
items.push(<DynamicItem key={name} name={name} input={input}/>)
36+
})
37+
}
38+
39+
// Build the initialValues
40+
const initialValues: any = {}
41+
if (props.env.dynamicPayload) {
42+
Object.entries(props.env.dynamicPayload.inputs).forEach((entry) => {
43+
const [name, input] = entry
44+
initialValues[name] = input.default
45+
})
46+
}
47+
48+
return (
49+
<Modal
50+
visible={props.visible}
51+
onOk={onClickOk}
52+
onCancel={onClickCancel}
53+
>
54+
<Form
55+
form={form}
56+
layout="vertical"
57+
name="dynamic_payload"
58+
initialValues={initialValues}
59+
>
60+
{items.map(item => item)}
61+
</Form>
62+
</Modal>
63+
)
64+
}
65+
66+
interface DynamicItemProps {
67+
name: string
68+
input: DynamicPayloadInput
69+
}
70+
71+
function DynamicItem({name, input}: DynamicItemProps): JSX.Element {
72+
// Capitalize the first character.
73+
const label = name.charAt(0).toUpperCase() + name.slice(1)
74+
const description = input.description
75+
const rules = (input.required)? [{required: true}] : []
76+
77+
switch (input.type) {
78+
case DynamicPayloadInputTypeEnum.Select:
79+
return (
80+
<Form.Item
81+
label={label}
82+
name={name}
83+
tooltip={description}
84+
rules={rules}
85+
>
86+
<Select >
87+
{input.options?.map((option: any, idx: any) =>
88+
<Select.Option key={idx} value={option}>{option}</Select.Option>
89+
)}
90+
</Select>
91+
</Form.Item>
92+
)
93+
case DynamicPayloadInputTypeEnum.String:
94+
return (
95+
<Form.Item
96+
label={label}
97+
name={name}
98+
tooltip={description}
99+
rules={rules}
100+
>
101+
<Input />
102+
</Form.Item>
103+
)
104+
case DynamicPayloadInputTypeEnum.Number:
105+
return (
106+
<Form.Item
107+
label={label}
108+
name={name}
109+
tooltip={description}
110+
rules={rules}
111+
>
112+
<InputNumber />
113+
</Form.Item>
114+
)
115+
case DynamicPayloadInputTypeEnum.Boolean:
116+
return (
117+
<Form.Item
118+
label={label}
119+
name={name}
120+
tooltip={description}
121+
rules={rules}
122+
>
123+
<Checkbox />
124+
</Form.Item>
125+
)
126+
}
127+
}

ui/src/models/Config.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,31 @@ export default interface Config {
55
export interface Env {
66
name: string
77
requiredContexts?: string[]
8+
dynamicPayload?: DynamicPayload
89
review?: {
910
enabled: boolean
1011
reviewers: string[]
1112
}
1213
}
14+
15+
export interface DynamicPayload {
16+
enabled: boolean
17+
inputs: {
18+
[key: string]: DynamicPayloadInput
19+
}
20+
}
21+
22+
export interface DynamicPayloadInput {
23+
type: DynamicPayloadInputTypeEnum
24+
required?: boolean
25+
default?: any
26+
description?: string
27+
options?: string[]
28+
}
29+
30+
export enum DynamicPayloadInputTypeEnum {
31+
Select = "select",
32+
String = "string",
33+
Number = "number",
34+
Boolean = "boolean"
35+
}

ui/src/models/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ import Deployment, {
55
DeploymentType,
66
DeploymentStatus,
77
} from "./Deployment"
8-
import Config, { Env } from "./Config"
8+
import Config, {
9+
Env,
10+
DynamicPayload,
11+
DynamicPayloadInput,
12+
DynamicPayloadInputTypeEnum
13+
} from "./Config"
914
import Commit, { Author, Status, StatusState } from "./Commit"
1015
import Branch from "./Branch"
1116
import Tag from "./Tag"
@@ -33,6 +38,8 @@ export type {
3338
DeploymentStatus,
3439
Config,
3540
Env,
41+
DynamicPayload,
42+
DynamicPayloadInput,
3643
Commit,
3744
Author,
3845
Status,
@@ -58,6 +65,7 @@ export {
5865
HttpUnprocessableEntityError,
5966
DeploymentStatusEnum,
6067
DeploymentType,
68+
DynamicPayloadInputTypeEnum,
6169
StatusState,
6270
RequestStatus,
6371
ReviewStatusEnum,

ui/src/redux/repoDeploy.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,9 @@ export const fetchUser = createAsyncThunk<User, void, { state: {repoDeploy: Repo
256256
}
257257
)
258258

259-
export const deploy = createAsyncThunk<void, void, { state: {repoDeploy: RepoDeployState}}> (
259+
export const deploy = createAsyncThunk<void, any, { state: {repoDeploy: RepoDeployState}}> (
260260
"repoDeploy/deploy",
261-
async (_ , { getState, rejectWithValue, requestId }) => {
261+
async (payload, { getState, rejectWithValue, requestId }) => {
262262
const { namespace, name, env, type, branch, commit, tag, deploying, deployId } = getState().repoDeploy
263263
if (!env) {
264264
throw new Error("The env is undefined.")
@@ -271,11 +271,11 @@ export const deploy = createAsyncThunk<void, void, { state: {repoDeploy: RepoDep
271271
try {
272272
let deployment: Deployment
273273
if (type === DeploymentType.Commit && commit) {
274-
deployment = await createDeployment(namespace, name, type, commit.sha, env.name)
274+
deployment = await createDeployment(namespace, name, type, commit.sha, env.name, payload)
275275
} else if (type === DeploymentType.Branch && branch) {
276-
deployment = await createDeployment(namespace, name, type, branch.name, env.name)
276+
deployment = await createDeployment(namespace, name, type, branch.name, env.name, payload)
277277
} else if (type === DeploymentType.Tag && tag) {
278-
deployment = await createDeployment(namespace, name, type, tag.name, env.name)
278+
deployment = await createDeployment(namespace, name, type, tag.name, env.name, payload)
279279
} else {
280280
throw new Error("The type should be one of them: commit, branch, and tag.")
281281
}

ui/src/views/RepoDeploy.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect } from "react";
1+
import { useEffect, useState } from "react";
22
import { shallowEqual } from "react-redux";
33
import { useParams } from "react-router-dom";
44
import { PageHeader, Result, Button } from "antd";
@@ -20,9 +20,11 @@ import {
2020
addTagManually,
2121
searchCandidates,
2222
fetchUser,
23-
deploy} from "../redux/repoDeploy"
23+
deploy
24+
} from "../redux/repoDeploy"
2425

2526
import DeployForm, {Option} from "../components/DeployForm"
27+
import DynamicPayloadModal from "../components/DynamicPayloadModal";
2628

2729
const { actions } = repoDeploySlice
2830

@@ -37,6 +39,7 @@ export default function RepoDeploy(): JSX.Element {
3739
display,
3840
config,
3941
envs,
42+
env,
4043
currentDeployment,
4144
branches,
4245
branchStatuses,
@@ -47,6 +50,8 @@ export default function RepoDeploy(): JSX.Element {
4750
deploying } = useAppSelector(state => state.repoDeploy, shallowEqual)
4851
const dispatch = useAppDispatch()
4952

53+
const [payloadModalVisible, setPayloadModalVisible] = useState(false);
54+
5055
useEffect(() => {
5156
const f = async () => {
5257
await dispatch(actions.init({namespace, name}))
@@ -99,10 +104,20 @@ export default function RepoDeploy(): JSX.Element {
99104
}
100105

101106
const onClickDeploy = () => {
102-
const f = async () => {
103-
await dispatch(deploy())
107+
if (env?.dynamicPayload?.enabled) {
108+
setPayloadModalVisible(true)
109+
} else {
110+
dispatch(deploy(null))
104111
}
105-
f()
112+
}
113+
114+
const onClickDeployWithPayload = (values: any) => {
115+
dispatch(deploy(values))
116+
setPayloadModalVisible(false)
117+
}
118+
119+
const onClickCancel = () => {
120+
setPayloadModalVisible(false)
106121
}
107122

108123
if (!display) {
@@ -154,6 +169,16 @@ export default function RepoDeploy(): JSX.Element {
154169
deploying={deploying === RequestStatus.Pending}
155170
onClickDeploy={onClickDeploy}
156171
/>
172+
{(env)?
173+
<DynamicPayloadModal
174+
visible={payloadModalVisible}
175+
env={env}
176+
onClickOk={onClickDeployWithPayload}
177+
onClickCancel={onClickCancel}
178+
/>
179+
:
180+
<></>
181+
}
157182
</div>
158183
</div>
159184
)

0 commit comments

Comments
 (0)