From 2d340a996ae56bd0a2ec330564039ac57e797826 Mon Sep 17 00:00:00 2001 From: noah Date: Tue, 29 Mar 2022 20:44:05 +0900 Subject: [PATCH 1/4] Add the `dynamic_payload` field in openapi --- openapi/v1.yaml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/openapi/v1.yaml b/openapi/v1.yaml index d75573aa..78822e11 100644 --- a/openapi/v1.yaml +++ b/openapi/v1.yaml @@ -1840,6 +1840,8 @@ components: type: string payload: type: string + dynamic_payload: + $ref: '#/components/schemas/DynamicPayload' production_environment: type: boolean review: @@ -1861,6 +1863,38 @@ components: - auto_merge - payload - production_environment + DynamicPayload: + type: object + properties: + enabled: + type: boolean + inputs: + type: array + items: + type: object + properties: + type: + type: string + enum: + - select + - number + - string + - boolean + required: + type: boolean + default: + anyOf: + - type: number + - type: string + - type: boolean + description: + type: string + options: + type: array + items: + type: string + required: + - type Reviews: type: array items: From 7b69167ed69705ae1e5af7bbeff56cfc48e9c4cc Mon Sep 17 00:00:00 2001 From: noah Date: Tue, 29 Mar 2022 21:11:56 +0900 Subject: [PATCH 2/4] Add the `DynamicPayload` type to the api package --- openapi/v1.yaml | 5 +++-- ui/src/apis/config.ts | 12 ++++++++++-- ui/src/models/Config.ts | 21 +++++++++++++++++++++ ui/src/models/index.ts | 10 +++++++++- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/openapi/v1.yaml b/openapi/v1.yaml index 78822e11..7ec240d9 100644 --- a/openapi/v1.yaml +++ b/openapi/v1.yaml @@ -1869,8 +1869,9 @@ components: enabled: type: boolean inputs: - type: array - items: + # Dictionaries + type: object + additionalProperties: type: object properties: type: diff --git a/ui/src/apis/config.ts b/ui/src/apis/config.ts index 6510a166..74148263 100644 --- a/ui/src/apis/config.ts +++ b/ui/src/apis/config.ts @@ -2,7 +2,7 @@ import { StatusCodes } from 'http-status-codes' import { instance, headers } from './setting' import { _fetch } from "./_base" -import { Config, Env, HttpNotFoundError } from '../models' +import { Config, Env, DynamicPayloadInputTypeEnum, HttpNotFoundError } from '../models' interface ConfigData { envs: EnvData[] @@ -11,6 +11,10 @@ interface ConfigData { interface EnvData { name: string required_contexts?: string[] + dynamic_payload?: { + enabled: boolean, + inputs: Map, + } review?: { enabled: boolean reviewers: string[] @@ -19,11 +23,15 @@ interface EnvData { const mapDataToConfig = (data: ConfigData): Config => { const envs: Env[] = data.envs.map((e: EnvData) => { - const { review } = e + const { dynamic_payload, review } = e return { name: e.name, requiredContexts: e.required_contexts, + dynamicPayload: (dynamic_payload)? { + enabled: dynamic_payload?.enabled, + inputs: dynamic_payload?.inputs, + } : undefined, review, } }) diff --git a/ui/src/models/Config.ts b/ui/src/models/Config.ts index 5744d132..7de1ccd7 100644 --- a/ui/src/models/Config.ts +++ b/ui/src/models/Config.ts @@ -5,8 +5,29 @@ export default interface Config { export interface Env { name: string requiredContexts?: string[] + dynamicPayload?: DynamicPayload review?: { enabled: boolean reviewers: string[] } } + +export interface DynamicPayload { + enabled: boolean + inputs: Map +} + +export interface DynamicPayloadInput { + type: DynamicPayloadInputTypeEnum + required: boolean + default: any + description: string + options: string[] +} + +export enum DynamicPayloadInputTypeEnum { + Select = "select", + String = "string", + Number = "number", + Boolean = "boolean" +} diff --git a/ui/src/models/index.ts b/ui/src/models/index.ts index ae81c1f5..fd03431e 100644 --- a/ui/src/models/index.ts +++ b/ui/src/models/index.ts @@ -5,7 +5,12 @@ import Deployment, { DeploymentType, DeploymentStatus, } from "./Deployment" -import Config, { Env } from "./Config" +import Config, { + Env, + DynamicPayload, + DynamicPayloadInput, + DynamicPayloadInputTypeEnum +} from "./Config" import Commit, { Author, Status, StatusState } from "./Commit" import Branch from "./Branch" import Tag from "./Tag" @@ -33,6 +38,8 @@ export type { DeploymentStatus, Config, Env, + DynamicPayload, + DynamicPayloadInput, Commit, Author, Status, @@ -58,6 +65,7 @@ export { HttpUnprocessableEntityError, DeploymentStatusEnum, DeploymentType, + DynamicPayloadInputTypeEnum, StatusState, RequestStatus, ReviewStatusEnum, From 22a8c7fc3648bd0c7453ecb8d950e6d385cd2ae0 Mon Sep 17 00:00:00 2001 From: noah Date: Sat, 2 Apr 2022 16:54:46 +0900 Subject: [PATCH 3/4] Add the `DynamicPayloadModal` component --- ui/src/apis/config.ts | 4 +- ui/src/apis/deployment.ts | 6 +- ui/src/components/DeployForm.tsx | 3 +- ui/src/components/DynamicPayloadModal.tsx | 130 ++++++++++++++++++++++ ui/src/models/Config.ts | 12 +- ui/src/redux/repoDeploy.tsx | 10 +- ui/src/views/RepoDeploy.tsx | 35 +++++- 7 files changed, 180 insertions(+), 20 deletions(-) create mode 100644 ui/src/components/DynamicPayloadModal.tsx diff --git a/ui/src/apis/config.ts b/ui/src/apis/config.ts index 74148263..b8937c49 100644 --- a/ui/src/apis/config.ts +++ b/ui/src/apis/config.ts @@ -2,7 +2,7 @@ import { StatusCodes } from 'http-status-codes' import { instance, headers } from './setting' import { _fetch } from "./_base" -import { Config, Env, DynamicPayloadInputTypeEnum, HttpNotFoundError } from '../models' +import { Config, Env, HttpNotFoundError } from '../models' interface ConfigData { envs: EnvData[] @@ -13,7 +13,7 @@ interface EnvData { required_contexts?: string[] dynamic_payload?: { enabled: boolean, - inputs: Map, + inputs: any, } review?: { enabled: boolean diff --git a/ui/src/apis/deployment.ts b/ui/src/apis/deployment.ts index adc15a0a..58da41ea 100644 --- a/ui/src/apis/deployment.ts +++ b/ui/src/apis/deployment.ts @@ -191,11 +191,13 @@ export const getDeployment = async (namespace: string, name: string, number: num return deployment } -export const createDeployment = async (namespace: string, name: string, type: DeploymentType = DeploymentType.Commit, ref: string, env: string): Promise => { +// eslint-disable-next-line +export const createDeployment = async (namespace: string, name: string, type: DeploymentType = DeploymentType.Commit, ref: string, env: string, payload?: any): Promise => { const body = JSON.stringify({ type, ref, - env + env, + dynamic_payload: payload }) const response = await _fetch(`${instance}/api/v1/repos/${namespace}/${name}/deployments`, { headers, diff --git a/ui/src/components/DeployForm.tsx b/ui/src/components/DeployForm.tsx index 47eecdbf..ce162ab5 100644 --- a/ui/src/components/DeployForm.tsx +++ b/ui/src/components/DeployForm.tsx @@ -182,7 +182,8 @@ export default function DeployForm(props: DeployFormProps): JSX.Element { return (
+ name="deploy" + > { + form.validateFields() + .then(values => { + props.onClickOk(values) + }) + .catch(info => { + console.log(info) + }) + } + + const onClickCancel = () => { + props.onClickCancel() + } + + // Build items dynamically + const items = new Array() + if (props.env.dynamicPayload) { + // Object.entries(props.env.dynamicPayload.inputs).forEach() + Object.entries(props.env.dynamicPayload.inputs).forEach((entry) => { + const [name, input] = entry + items.push() + }) + } + + // Build the initialValues + const initialValues: any = {} + if (props.env.dynamicPayload) { + Object.entries(props.env.dynamicPayload.inputs).forEach((entry) => { + const [name, input] = entry + + if (input.default !== undefined) { + initialValues[name] = input.default + } + }) + } + + return ( + + + {items.map(item => item)} + + + ) +} + +interface DynamicItemProps { + name: string + input: DynamicPayloadInput +} + +function DynamicItem({name, input}: DynamicItemProps): JSX.Element { + // Capitalize the first character. + const label = name.charAt(0).toUpperCase() + name.slice(1) + const description = input.description + const rules = (input.required)? [{required: true}] : [] + + switch (input.type) { + case DynamicPayloadInputTypeEnum.Select: + return ( + + + + ) + case DynamicPayloadInputTypeEnum.String: + return ( + + + + ) + case DynamicPayloadInputTypeEnum.Number: + return ( + + + + ) + case DynamicPayloadInputTypeEnum.Boolean: + return ( + + + + ) + } +} diff --git a/ui/src/models/Config.ts b/ui/src/models/Config.ts index 7de1ccd7..519f5fbb 100644 --- a/ui/src/models/Config.ts +++ b/ui/src/models/Config.ts @@ -14,15 +14,17 @@ export interface Env { export interface DynamicPayload { enabled: boolean - inputs: Map + inputs: { + [key: string]: DynamicPayloadInput + } } export interface DynamicPayloadInput { type: DynamicPayloadInputTypeEnum - required: boolean - default: any - description: string - options: string[] + required?: boolean + default?: any + description?: string + options?: string[] } export enum DynamicPayloadInputTypeEnum { diff --git a/ui/src/redux/repoDeploy.tsx b/ui/src/redux/repoDeploy.tsx index d0d78c43..164021f1 100644 --- a/ui/src/redux/repoDeploy.tsx +++ b/ui/src/redux/repoDeploy.tsx @@ -256,9 +256,9 @@ export const fetchUser = createAsyncThunk ( +export const deploy = createAsyncThunk ( "repoDeploy/deploy", - async (_ , { getState, rejectWithValue, requestId }) => { + async (payload, { getState, rejectWithValue, requestId }) => { const { namespace, name, env, type, branch, commit, tag, deploying, deployId } = getState().repoDeploy if (!env) { throw new Error("The env is undefined.") @@ -271,11 +271,11 @@ export const deploy = createAsyncThunk state.repoDeploy, shallowEqual) const dispatch = useAppDispatch() + const [payloadModalVisible, setPayloadModalVisible] = useState(false); + useEffect(() => { const f = async () => { await dispatch(actions.init({namespace, name})) @@ -99,10 +104,20 @@ export default function RepoDeploy(): JSX.Element { } const onClickDeploy = () => { - const f = async () => { - await dispatch(deploy()) + if (env?.dynamicPayload?.enabled) { + setPayloadModalVisible(true) + } else { + dispatch(deploy(null)) } - f() + } + + const onClickDeployWithPayload = (values: any) => { + dispatch(deploy(values)) + setPayloadModalVisible(false) + } + + const onClickCancel = () => { + setPayloadModalVisible(false) } if (!display) { @@ -154,6 +169,16 @@ export default function RepoDeploy(): JSX.Element { deploying={deploying === RequestStatus.Pending} onClickDeploy={onClickDeploy} /> + {(env)? + + : + <> + } ) From 96d7f41a52c389657616e411a03a16db417f642b Mon Sep 17 00:00:00 2001 From: noah Date: Sat, 2 Apr 2022 17:42:47 +0900 Subject: [PATCH 4/4] Fix the condition --- ui/src/components/DynamicPayloadModal.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ui/src/components/DynamicPayloadModal.tsx b/ui/src/components/DynamicPayloadModal.tsx index 370c008b..63648fb7 100644 --- a/ui/src/components/DynamicPayloadModal.tsx +++ b/ui/src/components/DynamicPayloadModal.tsx @@ -41,10 +41,7 @@ export default function DynamicPayloadModal(props: DynamicPayloadModalProps): JS if (props.env.dynamicPayload) { Object.entries(props.env.dynamicPayload.inputs).forEach((entry) => { const [name, input] = entry - - if (input.default !== undefined) { - initialValues[name] = input.default - } + initialValues[name] = input.default }) }