This is an automated email from the ASF dual-hosted git repository.

kerwin pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new d4921fa2dd [Feature][UI] Support CRUD of project-level parameters. 
(#14344)
d4921fa2dd is described below

commit d4921fa2dda541d0fa3a198dd3052b61a73f2d37
Author: calvin <[email protected]>
AuthorDate: Tue Jun 13 18:54:41 2023 +0800

    [Feature][UI] Support CRUD of project-level parameters. (#14344)
---
 .../service/impl/ProjectParameterServiceImpl.java  |   8 +-
 .../resources/sql/dolphinscheduler_postgresql.sql  |   4 +
 .../src/layouts/content/use-dataList.ts            |  18 +-
 dolphinscheduler-ui/src/locales/en_US/menu.ts      |   1 +
 dolphinscheduler-ui/src/locales/en_US/project.ts   |  19 +-
 dolphinscheduler-ui/src/locales/zh_CN/menu.ts      |   1 +
 dolphinscheduler-ui/src/locales/zh_CN/project.ts   |  19 +-
 dolphinscheduler-ui/src/router/modules/projects.ts |  11 ++
 .../service/modules/projects-parameter/index.ts    |  89 ++++++++++
 .../service/modules/projects-parameter/types.ts    |  62 +++++++
 .../parameter/components/parameter-modal.tsx       | 147 ++++++++++++++++
 .../projects/parameter/components/use-modal.ts     | 112 ++++++++++++
 .../src/views/projects/parameter/index.tsx         | 161 +++++++++++++++++
 .../src/views/projects/parameter/use-table.ts      | 195 +++++++++++++++++++++
 14 files changed, 840 insertions(+), 7 deletions(-)

diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectParameterServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectParameterServiceImpl.java
index 56f18883b2..bae5142637 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectParameterServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectParameterServiceImpl.java
@@ -47,6 +47,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.google.common.collect.Lists;
@@ -135,7 +136,12 @@ public class ProjectParameterServiceImpl extends 
BaseServiceImpl implements Proj
         }
 
         // check if project parameter name exists
-        ProjectParameter tempProjectParameter = 
projectParameterMapper.queryByName(projectParameterName);
+        ProjectParameter tempProjectParameter = 
projectParameterMapper.selectOne(new QueryWrapper<ProjectParameter>()
+                .lambda()
+                .eq(ProjectParameter::getProjectCode, projectCode)
+                .eq(ProjectParameter::getParamName, projectParameterName)
+                .ne(ProjectParameter::getCode, code));
+
         if (tempProjectParameter != null) {
             log.error("Project parameter name {} already exists", 
projectParameterName);
             putMsg(result, Status.PROJECT_PARAMETER_ALREADY_EXISTS, 
projectParameterName);
diff --git 
a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql 
b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
index 1158e79c4c..be6e347f2c 100644
--- 
a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
+++ 
b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
@@ -996,6 +996,10 @@ DROP SEQUENCE IF EXISTS t_ds_worker_group_id_sequence;
 CREATE SEQUENCE  t_ds_worker_group_id_sequence;
 ALTER TABLE t_ds_worker_group ALTER COLUMN id SET DEFAULT 
NEXTVAL('t_ds_worker_group_id_sequence');
 
+DROP SEQUENCE IF EXISTS t_ds_project_parameter_id_sequence;
+CREATE SEQUENCE  t_ds_project_parameter_id_sequence;
+ALTER TABLE t_ds_project_parameter ALTER COLUMN id SET DEFAULT 
NEXTVAL('t_ds_project_parameter_id_sequence');
+
 -- Records of t_ds_user?user : admin , password : dolphinscheduler123
 INSERT INTO t_ds_user(user_name, user_password, user_type, email, phone, 
tenant_id, state, create_time, update_time, time_zone)
 VALUES ('admin', '7ad2410b2f4c074479a8937a28a22b8f', '0', '[email protected]', '', 
'-1', 1, '2018-03-27 15:48:50', '2018-10-24 17:40:22', null);
diff --git a/dolphinscheduler-ui/src/layouts/content/use-dataList.ts 
b/dolphinscheduler-ui/src/layouts/content/use-dataList.ts
index 1815fb524a..379073d2a1 100644
--- a/dolphinscheduler-ui/src/layouts/content/use-dataList.ts
+++ b/dolphinscheduler-ui/src/layouts/content/use-dataList.ts
@@ -102,12 +102,22 @@ export function useDataList() {
         icon: renderIcon(ProfileOutlined),
         children: [
           {
-            label:
-              t('menu.project_overview') +
-              (projectName ? `[${projectName}]` : ''),
+            label: t('menu.project') + (projectName ? `[${projectName}]` : ''),
             key: `/projects/${projectCode}`,
             icon: renderIcon(FundProjectionScreenOutlined),
-            payload: { projectName: projectName }
+            payload: { projectName: projectName },
+            children: [
+              {
+                label: t('menu.project_overview'),
+                key: `/projects/${projectCode}`,
+                payload: { projectName: projectName },
+              },
+              {
+                label: t('menu.project_parameter'),
+                key: `/projects/${projectCode}/parameter`,
+                payload: { projectName: projectName },
+              },
+            ]
           },
           {
             label: t('menu.workflow'),
diff --git a/dolphinscheduler-ui/src/locales/en_US/menu.ts 
b/dolphinscheduler-ui/src/locales/en_US/menu.ts
index 1a49c561c7..30d8b6f72a 100644
--- a/dolphinscheduler-ui/src/locales/en_US/menu.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/menu.ts
@@ -23,6 +23,7 @@ export default {
   monitor: 'Monitor',
   security: 'Security',
   project_overview: 'Project Overview',
+  project_parameter: 'Project Parameter',
   workflow_relation: 'Workflow Relation',
   workflow: 'Workflow',
   workflow_definition: 'Workflow Definition',
diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts 
b/dolphinscheduler-ui/src/locales/en_US/project.ts
index 1e63ecfc22..6bb98be1a1 100644
--- a/dolphinscheduler-ui/src/locales/en_US/project.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/project.ts
@@ -858,5 +858,22 @@ export default {
     dq: 'Data Quality',
     ml: 'Machine Learning',
     other: 'Other'
-  }
+  },
+  parameter: {
+    create_parameter: 'Create Parameter',
+    edit_parameter: 'Edit Parameter',
+    parameter_manage: 'Parameter Management',
+    code: 'Parameter Code',
+    name: 'Parameter Name',
+    value: 'Parameter Value',
+    create_time: 'Create Time',
+    update_time: 'Update Time',
+    name_tips: 'Please enter your parameter name',
+    value_tips: 'Please enter your parameter value',
+    operation: 'Operation',
+    edit: 'Edit',
+    delete: 'Delete',
+    delete_confirm: 'Delete?',
+    success: 'Success',
+  },
 }
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/menu.ts 
b/dolphinscheduler-ui/src/locales/zh_CN/menu.ts
index a29be34687..8f1f75d9e7 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/menu.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/menu.ts
@@ -24,6 +24,7 @@ export default {
   security: '安全中心',
   ui_setting: '界面设置',
   project_overview: '项目概览',
+  project_parameter: '项目变量',
   workflow_relation: '工作流关系',
   workflow: '工作流',
   workflow_definition: '工作流定义',
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts 
b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
index b0248d480a..6fc276aea5 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
@@ -834,5 +834,22 @@ export default {
     dq: '数据质量',
     ml: '机器学习',
     other: '其他'
-  }
+  },
+  parameter: {
+    create_parameter: '创建项目级变量',
+    edit_parameter: '修改项目级变量',
+    parameter_manage: '变量管理',
+    code: '变量编码',
+    name: '变量名称',
+    value: '变量值',
+    create_time: '创建时间',
+    update_time: '更新时间',
+    name_tips: '请输入变量名称',
+    value_tips: '请输入变量值',
+    operation: '操作',
+    edit: '编辑',
+    delete: '删除',
+    delete_confirm: '确定删除吗?',
+    success: '成功',
+  },
 }
diff --git a/dolphinscheduler-ui/src/router/modules/projects.ts 
b/dolphinscheduler-ui/src/router/modules/projects.ts
index e0b05b051d..bcc508ac95 100644
--- a/dolphinscheduler-ui/src/router/modules/projects.ts
+++ b/dolphinscheduler-ui/src/router/modules/projects.ts
@@ -53,6 +53,17 @@ export default {
         auth: []
       }
     },
+    {
+      path: '/projects/:projectCode/parameter',
+      name: 'projects-parameter',
+      component: components['projects-parameter'],
+      meta: {
+        title: '项目级变量',
+        activeMenu: 'projects',
+        showSide: true,
+        auth: []
+      }
+    },
     {
       path: '/projects/:projectCode/workflow/relation',
       name: 'workflow-relation',
diff --git 
a/dolphinscheduler-ui/src/service/modules/projects-parameter/index.ts 
b/dolphinscheduler-ui/src/service/modules/projects-parameter/index.ts
new file mode 100644
index 0000000000..be8d8ad56d
--- /dev/null
+++ b/dolphinscheduler-ui/src/service/modules/projects-parameter/index.ts
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { axios } from '@/service/service'
+import {
+  ListReq,
+  ProjectParameterCodeReq,
+  ProjectParameterReq,
+  UpdateProjectParameterReq
+} from './types'
+
+export function queryProjectParameterListPaging(
+  params: ListReq,
+  projectCode: number
+): any {
+  return axios({
+    url: `/projects/${projectCode}/project-parameter`,
+    method: 'get',
+    params
+  })
+}
+
+export function queryProjectParameterByCode(
+  projectCode: number,
+  code: number
+): any {
+  return axios({
+    url: `/projects/${projectCode}/project-parameter/${code}`,
+    method: 'get'
+  })
+}
+
+export function createProjectParameter(
+  data: ProjectParameterReq,
+  projectCode: number
+): any {
+  return axios({
+    url: `/projects/${projectCode}/project-parameter`,
+    method: 'post',
+    data
+  })
+}
+
+export function updateProjectParameter(
+  data: UpdateProjectParameterReq,
+  projectCode: number
+): any {
+  return axios({
+    url: `/projects/${projectCode}/project-parameter/${data.code}`,
+    method: 'put',
+    data
+  })
+}
+
+export function deleteProjectParameterByCode(
+  data: ProjectParameterCodeReq,
+  projectCode: number
+): any {
+  return axios({
+    url: `/projects/${projectCode}/project-parameter/delete`,
+    method: 'post',
+    data
+  })
+}
+
+export function deleteProjectParameterByCodes(
+  data: ProjectParameterCodeReq[],
+  projectCode: number
+): any {
+  return axios({
+    url: `/projects/${projectCode}/project-parameter/batch-delete`,
+    method: 'post',
+    data
+  })
+}
diff --git 
a/dolphinscheduler-ui/src/service/modules/projects-parameter/types.ts 
b/dolphinscheduler-ui/src/service/modules/projects-parameter/types.ts
new file mode 100644
index 0000000000..9e0f747136
--- /dev/null
+++ b/dolphinscheduler-ui/src/service/modules/projects-parameter/types.ts
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface ListReq {
+  pageNo: number
+  pageSize: number
+  searchVal?: string
+}
+
+interface ProjectParameterCodeReq {
+  code: number
+}
+
+interface ProjectParameterReq {
+  projectParameterName: string
+  projectParameterValue: string
+}
+
+interface UpdateProjectParameterReq extends ProjectParameterReq {
+  code: number
+}
+
+interface ProjectParameterList {
+  id: number
+  code: number
+  name: string
+  value: string
+  createTime: string
+  updateTime: string
+}
+
+interface ProjectParameterRes {
+  totalList: ProjectParameterList[]
+  total: number
+  totalPage: number
+  pageSize: number
+  currentPage: number
+  start: number
+}
+
+export {
+  ListReq,
+  ProjectParameterCodeReq,
+  ProjectParameterReq,
+  UpdateProjectParameterReq,
+  ProjectParameterRes,
+  ProjectParameterList
+}
diff --git 
a/dolphinscheduler-ui/src/views/projects/parameter/components/parameter-modal.tsx
 
b/dolphinscheduler-ui/src/views/projects/parameter/components/parameter-modal.tsx
new file mode 100644
index 0000000000..c69ae864b2
--- /dev/null
+++ 
b/dolphinscheduler-ui/src/views/projects/parameter/components/parameter-modal.tsx
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+  defineComponent,
+  getCurrentInstance,
+  PropType,
+  toRefs,
+  watch
+} from 'vue'
+import Modal from '@/components/modal'
+import { NForm, NFormItem, NInput } from 'naive-ui'
+import { useModal } from './use-modal'
+import { useI18n } from 'vue-i18n'
+
+const ParameterModal = defineComponent({
+  name: 'ParameterModal',
+  props: {
+    showModalRef: {
+      type: Boolean as PropType<boolean>,
+      default: false
+    },
+    statusRef: {
+      type: Number as PropType<number>,
+      default: 0
+    },
+    row: {
+      type: Object as PropType<any>,
+      default: {}
+    }
+  },
+  emits: ['cancelModal', 'confirmModal'],
+  setup(props, ctx) {
+    const { variables, handleValidate } = useModal(props, ctx)
+    const { t } = useI18n()
+
+    const cancelModal = () => {
+      if (props.statusRef === 0) {
+        variables.model.projectParameterName = ''
+        variables.model.projectParameterValue = ''
+      } else {
+        variables.model.projectParameterName = props.row.paramName
+        variables.model.projectParameterValue = props.row.paramValue
+      }
+      ctx.emit('cancelModal', props.showModalRef)
+    }
+
+    const confirmModal = () => {
+      handleValidate(props.statusRef)
+    }
+
+    const trim = getCurrentInstance()?.appContext.config.globalProperties.trim
+
+    watch(
+      () => props.showModalRef,
+      () => {
+        props.showModalRef
+      }
+    )
+
+    watch(
+      () => props.statusRef,
+      () => {
+        if (props.statusRef === 0) {
+          variables.model.projectParameterName = ''
+          variables.model.projectParameterValue = ''
+        } else {
+          variables.model.code = props.row.code
+          variables.model.projectParameterName = props.row.paramName
+          variables.model.projectParameterValue = props.row.paramValue
+        }
+      }
+    )
+
+    watch(
+      () => props.row,
+      () => {
+        variables.model.code = props.row.code
+        variables.model.projectParameterName = props.row.paramName
+        variables.model.projectParameterValue = props.row.paramValue
+      }
+    )
+
+    return { t, ...toRefs(variables), cancelModal, confirmModal, trim }
+  },
+  render() {
+    const { t } = this
+    return (
+      <div>
+        <Modal
+          title={
+            this.statusRef === 0
+              ? t('project.parameter.create_parameter')
+              : t('project.parameter.edit_parameter')
+          }
+          show={this.showModalRef}
+          onCancel={this.cancelModal}
+          onConfirm={this.confirmModal}
+          confirmDisabled={
+            !this.model.projectParameterName ||
+            !this.model.projectParameterValue
+          }
+          confirmClassName='btn-submit'
+          cancelClassName='btn-cancel'
+          confirmLoading={this.saving}
+        >
+          {{
+            default: () => (
+              <NForm model={this.model} rules={this.rules} ref='formRef'>
+                <NFormItem label={t('project.parameter.name')} path='name'>
+                  <NInput
+                    allowInput={this.trim}
+                    placeholder={t('project.parameter.name_tips')}
+                    v-model={[this.model.projectParameterName, 'value']}
+                  />
+                </NFormItem>
+                <NFormItem label={t('project.parameter.value')} path='value'>
+                  <NInput
+                    allowInput={this.trim}
+                    placeholder={t('project.parameter.value_tips')}
+                    v-model={[this.model.projectParameterValue, 'value']}
+                  />
+                </NFormItem>
+              </NForm>
+            )
+          }}
+        </Modal>
+      </div>
+    )
+  }
+})
+
+export default ParameterModal
diff --git 
a/dolphinscheduler-ui/src/views/projects/parameter/components/use-modal.ts 
b/dolphinscheduler-ui/src/views/projects/parameter/components/use-modal.ts
new file mode 100644
index 0000000000..56b5186846
--- /dev/null
+++ b/dolphinscheduler-ui/src/views/projects/parameter/components/use-modal.ts
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { reactive, ref, SetupContext } from 'vue'
+import { useI18n } from 'vue-i18n'
+import type { Router } from 'vue-router'
+import {
+  createProjectParameter,
+  updateProjectParameter
+} from '@/service/modules/projects-parameter'
+import {
+  ProjectParameterReq,
+  UpdateProjectParameterReq
+} from '@/service/modules/projects-parameter/types'
+import { useRouter } from 'vue-router'
+
+export function useModal(
+  props: any,
+  ctx: SetupContext<('cancelModal' | 'confirmModal')[]>
+) {
+  const { t } = useI18n()
+  const router: Router = useRouter()
+
+  const variables = reactive({
+    formRef: ref(),
+    projectCode: ref(Number(router.currentRoute.value.params.projectCode)),
+    model: {
+      code: ref<number>(-1),
+      projectParameterName: ref(''),
+      projectParameterValue: ref('')
+    },
+    saving: false,
+    rules: {
+      name: {
+        required: true,
+        trigger: ['input', 'blur'],
+        validator() {
+          if (variables.model.projectParameterName === '') {
+            return new Error(t('project.parameter.name_tips'))
+          }
+        }
+      },
+      value: {
+        required: true,
+        trigger: ['input', 'blur'],
+        validator() {
+          if (variables.model.projectParameterValue === '') {
+            return new Error(t('project.parameter.value_tips'))
+          }
+        }
+      }
+    }
+  })
+
+  const handleValidate = async (statusRef: number) => {
+    // await variables.formRef.validate()
+
+    if (variables.saving) return
+    variables.saving = true
+
+    try {
+      statusRef === 0 ? await submitModal() : await updateModal()
+      variables.saving = false
+    } catch (err) {
+      variables.saving = false
+    }
+  }
+
+  const submitModal = () => {
+    const data: ProjectParameterReq = {
+      projectParameterName: variables.model.projectParameterName,
+      projectParameterValue: variables.model.projectParameterValue
+    }
+
+    createProjectParameter(data, variables.projectCode).then(() => {
+      variables.model.projectParameterName = ''
+      variables.model.projectParameterValue = ''
+      ctx.emit('confirmModal', props.showModalRef)
+    })
+  }
+
+  const updateModal = () => {
+    const data: UpdateProjectParameterReq = {
+      code: variables.model.code,
+      projectParameterName: variables.model.projectParameterName,
+      projectParameterValue: variables.model.projectParameterValue
+    }
+
+    updateProjectParameter(data, variables.projectCode).then(() => {
+      ctx.emit('confirmModal', props.showModalRef)
+    })
+  }
+
+  return {
+    variables,
+    handleValidate
+  }
+}
diff --git a/dolphinscheduler-ui/src/views/projects/parameter/index.tsx 
b/dolphinscheduler-ui/src/views/projects/parameter/index.tsx
new file mode 100644
index 0000000000..f8d0719f18
--- /dev/null
+++ b/dolphinscheduler-ui/src/views/projects/parameter/index.tsx
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+  NDataTable,
+  NIcon,
+  NInput,
+  NPagination,
+  NSpace,
+  NButton
+} from 'naive-ui'
+import { defineComponent, onMounted, toRefs, watch } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useTable } from '@/views/projects/parameter/use-table'
+import Card from '@/components/card'
+import ParameterModal from 
'@/views/projects/parameter/components/parameter-modal'
+import { SearchOutlined } from '@vicons/antd'
+
+export default defineComponent({
+  name: 'ProjectParameterList',
+  setup() {
+    const { variables, createColumns, getTableData } = useTable()
+
+    const requestData = () => {
+      getTableData({
+        pageSize: variables.pageSize,
+        pageNo: variables.page,
+        searchVal: variables.searchVal,
+        projectCode: variables.projectCode
+      })
+    }
+
+    const handleUpdateList = () => {
+      requestData()
+    }
+
+    const handleSearch = () => {
+      variables.page = 1
+      requestData()
+    }
+
+    const handleChangePageSize = () => {
+      variables.page = 1
+      requestData()
+    }
+
+    const onCancelModal = () => {
+      variables.showRef = false
+    }
+
+    const onConfirmModal = () => {
+      variables.showRef = false
+      requestData()
+    }
+
+    const onCreateParameter = () => {
+      variables.showRef = true
+      variables.statusRef = 0
+    }
+
+    onMounted(() => {
+      createColumns(variables)
+      requestData()
+    })
+
+    watch(useI18n().locale, () => {
+      createColumns(variables)
+    })
+
+    return {
+      requestData,
+      handleSearch,
+      handleUpdateList,
+      handleChangePageSize,
+      onCreateParameter,
+      onCancelModal,
+      onConfirmModal,
+      ...toRefs(variables)
+    }
+  },
+  render() {
+    const { t } = useI18n()
+    const {
+      loadingRef,
+      handleSearch,
+      onCreateParameter,
+      onConfirmModal,
+      onCancelModal
+    } = this
+
+    return (
+      <NSpace vertical>
+        <Card>
+          <NSpace justify='space-between'>
+            <NButton size='small' type='primary' onClick={onCreateParameter}>
+              {t('project.parameter.create_parameter')}
+            </NButton>
+            <NSpace>
+              <NInput
+                size='small'
+                clearable
+                v-model={[this.searchVal, 'value']}
+                placeholder={t('project.parameter.name')}
+              />
+              <NButton size='small' type='primary' onClick={handleSearch}>
+                <NIcon>
+                  <SearchOutlined />
+                </NIcon>
+              </NButton>
+            </NSpace>
+          </NSpace>
+        </Card>
+        <Card title={t('project.parameter.parameter_manage')}>
+          <NSpace vertical>
+            <NDataTable
+              loading={loadingRef}
+              columns={this.columns}
+              data={this.tableData}
+              striped
+              size={'small'}
+              scrollX={this.tableWidth}
+            />
+            <NSpace justify='center'>
+              <NPagination
+                v-model:page={this.page}
+                v-model:page-size={this.pageSize}
+                page-count={this.totalPage}
+                show-size-picker
+                page-sizes={[10, 30, 50]}
+                show-quick-jumper
+                onUpdatePage={this.requestData}
+                onUpdatePageSize={this.handleChangePageSize}
+              />
+            </NSpace>
+          </NSpace>
+        </Card>
+        <ParameterModal
+          showModalRef={this.showRef}
+          statusRef={this.statusRef}
+          row={this.row}
+          onCancelModal={onCancelModal}
+          onConfirmModal={onConfirmModal}
+        />
+      </NSpace>
+    )
+  }
+})
diff --git a/dolphinscheduler-ui/src/views/projects/parameter/use-table.ts 
b/dolphinscheduler-ui/src/views/projects/parameter/use-table.ts
new file mode 100644
index 0000000000..e0d4b940cf
--- /dev/null
+++ b/dolphinscheduler-ui/src/views/projects/parameter/use-table.ts
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { h, ref, reactive } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useRouter } from 'vue-router'
+import { NSpace, NTooltip, NButton, NPopconfirm } from 'naive-ui'
+import {
+  deleteProjectParameterByCode,
+  queryProjectParameterListPaging
+} from '@/service/modules/projects-parameter'
+import { ProjectParameterCodeReq } from 
'@/service/modules/projects-parameter/types'
+import { DeleteOutlined, EditOutlined } from '@vicons/antd'
+import {
+  COLUMN_WIDTH_CONFIG,
+  calculateTableWidth,
+  DefaultTableWidth
+} from '@/common/column-width-config'
+import type { Router } from 'vue-router'
+
+export function useTable() {
+  const { t } = useI18n()
+  const router: Router = useRouter()
+
+  const variables = reactive({
+    columns: [],
+    tableWidth: DefaultTableWidth,
+    row: {},
+    tableData: [],
+    projectCode: ref(Number(router.currentRoute.value.params.projectCode)),
+    page: ref(1),
+    pageSize: ref(10),
+    searchVal: ref(),
+    totalPage: ref(1),
+    showRef: ref(false),
+    statusRef: ref(0),
+    loadingRef: ref(false)
+  })
+
+  const createColumns = (variables: any) => {
+    variables.columns = [
+      {
+        title: '#',
+        key: 'id',
+        ...COLUMN_WIDTH_CONFIG['index'],
+        render: (row: any, index: number) => index + 1
+      },
+      {
+        title: t('project.parameter.name'),
+        key: 'paramName',
+        ...COLUMN_WIDTH_CONFIG['name']
+      },
+      {
+        title: t('project.parameter.value'),
+        key: 'paramValue',
+        ...COLUMN_WIDTH_CONFIG['name']
+      },
+      {
+        title: t('project.parameter.create_time'),
+        key: 'createTime',
+        ...COLUMN_WIDTH_CONFIG['time']
+      },
+      {
+        title: t('project.parameter.update_time'),
+        key: 'updateTime',
+        ...COLUMN_WIDTH_CONFIG['time']
+      },
+      {
+        title: t('project.parameter.operation'),
+        key: 'operation',
+        ...COLUMN_WIDTH_CONFIG['operation'](3),
+        render: (row: any) => {
+          return h(NSpace, null, {
+            default: () => [
+              h(
+                NTooltip,
+                {},
+                {
+                  trigger: () =>
+                    h(
+                      NButton,
+                      {
+                        circle: true,
+                        type: 'info',
+                        size: 'small',
+                        onClick: () => {
+                          handleEdit(row)
+                        }
+                      },
+                      {
+                        icon: () => h(EditOutlined)
+                      }
+                    ),
+                  default: () => t('project.parameter.edit')
+                }
+              ),
+              h(
+                NPopconfirm,
+                {
+                  onPositiveClick: () => {
+                    handleDelete(row.code)
+                  }
+                },
+                {
+                  trigger: () =>
+                    h(
+                      NTooltip,
+                      {},
+                      {
+                        trigger: () =>
+                          h(
+                            NButton,
+                            {
+                              circle: true,
+                              type: 'error',
+                              size: 'small'
+                            },
+                            {
+                              icon: () => h(DeleteOutlined)
+                            }
+                          ),
+                        default: () => t('project.parameter.delete')
+                      }
+                    ),
+                  default: () => t('project.parameter.delete_confirm')
+                }
+              )
+            ]
+          })
+        }
+      }
+    ]
+    if (variables.tableWidth) {
+      variables.tableWidth = calculateTableWidth(variables.columns)
+    }
+  }
+
+  const handleEdit = (row: any) => {
+    variables.showRef = true
+    variables.statusRef = 1
+    variables.row = row
+  }
+
+  const getTableData = (params: any) => {
+    if (variables.loadingRef) return
+    variables.loadingRef = true
+
+    queryProjectParameterListPaging({ ...params }, variables.projectCode).then(
+      (res: any) => {
+        variables.totalPage = res.totalPage
+        variables.tableData = res.totalList.map((item: any) => {
+          return { ...item }
+        })
+        variables.loadingRef = false
+      }
+    )
+  }
+
+  const handleDelete = (code: number) => {
+    if (variables.tableData.length === 1 && variables.page > 1) {
+      variables.page -= 1
+    }
+    const data: ProjectParameterCodeReq = {
+      code: code
+    }
+    deleteProjectParameterByCode(data, variables.projectCode).then(() => {
+      window.$message.success(t('project.parameter.success'))
+      getTableData({
+        pageSize: variables.pageSize,
+        pageNo: variables.page,
+        searchVal: variables.searchVal
+      })
+    })
+  }
+
+  return {
+    variables,
+    createColumns,
+    getTableData
+  }
+}

Reply via email to