You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampark.apache.org by be...@apache.org on 2022/10/30 14:58:40 UTC

[incubator-streampark] branch dev updated: [Fix] fix application create bug and add variable preview (#1927)

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

benjobs pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git


The following commit(s) were added to refs/heads/dev by this push:
     new 2dcd42f70 [Fix] fix application create bug and add variable preview (#1927)
2dcd42f70 is described below

commit 2dcd42f706173948565f1ec81861660beab4a569
Author: Sizhu Wang <39...@users.noreply.github.com>
AuthorDate: Sun Oct 30 22:58:35 2022 +0800

    [Fix] fix application create bug and add variable preview (#1927)
---
 .../src/api/flink/app/app.ts                       |   6 +-
 .../src/api/flink/app/app.type.ts                  |  28 ++++
 .../src/api/system/variable.ts                     |  20 ++-
 .../src/components/Description/src/Description.vue |   2 +-
 .../src/components/Form/src/BasicForm.vue          |   3 +-
 .../components/Form/src/components/FormAction.tsx  | 158 ++++++++++++++++++
 .../components/Form/src/components/FormItem.vue    |  13 +-
 .../src/components/Form/src/hooks/useFormValues.ts |   2 +-
 .../src/components/Form/src/props.ts               |   1 +
 .../src/components/Form/src/types/form.ts          |   9 +-
 .../src/components/Modal/src/index.less            |  11 +-
 .../src/components/Table/src/BasicTable.vue        |   1 +
 .../streampark-console-newui/src/design/index.less |   2 +-
 .../src/design/public.less                         |   5 +
 .../src/hooks/web/useMonaco.ts                     |  88 +++++++++-
 .../src/hooks/web/usePage.ts                       |   4 +-
 .../src/hooks/web/usePermission.ts                 |  31 +++-
 .../src/router/guard/permissionGuard.ts            |   2 +-
 .../src/settings/componentSetting.ts               |   2 +-
 .../src/settings/projectSetting.ts                 |   2 +-
 .../src/store/modules/multipleTab.ts               |   1 -
 .../src/store/modules/permission.ts                |  42 ++++-
 .../src/store/modules/user.ts                      |   9 +-
 .../streampark-console-newui/src/utils/cipher.ts   |   1 -
 .../src/views/base/login/Login.vue                 |   4 +-
 .../src/views/flink/app/Add.vue                    |  82 +++++----
 .../src/views/flink/app/EditFlink.vue              |  86 +++++-----
 .../src/views/flink/app/EditStreamPark.vue         | 142 ++++++++++------
 .../{FlinkSqlFormatter.ts => FlinkSqlFormatter.js} |   4 +-
 .../src/views/flink/app/View.vue                   |  47 ++----
 .../src/views/flink/app/components/AppConf.tsx     |   8 +-
 .../flink/app/components/AppDetail/DetailTab.vue   |  38 +++--
 .../components/AppView/StartApplicationModal.vue   |   8 +-
 .../components/AppView/StopApplicationModal.vue    |   6 +-
 .../src/views/flink/app/components/Dependency.vue  | 112 ++++++++++++-
 .../src/views/flink/app/components/ProgramArgs.vue |  70 ++++++++
 .../views/flink/app/components/UploadJobJar.vue    |  49 +++---
 .../views/flink/app/components/VariableReview.vue  |  60 +++++++
 .../src/views/flink/app/components/customForm.tsx  |   9 +-
 .../src/views/flink/app/components/flinkSql.vue    |  39 +++--
 .../src/views/flink/app/data/index.ts              |   3 +-
 .../src/views/flink/app/hooks/useAppTable.ts       | 128 --------------
 .../src/views/flink/app/hooks/useAppTableAction.ts |  16 +-
 .../flink/app/hooks/useCreateAndEditSchema.ts      | 183 ++++++++++++---------
 .../src/views/flink/app/hooks/useCreateSchema.ts   |  77 ++++-----
 .../src/views/flink/app/hooks/useEdit.ts           |  39 +++--
 .../views/flink/app/hooks/useEditFlinkSchema.ts    |  33 ++--
 .../src/views/flink/app/hooks/useEditStreamPark.ts |  23 +--
 .../src/views/flink/app/hooks/useFlinkRender.tsx   |  85 +++++++---
 .../src/views/flink/app/hooks/useFlinkSchema.ts    |  32 ++--
 .../src/views/flink/app/styles/Add.less            |  21 ++-
 .../src/views/flink/app/utils/index.ts             |  18 +-
 .../flink/setting/components/AlertDetailModal.vue  | 136 +++++++++++++++
 .../views/flink/setting/components/AlertModal.vue  |   3 +-
 .../flink/setting/components/AlertSetting.vue      |  19 ++-
 .../flink/setting/components/AlertTypeInfo.vue     |  21 +--
 .../flink/setting/components/FlinkEnvModal.vue     |   4 +-
 .../views/flink/setting/hooks/useClusterSetting.ts |  11 +-
 .../src/views/system/variable/DependApps.vue       |  21 ++-
 .../src/views/system/variable/View.vue             |   1 +
 .../system/variable/components/VariableDrawer.vue  |   5 +-
 .../system/variable/components/VariableInfo.vue    |   8 +
 62 files changed, 1423 insertions(+), 671 deletions(-)

diff --git a/streampark-console/streampark-console-newui/src/api/flink/app/app.ts b/streampark-console/streampark-console-newui/src/api/flink/app/app.ts
index a9fed61c4..f4ec9c276 100644
--- a/streampark-console/streampark-console-newui/src/api/flink/app/app.ts
+++ b/streampark-console/streampark-console-newui/src/api/flink/app/app.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import { AxiosResponse } from 'axios';
-import { AppListResponse, CancelParam, DashboardResponse } from './app.type';
+import { AppListResponse, CancelParam, CreateParams, DashboardResponse } from './app.type';
 import { Result } from '/#/axios';
 import { ContentTypeEnum } from '/@/enums/httpEnum';
 import { defHttp } from '/@/utils/http/axios';
@@ -128,7 +128,7 @@ export function fetchUpload(params) {
  * @param params Create parameters
  * @returns {Promise<AxiosResponse<Result>>} Whether the data creation was successful message: error message
  */
-export function fetchCreate(data): Promise<AxiosResponse<Result>> {
+export function fetchCreate(data: CreateParams): Promise<AxiosResponse<Result>> {
   return defHttp.post({ url: APP_API.CREATE, data }, { isReturnNativeResponse: true });
 }
 /**
@@ -223,6 +223,6 @@ export function fetchCancel(data: CancelParam): Promise<boolean> {
   return defHttp.post({ url: APP_API.CANCEL, data });
 }
 
-export function fetchName(data) {
+export function fetchName(data: { config: string }) {
   return defHttp.post({ url: APP_API.NAME, data });
 }
diff --git a/streampark-console/streampark-console-newui/src/api/flink/app/app.type.ts b/streampark-console/streampark-console-newui/src/api/flink/app/app.type.ts
index 126179344..21daac8dc 100644
--- a/streampark-console/streampark-console-newui/src/api/flink/app/app.type.ts
+++ b/streampark-console/streampark-console-newui/src/api/flink/app/app.type.ts
@@ -152,3 +152,31 @@ export interface CancelParam {
   drain: boolean;
   savePoint: string;
 }
+// create Params
+export interface CreateParams {
+  jobType: number;
+  executionMode: number;
+  versionId: string;
+  flinkSql: string;
+  appType: number;
+  config?: any;
+  format?: any;
+  jobName: string;
+  tags: string;
+  args?: any;
+  dependency: string;
+  options: string;
+  cpMaxFailureInterval: number;
+  cpFailureRateInterval: number;
+  cpFailureAction: number;
+  properties: string;
+  resolveOrder: number;
+  restartSize: number;
+  alertId: string;
+  description: string;
+  k8sNamespace?: any;
+  clusterId: string;
+  flinkClusterId: string;
+  flinkImage?: any;
+  yarnSessionClusterId?: any;
+}
diff --git a/streampark-console/streampark-console-newui/src/api/system/variable.ts b/streampark-console/streampark-console-newui/src/api/system/variable.ts
index 25e247f4e..77e2a5c54 100644
--- a/streampark-console/streampark-console-newui/src/api/system/variable.ts
+++ b/streampark-console/streampark-console-newui/src/api/system/variable.ts
@@ -28,6 +28,7 @@ enum VARIABLE_API {
   DELETE = '/variable/delete',
   SELECT = '/variable/select',
   CHECK_CODE = '/variable/check/code',
+  ALL = '/variable/all',
 }
 /**
  * get variable list
@@ -76,10 +77,25 @@ export function fetchCheckVariableCode(data: {
 }
 
 /**
- * Code check
+ * search depend app
  * @param {Object} data
- * @returns {Promise<AxiosResponse<Result>>}
+ * @returns {Promise<any>}
  */
 export function fetchDependApps(data: Recordable): Promise<any> {
   return defHttp.post({ url: VARIABLE_API.DEPEND, data });
 }
+/**
+ * Code check
+ * @param {Object} data
+ * @returns {Promise<any>}
+ */
+export function fetchVariableContent(data: Recordable): Promise<any> {
+  return defHttp.post({ url: VARIABLE_API.DEPEND, data });
+}
+/**
+ * get all variable
+ * @returns {Promise<any>}
+ */
+export function fetchVariableAll(data?: { key: string }): Promise<VariableListRecord[]> {
+  return defHttp.post({ url: VARIABLE_API.ALL, data });
+}
diff --git a/streampark-console/streampark-console-newui/src/components/Description/src/Description.vue b/streampark-console/streampark-console-newui/src/components/Description/src/Description.vue
index 65ffa5207..3843bef3b 100644
--- a/streampark-console/streampark-console-newui/src/components/Description/src/Description.vue
+++ b/streampark-console/streampark-console-newui/src/components/Description/src/Description.vue
@@ -33,7 +33,7 @@
     title: { type: String, default: '' },
     size: {
       type: String,
-      validator: (v) => ['small', 'default', 'middle', undefined].includes(v),
+      validator: (v: string) => ['small', 'default', 'middle', undefined].includes(v),
       default: 'small',
     },
     bordered: { type: Boolean, default: true },
diff --git a/streampark-console/streampark-console-newui/src/components/Form/src/BasicForm.vue b/streampark-console/streampark-console-newui/src/components/Form/src/BasicForm.vue
index 79f86a7f3..ea6738e76 100644
--- a/streampark-console/streampark-console-newui/src/components/Form/src/BasicForm.vue
+++ b/streampark-console/streampark-console-newui/src/components/Form/src/BasicForm.vue
@@ -60,7 +60,7 @@
   import { defineComponent, reactive, ref, computed, unref, onMounted, watch, nextTick } from 'vue';
   import { Form, Row } from 'ant-design-vue';
   import FormItem from './components/FormItem.vue';
-  import FormAction from './components/FormAction.vue';
+  import FormAction from './components/FormAction';
 
   import { dateItemType } from './helper';
   import { dateUtil } from '/@/utils/dateUtil';
@@ -106,6 +106,7 @@
 
       // Get the basic configuration of the form
       const getProps = computed((): FormProps => {
+        // @ts-ignore
         return { ...props, ...unref(propsRef) } as FormProps;
       });
 
diff --git a/streampark-console/streampark-console-newui/src/components/Form/src/components/FormAction.tsx b/streampark-console/streampark-console-newui/src/components/Form/src/components/FormAction.tsx
new file mode 100644
index 000000000..b6a01c868
--- /dev/null
+++ b/streampark-console/streampark-console-newui/src/components/Form/src/components/FormAction.tsx
@@ -0,0 +1,158 @@
+/*
+ * 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
+ *
+ *    https://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 type { ColEx } from '../types/index';
+//import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
+import { defineComponent, computed, PropType } from 'vue';
+import { Form, Col } from 'ant-design-vue';
+import { Button, ButtonProps } from '/@/components/Button';
+import { BasicArrow } from '/@/components/Basic';
+import { useFormContext } from '../hooks/useFormContext';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { propTypes } from '/@/utils/propTypes';
+import { getSlot } from '/@/utils/helper/tsxHelper';
+
+type ButtonOptions = Partial<ButtonProps> & { text: string };
+
+export default defineComponent({
+  name: 'BasicFormAction',
+  components: {
+    FormItem: Form.Item,
+    Button,
+    BasicArrow,
+    // ClearOutlined,
+    // SearchOutlined,
+    [Col.name]: Col,
+  },
+  props: {
+    showActionButtonGroup: propTypes.bool.def(true),
+    showResetButton: propTypes.bool.def(true),
+    showSubmitButton: propTypes.bool.def(true),
+    showAdvancedButton: propTypes.bool.def(true),
+    submitBeforeReset: propTypes.bool.def(false),
+    resetButtonOptions: {
+      type: Object as PropType<ButtonOptions>,
+      default: () => ({}),
+    },
+    submitButtonOptions: {
+      type: Object as PropType<ButtonOptions>,
+      default: () => ({}),
+    },
+    actionColOptions: {
+      type: Object as PropType<Partial<ColEx>>,
+      default: () => ({}),
+    },
+    actionSpan: propTypes.number.def(6),
+    isAdvanced: propTypes.bool,
+    hideAdvanceBtn: propTypes.bool,
+  },
+  emits: ['toggle-advanced'],
+  setup(props, { slots, emit }) {
+    const { t } = useI18n();
+
+    const actionColOpt = computed(() => {
+      const { showAdvancedButton, actionSpan: span, actionColOptions } = props;
+      const actionSpan = 24 - span;
+      const advancedSpanObj = showAdvancedButton ? { span: actionSpan < 6 ? 24 : actionSpan } : {};
+      const actionColOpt: Partial<ColEx> = {
+        style: { textAlign: 'right' },
+        span: showAdvancedButton ? 6 : 4,
+        ...advancedSpanObj,
+        ...actionColOptions,
+      };
+      return actionColOpt;
+    });
+
+    const getResetBtnOptions = computed((): ButtonOptions => {
+      return Object.assign({ text: t('common.resetText') }, props.resetButtonOptions);
+    });
+
+    const getSubmitBtnOptions = computed(() => {
+      return Object.assign({ text: t('common.queryText') }, props.submitButtonOptions);
+    });
+
+    function toggleAdvanced() {
+      emit('toggle-advanced');
+    }
+    const { submitAction, resetAction } = useFormContext();
+    const renderResetButton = () => {
+      return (
+        <>
+          {getSlot(slots, 'resetBefore')}
+          <Button type="default" class="mr-2" {...getResetBtnOptions.value} onClick={resetAction}>
+            {getResetBtnOptions.value.text}
+          </Button>
+        </>
+      );
+    };
+    const renderSubmitButton = () => {
+      return (
+        <>
+          {getSlot(slots, 'submitBefore')}
+          <Button type="primary" class="mr-2" {...getSubmitBtnOptions.value} onClick={submitAction}>
+            {getSubmitBtnOptions.value.text}
+          </Button>
+        </>
+      );
+    };
+
+    function renderAdvanceButton() {
+      return (
+        <>
+          {getSlot(slots, 'advanceBefore')}
+          <Button type="link" size="small" class="mr-2" onClick={toggleAdvanced}>
+            {props.isAdvanced ? t('component.form.putAway') : t('component.form.unfold')}
+          </Button>
+          {getSlot(slots, 'advanceAfter')}
+        </>
+      );
+    }
+
+    function getAdvanceGroup() {
+      if (props.submitBeforeReset) {
+        return (
+          <>
+            {props.showSubmitButton && renderSubmitButton()}
+            {props.showResetButton && renderResetButton()}
+          </>
+        );
+      } else {
+        return (
+          <>
+            {props.showResetButton && renderResetButton()}
+            {props.showSubmitButton && renderSubmitButton()}
+          </>
+        );
+      }
+    }
+    return () => {
+      if (props.showActionButtonGroup) {
+        return (
+          <Col {...actionColOpt.value}>
+            <div class="w-full" style={{ textAlign: actionColOpt.value.style.textAlign }}>
+              <Form.Item>
+                {getAdvanceGroup()}
+                {props.showAdvancedButton && !props.hideAdvanceBtn && renderAdvanceButton()}
+              </Form.Item>
+            </div>
+          </Col>
+        );
+      } else {
+        return <div></div>;
+      }
+    };
+  },
+});
diff --git a/streampark-console/streampark-console-newui/src/components/Form/src/components/FormItem.vue b/streampark-console/streampark-console-newui/src/components/Form/src/components/FormItem.vue
index f9fc5cc8c..ec851bb8a 100644
--- a/streampark-console/streampark-console-newui/src/components/Form/src/components/FormItem.vue
+++ b/streampark-console/streampark-console-newui/src/components/Form/src/components/FormItem.vue
@@ -333,7 +333,8 @@
       }
 
       function renderItem() {
-        const { itemProps, slot, render, field, suffix, itemExtra, component } = props.schema;
+        const { itemProps, slot, render, field, suffix, beforeItem, afterItem, component } =
+          props.schema;
         const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
         const { colon } = props.formProps;
 
@@ -353,9 +354,11 @@
           };
 
           const showSuffix = !!suffix;
-          const showItemExtra = !!itemExtra;
+          const showBeforeItem = !!beforeItem;
+          const showAfterItem = !!afterItem;
           const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
-          const getItemExtra = isFunction(itemExtra) ? itemExtra(unref(getValues)) : itemExtra;
+          const getBeforeItem = isFunction(beforeItem) ? beforeItem(unref(getValues)) : beforeItem;
+          const getAfterItem = isFunction(afterItem) ? afterItem(unref(getValues)) : afterItem;
 
           return (
             <Form.Item
@@ -368,11 +371,12 @@
               labelCol={labelCol}
               wrapperCol={wrapperCol}
             >
+              {showBeforeItem && <div class="extra">{getBeforeItem}</div>}
               <div style="display:flex">
                 <div style="flex:1;">{getContent()}</div>
                 {showSuffix && <span class="suffix">{getSuffix}</span>}
               </div>
-              {showItemExtra && <div class="extra">{getItemExtra}</div>}
+              {showAfterItem && <div class="extra">{getAfterItem}</div>}
             </Form.Item>
           );
         }
@@ -388,7 +392,6 @@
         const realColProps = { ...baseColProps, ...colProps };
         const { isIfShow, isShow } = getShow();
         const values = unref(getValues);
-
         const getContent = () => {
           return colSlot
             ? getSlot(slots, colSlot, values)
diff --git a/streampark-console/streampark-console-newui/src/components/Form/src/hooks/useFormValues.ts b/streampark-console/streampark-console-newui/src/components/Form/src/hooks/useFormValues.ts
index 294dca0a1..92dbf5999 100644
--- a/streampark-console/streampark-console-newui/src/components/Form/src/hooks/useFormValues.ts
+++ b/streampark-console/streampark-console-newui/src/components/Form/src/hooks/useFormValues.ts
@@ -91,7 +91,7 @@ export function useFormValues({
         value = value.map((item) => transformDateFunc?.(item));
       }
       // Remove spaces
-      if (isString(value)) {
+      if (isString(value) && !['configOverride', 'flinkSql'].includes(key)) {
         value = value.trim();
       }
       if (!tryDeconstructArray(key, value, res) && !tryDeconstructObject(key, value, res)) {
diff --git a/streampark-console/streampark-console-newui/src/components/Form/src/props.ts b/streampark-console/streampark-console-newui/src/components/Form/src/props.ts
index 89aab7e07..7e1d63b98 100644
--- a/streampark-console/streampark-console-newui/src/components/Form/src/props.ts
+++ b/streampark-console/streampark-console-newui/src/components/Form/src/props.ts
@@ -57,6 +57,7 @@ export const basicProps = {
   autoSubmitOnEnter: propTypes.bool.def(false),
   submitOnReset: propTypes.bool,
   submitOnChange: propTypes.bool,
+  submitBeforeReset: propTypes.bool,
   size: propTypes.oneOf(['default', 'small', 'large']).def('default'),
   // Disable the form
   disabled: propTypes.bool,
diff --git a/streampark-console/streampark-console-newui/src/components/Form/src/types/form.ts b/streampark-console/streampark-console-newui/src/components/Form/src/types/form.ts
index e3e93b7d8..84dc981ae 100644
--- a/streampark-console/streampark-console-newui/src/components/Form/src/types/form.ts
+++ b/streampark-console/streampark-console-newui/src/components/Form/src/types/form.ts
@@ -178,7 +178,14 @@ export interface FormSchema {
 
   suffix?: string | number | ((values: RenderCallbackParams) => string | number);
 
-  itemExtra?:
+  beforeItem?:
+    | string
+    | number
+    | VNode
+    | VNode[]
+    | ((values: RenderCallbackParams) => VNode | VNode[] | string | number);
+
+  afterItem?:
     | string
     | number
     | VNode
diff --git a/streampark-console/streampark-console-newui/src/components/Modal/src/index.less b/streampark-console/streampark-console-newui/src/components/Modal/src/index.less
index d0220950d..2fbb39088 100644
--- a/streampark-console/streampark-console-newui/src/components/Modal/src/index.less
+++ b/streampark-console/streampark-console-newui/src/components/Modal/src/index.less
@@ -93,7 +93,16 @@
   &-confirm-body {
     .ant-modal-confirm-content {
       // color: #fff;
-      margin-top: 30px;
+      margin-top: 12px;
+      padding-bottom: 12px;
+
+      &::before {
+        content: "";
+        position: absolute;
+        left: 0;
+        right: 0;
+        border-top: 1px solid #f0f0f0;
+      }
 
       > * {
         color: @text-color-help-dark;
diff --git a/streampark-console/streampark-console-newui/src/components/Table/src/BasicTable.vue b/streampark-console/streampark-console-newui/src/components/Table/src/BasicTable.vue
index 9b73475fc..a75ab62eb 100644
--- a/streampark-console/streampark-console-newui/src/components/Table/src/BasicTable.vue
+++ b/streampark-console/streampark-console-newui/src/components/Table/src/BasicTable.vue
@@ -19,6 +19,7 @@
     <BasicForm
       ref="formRef"
       submitOnReset
+      submitBeforeReset
       v-bind="getFormProps"
       v-if="getBindValues.useSearchForm"
       :tableAction="tableAction"
diff --git a/streampark-console/streampark-console-newui/src/design/index.less b/streampark-console/streampark-console-newui/src/design/index.less
index 8ad3862aa..38f10a0c6 100644
--- a/streampark-console/streampark-console-newui/src/design/index.less
+++ b/streampark-console/streampark-console-newui/src/design/index.less
@@ -23,7 +23,7 @@
 @import "./swal2.less";
 
 input:-webkit-autofill {
-  box-shadow: 0 0 0 1000px white inset !important;
+  box-shadow: 0 0 0 1000px transparent inset !important;
 }
 
 [data-theme="dark"] input:-webkit-autofill {
diff --git a/streampark-console/streampark-console-newui/src/design/public.less b/streampark-console/streampark-console-newui/src/design/public.less
index 6268fac5b..af007f3db 100644
--- a/streampark-console/streampark-console-newui/src/design/public.less
+++ b/streampark-console/streampark-console-newui/src/design/public.less
@@ -65,3 +65,8 @@
     opacity: 0.75;
   }
 }
+
+.extra .conf-switch {
+  color: darkgrey;
+  margin-left: 5px;
+}
diff --git a/streampark-console/streampark-console-newui/src/hooks/web/useMonaco.ts b/streampark-console/streampark-console-newui/src/hooks/web/useMonaco.ts
index 29eb8cc1a..ea12e1d22 100644
--- a/streampark-console/streampark-console-newui/src/hooks/web/useMonaco.ts
+++ b/streampark-console/streampark-console-newui/src/hooks/web/useMonaco.ts
@@ -29,18 +29,26 @@ export const isDark = computed(() => getDarkMode.value === ThemeEnum.DARK);
 export interface MonacoEditorOption {
   code?: any;
   language: string;
+  suggestions?: any[];
   options?: Editor.IStandaloneEditorConstructionOptions;
 }
+export interface TextRange {
+  startLineNumber: number;
+  endLineNumber: number;
+  startColumn: number;
+  endColumn: number;
+}
 
 export function useMonaco(
   target: Ref,
   options: MonacoEditorOption,
-  beforeMount?: (monoao: any) => void,
+  beforeMount?: (monoao: any) => Promise<void>,
 ) {
   const changeEventHook = createEventHook<string>();
   const isSetup = ref(false);
   let editor: Editor.IStandaloneCodeEditor;
   let monacoInstance: any;
+  const registerCompletionMap = new Map();
 
   const setContent = async (content: string) => {
     await until(isSetup).toBeTruthy();
@@ -71,7 +79,75 @@ export function useMonaco(
       return null;
     }
   };
+  let suggestLabels: Array<Recordable> = [];
+  const createSuggestions = (
+    monaco: any,
+    range: TextRange,
+    preWord: string,
+    currentWord: string,
+  ) => {
+    const suggestions: Array<Recordable> = [];
+    for (let i = 0; i < suggestLabels.length; i++) {
+      const id = suggestLabels[i].text;
+      const desc = suggestLabels[i].description;
+      suggestions.push({
+        label: `${id}${desc ? ':' + desc : ''}`,
+        insertText: `${preWord !== '{' && currentWord !== '{' ? '{' : ''}${id}}`,
+        detail: 'Variable Code',
+        kind: monaco.languages.CompletionItemKind.Variable,
+        range,
+      });
+    }
+    return suggestions;
+  };
+
+  const registerCompletion = (monaco: any, languageId: string, callbackIds: any[]) => {
+    if (callbackIds && callbackIds.length > 0) {
+      suggestLabels = callbackIds;
+      if (registerCompletionMap.has(languageId)) {
+        return;
+      }
+      registerCompletionMap.set(languageId, 1);
+
+      monaco.languages.registerCompletionItemProvider(languageId, {
+        // triggerCharacters: ['${'],
+        triggerCharacters: ['$', '{'],
+        provideCompletionItems: async (model, position: Recordable) => {
+          const word = model.getWordUntilPosition(position);
+
+          // Gets the full contents of the current input line
+          const content = model.getLineContent(position.lineNumber);
 
+          // Pass the subscript to get the content after the current cursor, which is the previous character of the content just entered
+          const currentWord = content[position.column - 2];
+          const preWord = content[position.column - 3];
+          const lastWord = content[position.column - 4];
+          if (
+            currentWord === '$' ||
+            (currentWord === '{' && preWord == '$') ||
+            (preWord === '{' && lastWord === '$')
+          ) {
+            const range: TextRange = {
+              startLineNumber: position.lineNumber,
+              endLineNumber: position.lineNumber,
+              startColumn: word.startColumn,
+              endColumn: word.endColumn,
+            };
+            return {
+              suggestions: createSuggestions(monaco, range, preWord, currentWord),
+            };
+          } else {
+            return {
+              suggestions: [],
+            };
+          }
+        },
+        resolveCompletionItem: () => {
+          return [{ label: 'sss' }];
+        },
+      });
+    }
+  };
   const disposeInstance = async () => {
     editor?.dispose();
   };
@@ -80,6 +156,7 @@ export function useMonaco(
     const { monaco } = await setupMonaco();
     monacoInstance = monaco;
     if (isFunction(beforeMount)) await beforeMount(monaco);
+
     watch(
       target,
       () => {
@@ -87,6 +164,9 @@ export function useMonaco(
         if (!el) {
           return;
         }
+        if (options.suggestions && options.suggestions.length > 0) {
+          registerCompletion(monaco, options.language, options.suggestions);
+        }
         const model = monaco.editor.createModel(options.code, options.language);
         const defaultOptions = {
           model,
@@ -103,7 +183,6 @@ export function useMonaco(
           },
         };
         editor = monaco.editor.create(el, Object.assign(defaultOptions, options.options || {}));
-
         isSetup.value = true;
         if (!options.options?.theme) {
           watch(
@@ -129,7 +208,10 @@ export function useMonaco(
 
   init();
 
-  tryOnUnmounted(() => stop());
+  tryOnUnmounted(() => {
+    stop();
+    disposeInstance();
+  });
 
   return {
     onChange: changeEventHook.on,
diff --git a/streampark-console/streampark-console-newui/src/hooks/web/usePage.ts b/streampark-console/streampark-console-newui/src/hooks/web/usePage.ts
index de93ee2a0..c0094f23d 100644
--- a/streampark-console/streampark-console-newui/src/hooks/web/usePage.ts
+++ b/streampark-console/streampark-console-newui/src/hooks/web/usePage.ts
@@ -56,10 +56,10 @@ export const useRedo = (_router?: Router) => {
         return;
       }
       if (name && Object.keys(params).length > 0) {
-        params['_redirect_type'] = 'name';
+        // params['_redirect_type'] = 'name';
         params['path'] = String(name);
       } else {
-        params['_redirect_type'] = 'path';
+        // params['_redirect_type'] = 'path';
         params['path'] = fullPath;
       }
       push({ name: REDIRECT_NAME, params, query }).then(() => resolve(true));
diff --git a/streampark-console/streampark-console-newui/src/hooks/web/usePermission.ts b/streampark-console/streampark-console-newui/src/hooks/web/usePermission.ts
index 977b32320..74d173a69 100644
--- a/streampark-console/streampark-console-newui/src/hooks/web/usePermission.ts
+++ b/streampark-console/streampark-console-newui/src/hooks/web/usePermission.ts
@@ -20,7 +20,7 @@ import { useAppStore } from '/@/store/modules/app';
 import { usePermissionStore } from '/@/store/modules/permission';
 import { useUserStore } from '/@/store/modules/user';
 
-import { useTabs } from './useTabs';
+// import { useTabs } from './useTabs';
 
 import { router, resetRouter } from '/@/router';
 
@@ -31,13 +31,16 @@ import { RoleEnum } from '/@/enums/roleEnum';
 import { isArray } from '/@/utils/is';
 import { useMultipleTabStore } from '/@/store/modules/multipleTab';
 import { intersection } from 'lodash-es';
+import { PageEnum } from '/@/enums/pageEnum';
+import { useRedo } from './usePage';
+import { menuMap } from '/@/router/constant';
 
 // User permissions related operations
 export function usePermission() {
   const userStore = useUserStore();
   const appStore = useAppStore();
   const permissionStore = usePermissionStore();
-  const { closeAll } = useTabs(router);
+  // const { closeAll } = useTabs(router);
 
   /**
    * Change permission mode
@@ -56,16 +59,30 @@ export function usePermission() {
    * Reset and regain authority resource information
    * @param id
    */
-  async function resume() {
+  async function resume(nextPath?: string) {
     const tabStore = useMultipleTabStore();
     tabStore.clearCacheTabs();
+
+    const redo = useRedo(router);
+
     resetRouter();
-    const routes = await permissionStore.buildRoutesAction();
+    const [routes, hasAuth] = await permissionStore.buildRoutesAction(nextPath);
     routes.forEach((route) => {
       router.addRoute(route as unknown as RouteRecordRaw);
     });
     permissionStore.setLastBuildMenuTime();
-    closeAll();
+    const currentPath = router.currentRoute.value?.path;
+    if (Object.keys(menuMap).includes(currentPath)) {
+      router.replace(menuMap[currentPath]);
+    } else {
+      if (!hasAuth) {
+        router.push({ path: PageEnum.BASE_HOME });
+      } else {
+        await redo();
+      }
+    }
+
+    // closeAll();
   }
 
   /**
@@ -117,8 +134,8 @@ export function usePermission() {
   /**
    * refresh menu data
    */
-  async function refreshMenu() {
-    resume();
+  async function refreshMenu(nextPath?: string) {
+    resume(nextPath);
   }
 
   return { changeRole, hasPermission, togglePermissionMode, refreshMenu };
diff --git a/streampark-console/streampark-console-newui/src/router/guard/permissionGuard.ts b/streampark-console/streampark-console-newui/src/router/guard/permissionGuard.ts
index 4a931a342..a64680b0f 100644
--- a/streampark-console/streampark-console-newui/src/router/guard/permissionGuard.ts
+++ b/streampark-console/streampark-console-newui/src/router/guard/permissionGuard.ts
@@ -110,7 +110,7 @@ export function createPermissionGuard(router: Router) {
       return;
     }
 
-    const routes = await permissionStore.buildRoutesAction();
+    const [routes] = await permissionStore.buildRoutesAction();
 
     routes.forEach((route) => {
       router.addRoute(route as unknown as RouteRecordRaw);
diff --git a/streampark-console/streampark-console-newui/src/settings/componentSetting.ts b/streampark-console/streampark-console-newui/src/settings/componentSetting.ts
index 6084d2691..7aca104b2 100644
--- a/streampark-console/streampark-console-newui/src/settings/componentSetting.ts
+++ b/streampark-console/streampark-console-newui/src/settings/componentSetting.ts
@@ -25,7 +25,7 @@ export default {
     // support xxx.xxx.xxx
     fetchSetting: {
       // The field name of the current page passed to the background
-      pageField: 'page',
+      pageField: 'pageNum',
       // The number field name of each page displayed in the background
       sizeField: 'pageSize',
       // Field name of the form data returned by the interface
diff --git a/streampark-console/streampark-console-newui/src/settings/projectSetting.ts b/streampark-console/streampark-console-newui/src/settings/projectSetting.ts
index 7dd2a2936..1168270d0 100644
--- a/streampark-console/streampark-console-newui/src/settings/projectSetting.ts
+++ b/streampark-console/streampark-console-newui/src/settings/projectSetting.ts
@@ -160,7 +160,7 @@ const setting: ProjectConfig = {
 
     // Whether to open page switching loading
     // Only open when enable=true
-    openPageLoading: true,
+    openPageLoading: false,
 
     // Whether to open the top progress bar
     openNProgress: true,
diff --git a/streampark-console/streampark-console-newui/src/store/modules/multipleTab.ts b/streampark-console/streampark-console-newui/src/store/modules/multipleTab.ts
index fa3a130ab..75a55de83 100644
--- a/streampark-console/streampark-console-newui/src/store/modules/multipleTab.ts
+++ b/streampark-console/streampark-console-newui/src/store/modules/multipleTab.ts
@@ -120,7 +120,6 @@ export const useMultipleTabStore = defineStore({
       const go = useGo(router);
       const len = this.tabList.length;
       const { path } = unref(router.currentRoute);
-
       let toPath: PageEnum | string = PageEnum.BASE_HOME;
 
       if (len > 0) {
diff --git a/streampark-console/streampark-console-newui/src/store/modules/permission.ts b/streampark-console/streampark-console-newui/src/store/modules/permission.ts
index 19c7ddbd3..1c2c3b71e 100644
--- a/streampark-console/streampark-console-newui/src/store/modules/permission.ts
+++ b/streampark-console/streampark-console-newui/src/store/modules/permission.ts
@@ -122,12 +122,13 @@ export const usePermissionStore = defineStore({
     },
 
     // Build routing
-    async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
+    async buildRoutesAction(nextPath = ''): Promise<[AppRouteRecordRaw[], boolean]> {
       const { t } = useI18n();
       const userStore = useUserStore();
       const appStore = useAppStoreWithOut();
       // get teamList
       const { userId } = getAuthCache(USER_INFO_KEY) as UserInfo;
+      let hasAuth = false;
       if (userStore.teamList.length == 0 && userId) {
         const teamList = await fetchUserTeam({ userId });
         userStore.setTeamList(teamList.map((i) => ({ label: i.teamName, value: i.id })));
@@ -159,8 +160,7 @@ export const usePermissionStore = defineStore({
        * */
       const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
         if (!routes || routes.length === 0) return;
-        let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
-
+        let homePath: string = nextPath || userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
         function patcher(routes: AppRouteRecordRaw[], parentPath = '') {
           if (parentPath) parentPath = parentPath + '/';
           routes.forEach((route: AppRouteRecordRaw) => {
@@ -171,6 +171,7 @@ export const usePermissionStore = defineStore({
                 homePath = route.redirect! as string;
               } else {
                 route.meta = Object.assign({}, route.meta, { affix: true });
+                hasAuth = true;
                 throw new Error('end');
               }
             }
@@ -183,8 +184,39 @@ export const usePermissionStore = defineStore({
         } catch (e) {
           // Processed out of loop
         }
-        return;
+        return hasAuth;
       };
+      /**
+       * @description Fix the affix tag in routes according to the homepage path set (fixed homepage)
+       * */
+      // const checkCurrentRouter = (routes: AppRouteRecordRaw[]) => {
+      //   if (!routes || routes.length === 0) return;
+      //   let homePath: string = nextPath || userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
+
+      //   function patcher(routes: AppRouteRecordRaw[], parentPath = '') {
+      //     if (parentPath) parentPath = parentPath + '/';
+      //     routes.forEach((route: AppRouteRecordRaw) => {
+      //       const { path, children, redirect } = route;
+      //       const currentPath = path.startsWith('/') ? path : parentPath + path;
+      //       if (currentPath === homePath) {
+      //         if (redirect) {
+      //           homePath = route.redirect! as string;
+      //         } else {
+      //           route.meta = Object.assign({}, route.meta, { affix: true });
+      //           throw new Error('end');
+      //         }
+      //       }
+      //       children && children.length > 0 && patcher(children, currentPath);
+      //     });
+      //   }
+
+      //   try {
+      //     patcher(routes);
+      //   } catch (e) {
+      //     // Processed out of loop
+      //   }
+      //   return;
+      // };
 
       switch (permissionMode) {
         // Role authorization
@@ -273,7 +305,7 @@ export const usePermissionStore = defineStore({
 
       routes.push(ERROR_LOG_ROUTE);
       patchHomeAffix(routes);
-      return routes;
+      return [routes, hasAuth];
     },
   },
 });
diff --git a/streampark-console/streampark-console-newui/src/store/modules/user.ts b/streampark-console/streampark-console-newui/src/store/modules/user.ts
index cdb1dab57..2a6f3ed37 100644
--- a/streampark-console/streampark-console-newui/src/store/modules/user.ts
+++ b/streampark-console/streampark-console-newui/src/store/modules/user.ts
@@ -35,7 +35,7 @@ import { router } from '/@/router';
 import { usePermissionStore } from '/@/store/modules/permission';
 import { RouteRecordRaw } from 'vue-router';
 import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
-import { h } from 'vue';
+import { h, unref } from 'vue';
 import { getUserTeamId } from '/@/utils';
 import { usePermission } from '/@/hooks/web/usePermission';
 
@@ -166,8 +166,7 @@ export const useUserStore = defineStore({
         this.teamId = data.teamId;
         sessionStorage.setItem(APP_TEAMID_KEY_, data.teamId);
         localStorage.setItem(APP_TEAMID_KEY_, data.teamId);
-
-        if (!data.userId) refreshMenu();
+        if (!data.userId) refreshMenu(unref(router.currentRoute)?.path);
         return Promise.resolve(true);
       } catch (error) {
         return Promise.reject(error);
@@ -185,7 +184,7 @@ export const useUserStore = defineStore({
         try {
           const permissionStore = usePermissionStore();
           if (!permissionStore.isDynamicAddedRoute) {
-            const routes = await permissionStore.buildRoutesAction();
+            const [routes] = await permissionStore.buildRoutesAction();
             routes.forEach((route) => {
               router.addRoute(route as unknown as RouteRecordRaw);
             });
@@ -231,7 +230,7 @@ export const useUserStore = defineStore({
       createConfirm({
         iconType: 'warning',
         title: () => h('span', t('sys.app.logoutTip')),
-        content: () => h('span', t('sys.app.logoutMessage')),
+        content: () => h('span', { class: 'inline-block pt-20px' }, t('sys.app.logoutMessage')),
         onOk: async () => {
           await this.logout(true);
         },
diff --git a/streampark-console/streampark-console-newui/src/utils/cipher.ts b/streampark-console/streampark-console-newui/src/utils/cipher.ts
index b44958039..ab4cbd006 100644
--- a/streampark-console/streampark-console-newui/src/utils/cipher.ts
+++ b/streampark-console/streampark-console-newui/src/utils/cipher.ts
@@ -21,7 +21,6 @@ import ECB from 'crypto-js/mode-ecb';
 import md5 from 'crypto-js/md5';
 import UTF8 from 'crypto-js/enc-utf8';
 import Base64 from 'crypto-js/enc-base64';
-
 export interface EncryptionParams {
   key: string;
   iv: string;
diff --git a/streampark-console/streampark-console-newui/src/views/base/login/Login.vue b/streampark-console/streampark-console-newui/src/views/base/login/Login.vue
index 9295de01c..0b2ad2e3e 100644
--- a/streampark-console/streampark-console-newui/src/views/base/login/Login.vue
+++ b/streampark-console/streampark-console-newui/src/views/base/login/Login.vue
@@ -144,7 +144,9 @@
     input {
       min-width: 300px;
       background: transparent;
-
+      &:autofill {
+        background: transparent;
+      }
       @media (max-width: @screen-xl) {
         min-width: 260px;
       }
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/Add.vue b/streampark-console/streampark-console-newui/src/views/flink/app/Add.vue
index 92eaddc2c..07aa19f2f 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/Add.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/Add.vue
@@ -15,13 +15,13 @@
   limitations under the License.
 -->
 <script lang="ts">
-  import { defineComponent } from 'vue';
-  import { useGo } from '/@/hooks/web/usePage';
-  export default defineComponent({
+  export default {
     name: 'AppCreate',
-  });
+  };
 </script>
 <script setup lang="ts" name="AppCreate">
+  import { useGo } from '/@/hooks/web/usePage';
+  import ProgramArgs from './components/ProgramArgs.vue';
   import { Switch, Alert } from 'ant-design-vue';
   import { onMounted, reactive, ref, unref } from 'vue';
   import { PageWrapper } from '/@/components/Page';
@@ -32,7 +32,6 @@
   import { useDrawer } from '/@/components/Drawer';
   import Mergely from './components/Mergely.vue';
   import { handleConfTemplate } from '/@/api/flink/config';
-  import { decodeByBase64 } from '/@/utils/cipher';
   import UploadJobJar from './components/UploadJobJar.vue';
   import { fetchAppConf, fetchCreate, fetchMain, fetchUpload } from '/@/api/flink/app/app';
   import options from './data/option';
@@ -42,13 +41,25 @@
   import { createLocalStorage } from '/@/utils/cache';
   import { buildUUID } from '/@/utils/uuid';
   import { useI18n } from '/@/hooks/web/useI18n';
+  import VariableReview from './components/VariableReview.vue';
+  import { CreateParams } from '/@/api/flink/app/app.type';
+  import { decodeByBase64, encryptByBase64 } from '/@/utils/cipher';
 
-  const FlinkSqlEditor = createAsyncComponent(() => import('./components/flinkSql.vue'));
-  const Dependency = createAsyncComponent(() => import('./components/Dependency.vue'));
+  const FlinkSqlEditor = createAsyncComponent(() => import('./components/flinkSql.vue'), {
+    loading: true,
+  });
+  const Dependency = createAsyncComponent(() => import('./components/Dependency.vue'), {
+    loading: true,
+  });
   const PomTemplateTab = createAsyncComponent(
     () => import('./components/PodTemplate/PomTemplateTab.vue'),
+    {
+      loading: true,
+    },
   );
-  const UseSysHadoopConf = createAsyncComponent(() => import('./components/UseSysHadoopConf.vue'));
+  const UseSysHadoopConf = createAsyncComponent(() => import('./components/UseSysHadoopConf.vue'), {
+    loading: true,
+  });
 
   const go = useGo();
   const flinkSql = ref();
@@ -71,7 +82,9 @@
     tmPodTemplate: '',
   });
 
-  const { getCreateFormSchema, flinkEnvs, flinkClusters } = useCreateSchema(dependencyRef);
+  const { flinkEnvs, flinkClusters, getCreateFormSchema, suggestions } =
+    useCreateSchema(dependencyRef);
+
   const [registerAppForm, { setFieldsValue, getFieldsValue, submit }] = useForm({
     labelCol: { lg: { span: 5, offset: 0 }, sm: { span: 7, offset: 0 } },
     wrapperCol: { lg: { span: 16, offset: 0 }, sm: { span: 17, offset: 0 } },
@@ -81,6 +94,7 @@
   });
 
   const [registerConfDrawer, { openDrawer: openConfDrawer }] = useDrawer();
+  const [registerReviewDrawer, { openDrawer: openReviewDrawer }] = useDrawer();
 
   /* Initialize the form */
   async function handleInitForm() {
@@ -149,9 +163,9 @@
     const cluster =
       unref(flinkClusters).filter((c) => {
         if (values.flinkClusterId) {
-          return c.clusterId === values.flinkClusterId && c.clusterState === 1;
+          return c.id == values.flinkClusterId && c.clusterState === 1;
         } else {
-          return c.clusterId === values.yarnSessionClusterId && c.clusterState === 1;
+          return c.clusterId == values.yarnSessionClusterId && c.clusterState === 1;
         }
       })[0] || null;
     if (cluster) {
@@ -173,14 +187,13 @@
       appType: values.appType,
     };
     handleSubmitParams(params, values, k8sTemplate);
-
     // common params...
     const resourceFrom = values.resourceFrom;
     if (resourceFrom != null) {
-      if (resourceFrom === 'cvs') {
+      if (resourceFrom === 'csv') {
         params['resourceFrom'] = 1;
         //streampark flink
-        if (values.appType === 1) {
+        if (values.appType === '1') {
           const configVal = values['config'];
           params['format'] = configVal.endsWith('.properties') ? 2 : 1;
           if (values.configOverride == null) {
@@ -188,16 +201,14 @@
               config: configVal,
             });
             params['config'] = res;
-            handleCreateApp(params);
           } else {
             params['config'] = decodeByBase64(values.configOverride);
-            handleCreateApp(params);
           }
         } else {
           params['jar'] = values.jar || null;
           params['mainClass'] = values.mainClass || null;
-          handleCreateApp(params);
         }
+        handleCreateApp(params);
       } else {
         // from upload
         Object.assign(params, {
@@ -211,25 +222,27 @@
     }
   }
   /* flink sql mode */
-  function handleSubmitSQL(values) {
+  async function handleSubmitSQL(values) {
     // Trigger a pom confirmation operation.
-    unref(dependencyRef)?.handleApplyPom();
+    await unref(dependencyRef)?.handleApplyPom();
     // common params...
     const dependency: { pom?: string; jar?: string } = {};
-    if (values.dependency && values.dependency.length > 0) {
+    const dependencyRecords = unref(dependencyRef)?.dependencyRecords;
+    const uploadJars = unref(dependencyRef)?.uploadJars;
+    if (unref(dependencyRecords) && unref(dependencyRecords).length > 0) {
       Object.assign(dependency, {
-        pom: values.dependency,
+        pom: unref(dependencyRecords),
       });
     }
-    if (values.uploadJars && values.uploadJars.length > 0) {
+    if (uploadJars && unref(uploadJars).length > 0) {
       Object.assign(dependency, {
-        jar: values.dependency,
+        jar: unref(uploadJars),
       });
     }
 
     let config = values.configOverride;
     if (config != null && config !== undefined && config.trim() != '') {
-      config = decodeByBase64(config);
+      config = encryptByBase64(config);
     } else {
       config = null;
     }
@@ -239,7 +252,7 @@
       jobType: 2,
       flinkSql: values.flinkSql,
       appType: 1,
-      config: config,
+      config,
       format: values.isSetConfig ? 1 : null,
       dependency:
         dependency.pom === undefined && dependency.jar === undefined
@@ -250,14 +263,14 @@
     handleCreateApp(params);
   }
   /* Submit to create */
-  function handleAppCreate(formValue: Recordable) {
+  async function handleAppCreate(formValue: Recordable) {
     try {
       submitLoading.value = true;
       if (formValue.jobType === 'sql') {
         if (formValue.flinkSql == null || formValue.flinkSql.trim() === '') {
           createMessage.warning('Flink Sql is required');
         } else {
-          const access = flinkSql?.value?.handleVerifySql();
+          const access = await flinkSql?.value?.handleVerifySql();
           if (!access) return;
         }
       }
@@ -282,7 +295,8 @@
     const socketId = buildUUID();
     ls.set('DOWN_SOCKET_ID', socketId);
     Object.assign(param, { socketId });
-    const { data } = await fetchCreate(param);
+    console.log('param', param);
+    const { data } = await fetchCreate(param as CreateParams);
     if (data.data) {
       go('/flink/app');
     } else {
@@ -296,13 +310,15 @@
 </script>
 
 <template>
-  <PageWrapper contentFullHeight contentBackground contentClass="p-24px app_controller">
+  <PageWrapper contentFullHeight contentBackground contentClass="p-26px app_controller">
     <BasicForm @register="registerAppForm" @submit="handleAppCreate" :schemas="getCreateFormSchema">
       <template #flinkSql="{ model, field }">
         <FlinkSqlEditor
           ref="flinkSql"
           v-model:value="model[field]"
           :versionId="model['versionId']"
+          :suggestions="suggestions"
+          @preview="(value) => openReviewDrawer(true, { value, suggestions })"
         />
       </template>
       <template #dependency="{ model, field }">
@@ -343,6 +359,13 @@
           v-model:tmPodTemplate="k8sTemplate.tmPodTemplate"
         />
       </template>
+      <template #args="{ model }">
+        <ProgramArgs
+          v-model:value="model.args"
+          :suggestions="suggestions"
+          @preview="(value) => openReviewDrawer(true, { value, suggestions })"
+        />
+      </template>
       <template #useSysHadoopConf="{ model, field }">
         <UseSysHadoopConf v-model:hadoopConf="model[field]" />
       </template>
@@ -362,6 +385,7 @@
       @close="handleEditConfClose"
       @register="registerConfDrawer"
     />
+    <VariableReview @register="registerReviewDrawer" />
   </PageWrapper>
 </template>
 <style lang="less">
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/EditFlink.vue b/streampark-console/streampark-console-newui/src/views/flink/app/EditFlink.vue
index 3b724b191..95760064d 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/EditFlink.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/EditFlink.vue
@@ -15,17 +15,17 @@
   limitations under the License.
 -->
 <script lang="ts">
-  export default defineComponent({
+  export default {
     name: 'EditFlink',
-  });
+  };
 </script>
 <script setup lang="ts" name="EditFlink">
   import { PageWrapper } from '/@/components/Page';
   import { BasicForm, useForm } from '/@/components/Form';
-  import { onMounted, reactive, ref, nextTick, defineComponent, unref } from 'vue';
+  import { onMounted, reactive, ref, nextTick, unref } from 'vue';
   import { Alert } from 'ant-design-vue';
   import { fetchMain, fetchUpload, fetchUpdate } from '/@/api/flink/app/app';
-  import { handleFormValue, handleYarnQueue } from './utils';
+  import { handleSubmitParams } from './utils';
   import PomTemplateTab from './components/PodTemplate/PomTemplateTab.vue';
   import { fetchListJars } from '/@/api/flink/project';
   import { useEditFlinkSchema } from './hooks/useEditFlinkSchema';
@@ -34,6 +34,10 @@
   import { useI18n } from '/@/hooks/web/useI18n';
   import { useRoute } from 'vue-router';
   import { useGo } from '/@/hooks/web/usePage';
+  import UploadJobJar from './components/UploadJobJar.vue';
+  import ProgramArgs from './components/ProgramArgs.vue';
+  import VariableReview from './components/VariableReview.vue';
+  import { useDrawer } from '/@/components/Drawer';
 
   const route = useRoute();
   const { t } = useI18n();
@@ -45,6 +49,7 @@
 
   const uploadLoading = ref(false);
   const uploadJar = ref('');
+  const programArgRef = ref();
 
   const k8sTemplate = reactive({
     podTemplate: '',
@@ -52,8 +57,10 @@
     tmPodTemplate: '',
   });
 
-  const { getEditFlinkFormSchema, alerts } = useEditFlinkSchema(jars);
-  const { handleGetApplication, app, handleResetApplication, selectAlertId } = useEdit(alerts);
+  const [registerReviewDrawer, { openDrawer: openReviewDrawer }] = useDrawer();
+
+  const { getEditFlinkFormSchema, alerts, suggestions } = useEditFlinkSchema(jars);
+  const { handleGetApplication, app, handleResetApplication } = useEdit();
   const [registerForm, { setFieldsValue, submit }] = useForm({
     labelWidth: 120,
     colon: true,
@@ -66,12 +73,16 @@
   /* Form reset */
   function handleReset(executionMode?: string) {
     nextTick(async () => {
-      const resetParams = await handleResetApplication();
+      let selectAlertId: string | undefined;
+      if (app.alertId) {
+        selectAlertId = unref(alerts)?.filter((t) => t.id == app.alertId)[0]?.id;
+      }
+      const resetParams = handleResetApplication();
       const defaultParams = {
         jobName: app.jobName,
         tags: app.tags,
         mainClass: app.mainClass,
-        args: app.args,
+        args: app.args || '',
         jar: app.jar,
         description: app.description,
         properties: app.properties,
@@ -79,9 +90,11 @@
         executionMode: app.executionMode,
         yarnQueue: app.yarnQueue,
         restartSize: app.restartSize,
-        cpMaxFailureInterval: app.cpMaxFailureInterval,
-        cpFailureRateInterval: app.cpFailureRateInterval,
-        cpFailureAction: app.cpFailureAction,
+        checkPointFailure: {
+          cpMaxFailureInterval: app.cpMaxFailureInterval,
+          cpFailureRateInterval: app.cpFailureRateInterval,
+          cpFailureAction: app.cpFailureAction,
+        },
         versionId: app.versionId || null,
         k8sRestExposedType: app.k8sRestExposedType,
         clusterId: app.clusterId,
@@ -96,6 +109,7 @@
         Object.assign(defaultParams, { executionMode: app.executionMode });
       }
       setFieldsValue(defaultParams);
+      app.args && programArgRef.value?.setContent(app.args);
     });
   }
   /* Custom job upload */
@@ -121,42 +135,13 @@
   function handleAppUpdate(values) {
     submitLoading.value = true;
     try {
-      const options = handleFormValue(values);
       const params = {
         id: app.id,
-        jobName: values.jobName,
-        tags: values.tags,
-        resolveOrder: values.resolveOrder,
-        versionId: values.versionId,
-        executionMode: values.executionMode,
         jar: values.jar,
         mainClass: values.mainClass,
-        args: values.args,
-        options: JSON.stringify(options),
-        yarnQueue: handleYarnQueue(values),
-        cpMaxFailureInterval: values.cpMaxFailureInterval || null,
-        cpFailureRateInterval: values.cpFailureRateInterval || null,
-        cpFailureAction: values.cpFailureAction || null,
-        properties: values.properties,
-        restartSize: values.restartSize,
-        // alertEmail: values.alertEmail || null,
-        alertId: values.alertId,
-        description: values.description,
-        k8sRestExposedType: values.k8sRestExposedType,
-        k8sNamespace: values.k8sNamespace || null,
-        clusterId: values.clusterId || null,
-        flinkClusterId: values.flinkClusterId || null,
-        flinkImage: values.flinkImage || null,
-        resourceFrom: values.resourceFrom,
-        yarnSessionClusterId: values.yarnSessionClusterId || null,
       };
-      if (params.executionMode === 6) {
-        Object.assign(params, {
-          k8sPodTemplate: k8sTemplate.podTemplate,
-          k8sJmPodTemplate: k8sTemplate.jmPodTemplate,
-          k8sTmPodTemplate: k8sTemplate.tmPodTemplate,
-        });
-      }
+      handleSubmitParams(params, values, k8sTemplate);
+
       handleUpdateApp(params);
     } catch (error) {
       submitLoading.value = false;
@@ -180,7 +165,7 @@
     }
     const value = await handleGetApplication();
     setFieldsValue(value);
-    if (app.resourceFrom === 1) {
+    if (app.resourceFrom == 1) {
       jars.value = await fetchListJars({
         id: app.projectId,
         module: app.module,
@@ -190,7 +175,7 @@
   });
 </script>
 <template>
-  <PageWrapper contentBackground>
+  <PageWrapper contentBackground content-class="p-26px app_controller">
     <BasicForm @register="registerForm" @submit="handleAppUpdate" :schemas="getEditFlinkFormSchema">
       <template #podTemplate>
         <PomTemplateTab
@@ -199,6 +184,7 @@
           v-model:tmPodTemplate="k8sTemplate.tmPodTemplate"
         />
       </template>
+
       <template #uploadJobJar>
         <UploadJobJar :custom-request="handleCustomJobRequest" v-model:loading="uploadLoading">
           <template #uploadInfo>
@@ -212,6 +198,17 @@
           </template>
         </UploadJobJar>
       </template>
+
+      <template #args="{ model }">
+        <ProgramArgs
+          ref="programArgRef"
+          v-if="model.args != null && model.args != undefined"
+          v-model:value="model.args"
+          :suggestions="suggestions"
+          @preview="(value) => openReviewDrawer(true, { value, suggestions })"
+        />
+      </template>
+
       <template #formFooter>
         <div class="flex items-center w-full justify-center">
           <a-button @click="go('/flink/app')">
@@ -223,6 +220,7 @@
         </div>
       </template>
     </BasicForm>
+    <VariableReview @register="registerReviewDrawer" />
   </PageWrapper>
 </template>
 <style lang="less">
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/EditStreamPark.vue b/streampark-console/streampark-console-newui/src/views/flink/app/EditStreamPark.vue
index 75d93984d..568cb70d7 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/EditStreamPark.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/EditStreamPark.vue
@@ -15,21 +15,21 @@
   limitations under the License.
 -->
 <script lang="ts">
-  export default defineComponent({
+  export default {
     name: 'EditStreamPark',
-  });
+  };
 </script>
 <script setup lang="ts" name="EditStreamPark">
   import { PageWrapper } from '/@/components/Page';
   import { BasicForm, useForm } from '/@/components/Form';
-  import { onMounted, reactive, ref, nextTick, unref, defineComponent } from 'vue';
+  import { onMounted, reactive, ref, nextTick, unref } from 'vue';
   import { AppListRecord } from '/@/api/flink/app/app.type';
   import configOptions from './data/option';
   import { fetchMain, fetchUpload, fetchUpdate, fetchGet } from '/@/api/flink/app/app';
   import { useRoute } from 'vue-router';
   import { handleSubmitParams } from './utils';
   import { fetchFlinkHistory } from '/@/api/flink/app/flinkSql';
-  import { decodeByBase64 } from '/@/utils/cipher';
+  import { decodeByBase64, encryptByBase64 } from '/@/utils/cipher';
   import PomTemplateTab from './components/PodTemplate/PomTemplateTab.vue';
   import UploadJobJar from './components/UploadJobJar.vue';
   import FlinkSqlEditor from './components/flinkSql.vue';
@@ -46,13 +46,14 @@
   import { useEdit } from './hooks/useEdit';
   import { useI18n } from '/@/hooks/web/useI18n';
   import { useGo } from '/@/hooks/web/usePage';
+  import ProgramArgs from './components/ProgramArgs.vue';
+  import VariableReview from './components/VariableReview.vue';
 
   const route = useRoute();
   const go = useGo();
   const { t } = useI18n();
   const { createMessage } = useMessage();
   const app = reactive<Partial<AppListRecord>>({});
-  const selectAlertId = ref<string>('');
   const flinkSqlHistory = ref<any[]>([]);
   const submitLoading = ref<boolean>(false);
 
@@ -62,15 +63,23 @@
   const uploadJar = ref('');
   const flinkSql = ref();
   const dependencyRef = ref();
+  const programArgRef = ref();
 
   const k8sTemplate = reactive({
     podTemplate: '',
     jmPodTemplate: '',
     tmPodTemplate: '',
   });
+
   const { handleResetApplication, defaultOptions } = useEdit();
-  const { getEditStreamParkFormSchema, registerDifferentDrawer, alerts, flinkEnvs, flinkClusters } =
-    useEditStreamParkSchema(configVersions, flinkSqlHistory, dependencyRef);
+  const {
+    alerts,
+    flinkEnvs,
+    flinkClusters,
+    getEditStreamParkFormSchema,
+    registerDifferentDrawer,
+    suggestions,
+  } = useEditStreamParkSchema(configVersions, flinkSqlHistory, dependencyRef);
 
   const [registerForm, { setFieldsValue, getFieldsValue, submit }] = useForm({
     labelWidth: 120,
@@ -82,15 +91,20 @@
   });
 
   const [registerConfDrawer, { openDrawer: openConfDrawer }] = useDrawer();
+  const [registerReviewDrawer, { openDrawer: openReviewDrawer }] = useDrawer();
 
   /* Form reset */
   function handleReset(executionMode?: string) {
+    let selectAlertId = '';
+    if (app.alertId) {
+      selectAlertId = unref(alerts).filter((t) => t.id == app.alertId)[0]?.id;
+    }
     nextTick(() => {
       const resetParams = handleResetApplication();
       const defaultParams = {
         jobName: app.jobName,
         tags: app.tags,
-        args: app.args,
+        args: app.args || '',
         description: app.description,
         properties: app.properties,
         resolveOrder: app.resolveOrder,
@@ -99,9 +113,11 @@
         yarnQueue: app.yarnQueue,
         restartSize: app.restartSize,
         alertId: selectAlertId,
-        cpMaxFailureInterval: app.cpMaxFailureInterval,
-        cpFailureRateInterval: app.cpFailureRateInterval,
-        cpFailureAction: app.cpFailureAction,
+        checkPointFailure: {
+          cpMaxFailureInterval: app.cpMaxFailureInterval,
+          cpFailureRateInterval: app.cpFailureRateInterval,
+          cpFailureAction: app.cpFailureAction,
+        },
         clusterId: app.clusterId,
         flinkClusterId: app.flinkClusterId,
         flinkImage: app.flinkImage,
@@ -109,10 +125,12 @@
         yarnSessionClusterId: app.yarnSessionClusterId,
         ...resetParams,
       };
+      console.log('resetParams', resetParams);
       if (!executionMode) {
         Object.assign(defaultParams, { executionMode: app.executionMode });
       }
       setFieldsValue(defaultParams);
+      app.args && programArgRef.value?.setContent(app.args);
     });
   }
   /* Custom job upload */
@@ -123,9 +141,7 @@
       const path = await fetchUpload(formData);
       uploadLoading.value = false;
       uploadJar.value = data.file.name;
-      const res = await fetchMain({
-        jar: path,
-      });
+      const res = await fetchMain({ jar: path });
       setFieldsValue({ jar: uploadJar.value, mainClass: res });
     } catch (error) {
       console.error(error);
@@ -138,10 +154,10 @@
   async function handleAppUpdate(values) {
     try {
       submitLoading.value = true;
-      if (app.jobType === 1) {
+      if (app.jobType == 1) {
         handleSubmitCustomJob(values);
       } else {
-        if (app.jobType === 2) {
+        if (app.jobType == 2) {
           if (values.flinkSql == null || values.flinkSql.trim() === '') {
             createMessage.warning('Flink Sql is required');
           } else {
@@ -157,17 +173,23 @@
     }
   }
 
-  function handleSubmitSQL(values) {
+  function handleSubmitSQL(values: Recordable) {
     try {
       // Trigger a pom confirmation operation.
       unref(dependencyRef)?.handleApplyPom();
       // common params...
-      const dependency: { pom?: any; jar?: any } = {};
-      if (values.dependency !== null && values.dependency.length > 0) {
-        Object.assign(dependency, { pom: values.dependency });
+      const dependency: { pom?: string; jar?: string } = {};
+      const dependencyRecords = unref(dependencyRef)?.dependencyRecords;
+      const uploadJars = unref(dependencyRef)?.uploadJars;
+      if (unref(dependencyRecords) && unref(dependencyRecords).length > 0) {
+        Object.assign(dependency, {
+          pom: unref(dependencyRecords),
+        });
       }
-      if (values.uploadJars != null && values.uploadJars.length > 0) {
-        Object.assign(dependency, { jar: values.dependency });
+      if (uploadJars && unref(uploadJars).length > 0) {
+        Object.assign(dependency, {
+          jar: unref(uploadJars),
+        });
       }
       if (values.yarnSessionClusterId) {
         const cluster =
@@ -180,7 +202,7 @@
       }
       let config = values.configOverride;
       if (config != null && config.trim() !== '') {
-        config = decodeByBase64(config);
+        config = encryptByBase64(config);
       } else {
         config = null;
       }
@@ -205,10 +227,10 @@
   async function handleSubmitCustomJob(values: Recordable) {
     try {
       const format =
-        values.strategy === 1 ? app.format : values.config.endsWith('.properties') ? 2 : 1;
+        values.strategy == 1 ? app.format : (values.config || '').endsWith('.properties') ? 2 : 1;
       let config = values.configOverride || app.config;
       if (config != null && config.trim() !== '') {
-        config = decodeByBase64(config);
+        config = encryptByBase64(config);
       } else {
         config = null;
       }
@@ -221,11 +243,11 @@
         values.flinkClusterId = cluster.id;
         values.yarnSessionClusterId = cluster.clusterId;
       }
-      const configId = values.strategy === 1 ? app.configId : null;
+      const configId = values.strategy == 1 ? app.configId : null;
       const params = {
         id: app.id,
         format: format,
-        configId: configId,
+        configId,
         config,
       };
       handleSubmitParams(params, values, k8sTemplate);
@@ -255,38 +277,21 @@
     const appId = route.query.appId;
     const res = await fetchGet({ id: appId as string });
     let configId = '';
-    fetchConfHistory({ id: route.query.appId }).then((confVersion) => {
-      confVersion.forEach((value) => {
-        if (value.effective) {
-          configId = value.id;
-        }
-      });
-      configVersions.value = confVersion;
+    const confVersion = await fetchConfHistory({ id: route.query.appId });
+    confVersion.forEach((conf: Recordable) => {
+      if (conf.effective) {
+        configId = conf.id;
+      }
     });
-
+    configVersions.value = confVersion;
     Object.assign(app, res);
     Object.assign(defaultOptions, JSON.parse(app.options || '{}'));
-    setFieldsValue({
-      jobType: res.jobType,
-      executionMode: res.executionMode,
-      flinkSql: decodeByBase64(res.flinkSql),
-      dependency: res.dependency,
-      module: res.module,
-      configId,
-      sqlId: app.sqlId,
-      versionId: app.versionId,
-    });
-    nextTick(() => {
-      unref(flinkSql)?.setContent(decodeByBase64(res.flinkSql));
-    });
-    if (app.jobType === 2) {
+
+    if (app.jobType == 2) {
       fetchFlinkHistory({ id: appId }).then((res) => {
         flinkSqlHistory.value = res;
       });
     }
-    if (app.alertId) {
-      selectAlertId.value = unref(alerts).filter((t) => t.id == app.alertId)[0]?.id;
-    }
     let isSetConfig = false;
     let configOverride = '';
     if (app.config && app.config.trim() !== '') {
@@ -299,7 +304,26 @@
         [item.key]: item.defaultValue,
       });
     });
-    setFieldsValue(defaultFormValue);
+    setFieldsValue({
+      jobType: res.jobType,
+      executionMode: res.executionMode,
+      flinkSql: res.flinkSql ? decodeByBase64(res.flinkSql) : '',
+      dependency: '',
+      module: res.module,
+      configId,
+      sqlId: app.sqlId,
+      versionId: app.versionId,
+      projectName: app.projectName,
+      project: app.projectId,
+      ...defaultFormValue,
+    });
+    nextTick(() => {
+      unref(flinkSql)?.setContent(decodeByBase64(res.flinkSql));
+
+      setTimeout(() => {
+        unref(dependencyRef)?.setDefaultValue(JSON.parse(res.dependency || '{}'));
+      }, 1000);
+    });
     handleReset();
   }
 
@@ -338,6 +362,15 @@
           v-model:tmPodTemplate="k8sTemplate.tmPodTemplate"
         />
       </template>
+      <template #args="{ model }">
+        <ProgramArgs
+          ref="programArgRef"
+          v-if="model.args != null && model.args != undefined"
+          v-model:value="model.args"
+          :suggestions="suggestions"
+          @preview="(value) => openReviewDrawer(true, { value, suggestions })"
+        />
+      </template>
       <template #uploadJobJar>
         <UploadJobJar :custom-request="handleCustomJobRequest" v-model:loading="uploadLoading" />
       </template>
@@ -346,6 +379,8 @@
           ref="flinkSql"
           v-model:value="model[field]"
           :versionId="model['versionId']"
+          :suggestions="suggestions"
+          @preview="(value) => openReviewDrawer(true, { value, suggestions })"
         />
       </template>
       <template #dependency="{ model, field }">
@@ -383,6 +418,7 @@
       @register="registerConfDrawer"
     />
     <Different @register="registerDifferentDrawer" />
+    <VariableReview @register="registerReviewDrawer" />
   </PageWrapper>
 </template>
 <style lang="less">
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/FlinkSqlFormatter.ts b/streampark-console/streampark-console-newui/src/views/flink/app/FlinkSqlFormatter.js
similarity index 98%
rename from streampark-console/streampark-console-newui/src/views/flink/app/FlinkSqlFormatter.ts
rename to streampark-console/streampark-console-newui/src/views/flink/app/FlinkSqlFormatter.js
index bd5b77f89..9c00b6f6a 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/FlinkSqlFormatter.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/FlinkSqlFormatter.js
@@ -403,6 +403,6 @@ class FlinkSqlFormatter extends Formatter {
  *  @param {Object} cfg.params Collection of params for placeholder replacement
  * @return {String}
  */
-export const format = (query) => {
-  return (new FlinkSqlFormatter() as any).format(query);
+export const format = (query, config = {}) => {
+  return new FlinkSqlFormatter(config).format(query);
 };
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/View.vue b/streampark-console/streampark-console-newui/src/views/flink/app/View.vue
index 858dfbbb2..bb2faf41d 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/View.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/View.vue
@@ -15,9 +15,9 @@
   limitations under the License.
 -->
 <script lang="ts">
-  import { defineComponent, ref, unref, onUnmounted, watch } from 'vue';
-  import { useUserStore } from '/@/store/modules/user';
+  import { defineComponent, nextTick, ref, unref, onUnmounted } from 'vue';
   import { useAppTableAction } from './hooks/useAppTableAction';
+
   export default defineComponent({
     name: 'AppView',
   });
@@ -42,8 +42,6 @@
   import AppDashboard from './components/AppView/AppDashboard.vue';
   import State from './components/State';
 
-  const userStore = useUserStore();
-
   const optionApps = {
     starting: new Map(),
     stopping: new Map(),
@@ -51,10 +49,7 @@
   };
 
   const appDashboardRef = ref<any>();
-  const searchText = ref('');
-  const tags = ref(undefined);
-  const jobType = ref(undefined);
-  const userId = ref(undefined);
+
   const yarn = ref<Nullable<string>>(null);
 
   const [registerStartModal, { openModal: openStartModal }] = useModal();
@@ -72,12 +67,6 @@
         }
         delete params.state;
       }
-      Object.assign(params, {
-        jobName: searchText.value,
-        jobType: jobType.value,
-        userId: userId.value,
-        tags: tags.value,
-      });
       return params;
     },
     afterFetch: (dataSource) => {
@@ -128,22 +117,10 @@
     openStopModal,
     openLogModal,
     openBuildDrawer,
-    reload,
+    handlePageDataReload,
     optionApps,
   );
 
-  watch(
-    () => userStore.getTeamId,
-    async (val) => {
-      if (val) {
-        tags.value = undefined;
-        jobType.value = undefined;
-        userId.value = undefined;
-        reload();
-      }
-    },
-  );
-
   // build Detail
   function openBuildProgressDetailDrawer(app: AppListRecord) {
     openBuildDrawer(true, { appId: app.id });
@@ -168,10 +145,15 @@
     optionApps[data.type].set(data.key, data.value);
   }
 
-  const { start, stop } = useTimeoutFn(() => {
-    if (!getLoading()) {
+  function handlePageDataReload() {
+    nextTick(() => {
       appDashboardRef.value?.handleDashboard(false);
       reload({ polling: true });
+    });
+  }
+  const { start, stop } = useTimeoutFn(() => {
+    if (!getLoading()) {
+      handlePageDataReload();
     }
     start();
   }, 2000);
@@ -179,13 +161,6 @@
   onUnmounted(() => {
     stop();
   });
-
-  watch(
-    () => [tags.value, userId.value, jobType.value],
-    () => {
-      reload({ polling: true });
-    },
-  );
 </script>
 <template>
   <PageWrapper contentFullHeight>
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/AppConf.tsx b/streampark-console/streampark-console-newui/src/views/flink/app/components/AppConf.tsx
index ca1b18ae8..951b050b8 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/components/AppConf.tsx
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/AppConf.tsx
@@ -42,6 +42,7 @@ export default defineComponent({
   emit: ['openMergely'],
   setup(props, { emit }) {
     const { model } = toRefs(props);
+    if (!model.value.strategy) model.value.strategy = '1';
     async function handleChangeConfig(v: string) {
       const res = await fetchGetVer({ id: v });
       model.value.configId = res.id;
@@ -58,11 +59,13 @@ export default defineComponent({
       model.value.jobName = res;
       model.value.configOverride = decodeByBase64(resp);
     }
+    console.log('configId', props.model.project);
     return () => {
       return (
         <div>
           <Input.Group compact>
             <Select
+              class="mr-10px"
               style="width: 25%"
               value={unref(model).strategy}
               onChange={(value: any) => (model.value.strategy = value)}
@@ -71,11 +74,12 @@ export default defineComponent({
               <Select.Option value="2">reselect</Select.Option>
             </Select>
             {unref(model).strategy == 1 && (
-              <Form.Item style="width: calc(75% - 65px)">
+              <Form.Item style="width: calc(75% - 75px);margin-left:10px;">
                 <Select
                   class="!w-full"
                   onChange={(value: any) => handleChangeConfig(value)}
                   value={unref(model).configId}
+                  placeholder="please select tag"
                 >
                   {props.configVersions.map((ver) => {
                     return (
@@ -91,7 +95,7 @@ export default defineComponent({
                   class="!w-full"
                   dropdownStyle={{ maxHeight: '400px', overflow: 'auto' }}
                   api={fetchListConf}
-                  params={{ id: props.model.projectId, module: props.model.module }}
+                  params={{ id: props.model.project, module: props.model.module }}
                   placeholder="Please select config"
                   tree-default-expand-all
                   onChange={(value) => handleChangeNewConfig(value)}
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/AppDetail/DetailTab.vue b/streampark-console/streampark-console-newui/src/views/flink/app/components/AppDetail/DetailTab.vue
index 325385fb3..d1b300ced 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/components/AppDetail/DetailTab.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/AppDetail/DetailTab.vue
@@ -15,13 +15,15 @@
   limitations under the License.
 -->
 <script lang="ts">
-  import { defineComponent, ref, toRefs, watch } from 'vue';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  export default defineComponent({
+  export default {
     name: 'DetailTab',
-  });
+  };
 </script>
 <script setup lang="ts" name="DetailTab">
+  import { ref, toRefs, watch } from 'vue';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useDrawer } from '/@/components/Drawer';
+  import Mergely from '../Mergely.vue';
   import { Tabs, Descriptions, Tag } from 'ant-design-vue';
 
   import { useMonaco } from '/@/hooks/web/useMonaco';
@@ -36,7 +38,7 @@
   import { getMonacoOptions } from '../../data';
   import { handleView } from '../../utils';
   import { useRoute } from 'vue-router';
-  import { fetchListVer, fetchRemoveConf } from '/@/api/flink/config';
+  import { fetchGetVer, fetchListVer, fetchRemoveConf } from '/@/api/flink/config';
   import { fetchRemoveSavePoint, fetchSavePonitHistory } from '/@/api/flink/app/savepoint';
 
   import { fetchBackUps, fetchOptionLog } from '/@/api/flink/app/app';
@@ -96,6 +98,7 @@
 
   const [registerCompare, { openModal: openCompareModal }] = useModal();
   const [registerExecOption, { openModal: openExecOptionModal }] = useModal();
+  const [registerDetailDrawer, { openDrawer: openDetailDrawer }] = useDrawer();
 
   const [registerConfigTable, { getDataSource, reload: reloadConf }] = useTable({
     api: fetchListVer,
@@ -125,13 +128,13 @@
     return [
       {
         tooltip: { title: t('flink.app.detail.detailTab.configDetail') },
-        shape: 'circle',
+        type: 'link',
         icon: 'ant-design:eye-outlined',
         onClick: handleConfDetail.bind(null, record),
       },
       {
         tooltip: { title: t('flink.app.detail.compareConfig') },
-        shape: 'circle',
+        type: 'link',
         icon: 'ant-design:swap-outlined',
         onClick: handleCompare.bind(null, record),
         ifShow: getDataSource().length > 1,
@@ -142,14 +145,28 @@
           confirm: handleDeleteConf.bind(null, record),
         },
         auth: 'conf:delete',
-        shape: 'circle',
+        type: 'link',
         icon: 'ant-design:delete-outlined',
-        type: 'danger' as any,
+        color: 'error',
         ifShow: !record.effective,
       },
     ];
   }
-  function handleConfDetail() {}
+  async function handleConfDetail(record: Recordable) {
+    const hide = createMessage.loading('loading');
+    try {
+      const res = await fetchGetVer({
+        id: record.id,
+      });
+      openDetailDrawer(true, {
+        configOverride: decodeByBase64(res.content),
+      });
+    } catch (error: unknown) {
+      console.error(error);
+    } finally {
+      hide();
+    }
+  }
 
   /* delete configuration */
   async function handleDeleteConf(record) {
@@ -326,5 +343,6 @@
 
     <CompareModal @register="registerCompare" />
     <ExecOptionModal @register="registerExecOption" />
+    <Mergely :read-only="true" @register="registerDetailDrawer" />
   </div>
 </template>
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/AppView/StartApplicationModal.vue b/streampark-console/streampark-console-newui/src/views/flink/app/components/AppView/StartApplicationModal.vue
index 536af5c03..a5dfffa99 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/components/AppView/StartApplicationModal.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/AppView/StartApplicationModal.vue
@@ -61,7 +61,7 @@
           unCheckedChildren: 'OFF',
         },
         defaultValue: false,
-        itemExtra: h('span', { class: 'conf-switch' }, 'flame Graph support'),
+        afterItem: h('span', { class: 'conf-switch' }, 'flame Graph support'),
         ifShow: () => [5, 6].includes(receiveData.executionMode),
       },
       {
@@ -73,7 +73,7 @@
           unCheckedChildren: 'OFF',
         },
         defaultValue: true,
-        itemExtra: h(
+        afterItem: h(
           'span',
           { class: 'conf-switch' },
           'restore the application from savepoint or latest checkpoint',
@@ -86,7 +86,7 @@
           receiveData.historySavePoint && receiveData.historySavePoint.length > 0
             ? 'Select'
             : 'Input',
-        itemExtra: h(
+        afterItem: h(
           'span',
           { class: 'conf-switch' },
           'restore the application from savepoint or latest checkpoint',
@@ -103,7 +103,7 @@
           checkedChildren: 'ON',
           unCheckedChildren: 'OFF',
         },
-        itemExtra: h(
+        afterItem: h(
           'span',
           { class: 'conf-switch' },
           'restore the application from savepoint or latest checkpoint',
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/AppView/StopApplicationModal.vue b/streampark-console/streampark-console-newui/src/views/flink/app/components/AppView/StopApplicationModal.vue
index 27f8f264d..08c947d5a 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/components/AppView/StopApplicationModal.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/AppView/StopApplicationModal.vue
@@ -54,7 +54,7 @@
           unCheckedChildren: 'OFF',
         },
         defaultValue: true,
-        itemExtra: h('span', { class: 'conf-switch' }, 'trigger savePoint before taking cancel'),
+        afterItem: h('span', { class: 'conf-switch' }, 'trigger savePoint before taking cancel'),
       },
       {
         field: 'customSavepoint',
@@ -64,7 +64,7 @@
           placeholder: 'Entry the custom savepoint path',
           allowClear: true,
         },
-        itemExtra: h(
+        afterItem: h(
           'span',
           { class: 'conf-switch' },
           'restore the application from savepoint or latest checkpoint',
@@ -80,7 +80,7 @@
           unCheckedChildren: 'OFF',
         },
         defaultValue: false,
-        itemExtra: h('span', { class: 'conf-switch' }, 'Send max watermark before stopped'),
+        afterItem: h('span', { class: 'conf-switch' }, 'Send max watermark before stopped'),
       },
     ],
     colon: true,
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/Dependency.vue b/streampark-console/streampark-console-newui/src/views/flink/app/components/Dependency.vue
index 926f80877..4fce9bc0e 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/components/Dependency.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/Dependency.vue
@@ -17,6 +17,7 @@
 <script lang="ts">
   import { computed, defineComponent, onMounted, reactive, ref } from 'vue';
   import { useI18n } from '/@/hooks/web/useI18n';
+  import { toPomString } from '../utils/Pom';
 
   export default defineComponent({
     name: 'Dependency',
@@ -27,12 +28,19 @@
   import { getMonacoOptions } from '../data';
   import { Icon } from '/@/components/Icon';
   import { useMonaco } from '/@/hooks/web/useMonaco';
-  import { Select, Tabs } from 'ant-design-vue';
+  import { Select, Tabs, Alert, Tag, Space } from 'ant-design-vue';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { fetchUpload } from '/@/api/flink/app/app';
   import { fetchUploadJars } from '/@/api/flink/app/flinkHistory';
   import UploadJobJar from './UploadJobJar.vue';
 
+  interface DependencyType {
+    artifactId: string;
+    exclusions: string[];
+    groupId: string;
+    version: string;
+  }
+
   const TabPane = Tabs.TabPane;
   const SelectOption = Select.Option;
   const activeTab = ref('pom');
@@ -42,6 +50,7 @@
     pom: {},
   });
   const selectedHistoryUploadJars = ref<string[]>([]);
+  const dependencyRecords = ref<DependencyType[]>([]);
   const uploadJars = ref<string[]>([]);
   const loading = ref(false);
 
@@ -72,7 +81,7 @@
     },
   });
 
-  function handleApplyPom() {
+  async function handleApplyPom() {
     const versionId = props.formModel?.versionId;
     if (versionId == null) {
       Swal.fire('Failed', t('flink.app.dependencyError'), 'error');
@@ -109,7 +118,7 @@
               artifactId: artifactId,
               version: version,
             };
-            const pomExclusion = new Map();
+            const pomExclusion = {};
             if (exclusion != null) {
               const exclusions = exclusion.split('<exclusion>');
               exclusions.forEach((e) => {
@@ -117,10 +126,10 @@
                   const e_group = e.match(groupExp) ? groupExp.exec(e)![1].trim() : null;
                   const e_artifact = e.match(artifactExp) ? artifactExp.exec(e)![1].trim() : null;
                   const id = e_group + '_' + e_artifact;
-                  pomExclusion.set(id, {
+                  pomExclusion[id] = {
                     groupId: e_group,
                     artifactId: e_artifact,
-                  });
+                  };
                 }
               });
             }
@@ -136,6 +145,7 @@
       alertInvalidDependency(scalaVersion, invalidArtifact);
       return;
     }
+    handleUpdateDependency();
     setContent(defaultValue);
   }
 
@@ -163,6 +173,7 @@
   /* custom http  */
   async function handleCustomDepsRequest(data) {
     try {
+      loading.value = true;
       const formData = new FormData();
       formData.append('file', data.file);
       await fetchUpload(formData);
@@ -171,13 +182,27 @@
       Object.assign(props.formModel.historyjar, {
         [data.file.name]: data.file.name,
       });
+      dependency.jar[data.file.name] = data.file.name;
+      handleUpdateDependency();
     } catch (error) {
       console.error(error);
     } finally {
       loading.value = false;
     }
   }
-
+  // update the dependency list
+  function handleUpdateDependency() {
+    const deps: DependencyType[] = [];
+    const jars: string[] = [];
+    Object.keys(dependency.pom).forEach((v: string) => {
+      deps.push(dependency.pom[v]);
+    });
+    Object.keys(dependency.jar).forEach((v: string) => {
+      jars.push(v);
+    });
+    dependencyRecords.value = deps;
+    uploadJars.value = jars;
+  }
   /* load history config records */
   async function handleReloadHistoryUploads() {
     selectedHistoryUploadJars.value = [];
@@ -188,7 +213,35 @@
   const filteredHistoryUploadJarsOptions = computed(() => {
     return uploadJars.value.filter((o) => !Reflect.has(dependency.jar, o));
   });
+  function handleRemoveJar(jar: string) {
+    delete dependency.jar[jar];
+    selectedHistoryUploadJars.value.splice(selectedHistoryUploadJars.value.indexOf(jar), 1);
+    handleUpdateDependency();
+  }
+  function handleRemovePom(pom: Recordable) {
+    const id = pom.groupId + '_' + pom.artifactId;
+    delete dependency.pom[id];
+    handleUpdateDependency();
+  }
 
+  function handleEditPom(pom: DependencyType) {
+    const pomString = toPomString(pom);
+    activeTab.value = 'pom';
+    setContent(pomString);
+  }
+  // set default value
+  function setDefaultValue(dataSource: { pom?: DependencyType[]; jar?: string[] }) {
+    console.log('dataSource', dataSource);
+    dependencyRecords.value = dataSource.pom || [];
+    uploadJars.value = dataSource.jar || [];
+    dataSource.pom?.map((pomRecord: DependencyType) => {
+      const id = pomRecord.groupId + '_' + pomRecord.artifactId;
+      dependency.pom[id] = pomRecord;
+    });
+    dataSource.jar?.map((fileName: string) => {
+      dependency.jar[fileName] = fileName;
+    });
+  }
   onMounted(() => {
     handleReloadHistoryUploads();
   });
@@ -196,9 +249,13 @@
   onChange((data) => {
     emit('update:value', data);
   });
+
   defineExpose({
-    handleApplyPom,
+    setDefaultValue,
     dependency,
+    handleApplyPom,
+    dependencyRecords,
+    uploadJars,
   });
 </script>
 
@@ -231,4 +288,45 @@
       <UploadJobJar :custom-request="handleCustomDepsRequest" v-model:loading="loading" />
     </TabPane>
   </Tabs>
+  <div class="dependency-box" v-if="dependencyRecords.length > 0 || uploadJars.length > 0">
+    <Alert
+      class="dependency-item"
+      v-for="(value, index) in dependencyRecords"
+      :key="`dependency_${index}`"
+      type="info"
+      @click="handleEditPom(value)"
+    >
+      <template #message>
+        <Space @click="handleEditPom(value)" class="tag-dependency-pom">
+          <Tag class="tag-dependency" color="#2db7f5">POM</Tag>
+          {{ value.artifactId }}-{{ value.version }}.jar
+          <Icon
+            :size="12"
+            icon="ant-design:close-outlined"
+            class="icon-close cursor-pointer"
+            @click.stop="handleRemovePom(value)"
+          />
+        </Space>
+      </template>
+    </Alert>
+    <Alert
+      class="dependency-item"
+      v-for="(value, index) in uploadJars"
+      :key="`upload_jars_${index}`"
+      type="info"
+    >
+      <template #message>
+        <Space>
+          <Tag class="tag-dependency" color="#108ee9">JAR</Tag>
+          {{ value }}
+          <Icon
+            icon="ant-design:close-outlined"
+            class="icon-close cursor-pointer"
+            :size="12"
+            @click="handleRemoveJar(value)"
+          />
+        </Space>
+      </template>
+    </Alert>
+  </div>
 </template>
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/ProgramArgs.vue b/streampark-console/streampark-console-newui/src/views/flink/app/components/ProgramArgs.vue
new file mode 100644
index 000000000..99dff4994
--- /dev/null
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/ProgramArgs.vue
@@ -0,0 +1,70 @@
+<!--
+  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
+
+      https://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.
+-->
+<template>
+  <div ref="programArgRef" class="w-full border mt-5px" style="height: 120px"> </div>
+  <div class="relative flinksql-tool">
+    <a-button
+      class="flinksql-tool-item"
+      v-if="canReview"
+      @click="emit('preview', value)"
+      size="small"
+    >
+      <Icon icon="ant-design:eye-outlined" />
+      preview
+    </a-button>
+  </div>
+</template>
+<script lang="ts">
+  export default defineComponent({
+    name: 'ProgramArg',
+  });
+</script>
+<script lang="ts" setup>
+  import { defineComponent, computed, ref, toRefs } from 'vue';
+  import { getMonacoOptions } from '../data';
+  import Icon from '/@/components/Icon';
+  import { useMonaco } from '/@/hooks/web/useMonaco';
+  const props = defineProps({
+    value: {
+      type: String,
+      required: true,
+    },
+    suggestions: {
+      type: Array as PropType<Array<{ text: string; description: string; value: string }>>,
+      default: () => [],
+    },
+  });
+  const { value, suggestions } = toRefs(props);
+  const emit = defineEmits(['update:value', 'preview']);
+  const programArgRef = ref();
+  const { onChange, setContent } = useMonaco(programArgRef, {
+    language: 'plaintext',
+    code: '',
+    suggestions: suggestions.value,
+    options: {
+      ...(getMonacoOptions(false) as any),
+      autoClosingBrackets: 'never',
+    },
+  });
+  const canReview = computed(() => {
+    return /\${.+}/.test(value.value);
+  });
+  onChange((data) => {
+    emit('update:value', data);
+  });
+  defineExpose({ setContent });
+</script>
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/UploadJobJar.vue b/streampark-console/streampark-console-newui/src/views/flink/app/components/UploadJobJar.vue
index ebb46f47c..75953452c 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/components/UploadJobJar.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/UploadJobJar.vue
@@ -15,10 +15,9 @@
   limitations under the License.
 -->
 <script lang="ts">
-  import { defineComponent } from 'vue';
-  export default defineComponent({
+  export default {
     name: 'UploadJobJar',
-  });
+  };
 </script>
 <script setup lang="ts" name="UploadJobJar">
   import { Upload } from 'ant-design-vue';
@@ -64,25 +63,27 @@
 </script>
 
 <template>
-  <UploadDragger
-    name="file"
-    :multiple="true"
-    @change="handleUploadJar"
-    :showUploadList="loading"
-    :customRequest="customRequest"
-    :beforeUpload="handleBeforeUpload"
-  >
-    <div class="h-266px">
-      <p class="ant-upload-drag-icon !pt-40px">
-        <Icon icon="ant-design:inbox-outlined" :style="{ fontSize: '70px' }" />
-      </p>
-      <p class="ant-upload-text h-45px">
-        {{ t('flink.app.dragUploadTitle') }}
-      </p>
-      <p class="ant-upload-hint h-45px">
-        {{ t('flink.app.dragUploadTip') }}
-      </p>
-    </div>
-  </UploadDragger>
-  <slot name="uploadInfo"></slot>
+  <div>
+    <UploadDragger
+      name="file"
+      :multiple="true"
+      @change="handleUploadJar"
+      :showUploadList="loading"
+      :customRequest="customRequest"
+      :beforeUpload="handleBeforeUpload"
+    >
+      <div class="h-266px">
+        <p class="ant-upload-drag-icon !pt-40px">
+          <Icon icon="ant-design:inbox-outlined" :style="{ fontSize: '70px' }" />
+        </p>
+        <p class="ant-upload-text h-45px">
+          {{ t('flink.app.dragUploadTitle') }}
+        </p>
+        <p class="ant-upload-hint h-45px">
+          {{ t('flink.app.dragUploadTip') }}
+        </p>
+      </div>
+    </UploadDragger>
+    <slot name="uploadInfo"></slot>
+  </div>
 </template>
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/VariableReview.vue b/streampark-console/streampark-console-newui/src/views/flink/app/components/VariableReview.vue
new file mode 100644
index 000000000..20782c9ac
--- /dev/null
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/VariableReview.vue
@@ -0,0 +1,60 @@
+<!--
+  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
+
+      https://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.
+-->
+<template>
+  <BasicDrawer
+    @register="registerDrawer"
+    :width="800"
+    placement="right"
+    :showOkBtn="false"
+    showFooter
+  >
+    <template #title>
+      <EyeOutlined style="color: green" />
+      Flink SQL preview
+    </template>
+    <div ref="flinkReviewRef" class="h-[calc(100vh-150px)] border"></div>
+  </BasicDrawer>
+</template>
+
+<script lang="ts" setup>
+  import { EyeOutlined } from '@ant-design/icons-vue';
+  import { ref } from 'vue';
+  import { getMonacoOptions } from '../data';
+  import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
+  import { useMonaco } from '/@/hooks/web/useMonaco';
+  const flinkReviewRef = ref();
+  const { setContent } = useMonaco(flinkReviewRef, {
+    language: 'sql',
+    code: '',
+    options: getMonacoOptions(true) as any,
+  });
+  const [registerDrawer] = useDrawerInner((data) => {
+    if (data) {
+      const suggestions = data.suggestions.reduce((pre: Recordable, cur: Recordable) => {
+        pre[cur.text] = cur.value;
+        return pre;
+      }, {});
+      console.log('suggestions', suggestions);
+      const content = data.value.replace(
+        /\${(.*?)}/g,
+        (node: string, $1: string) => suggestions[$1] || node,
+      );
+
+      setContent(content || '');
+    }
+  });
+</script>
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/customForm.tsx b/streampark-console/streampark-console-newui/src/views/flink/app/components/customForm.tsx
index b551b12ea..480b5b7f5 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/components/customForm.tsx
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/customForm.tsx
@@ -18,7 +18,7 @@ import { defineComponent } from 'vue';
 import type { PropType } from 'vue';
 import { Button, Form, Input, InputNumber, Tag, Select } from 'ant-design-vue';
 import Icon from '/@/components/Icon';
-interface PriceValue {
+export interface CheckPointFailure {
   cpMaxFailureInterval: number;
   cpFailureRateInterval: number;
   cpFailureAction: string;
@@ -26,12 +26,15 @@ interface PriceValue {
 import { cpTriggerAction } from '../data';
 export default defineComponent({
   props: {
-    value: { type: Object as PropType<PriceValue>, isRequired: true },
+    value: {
+      type: Object as PropType<CheckPointFailure>,
+      required: true,
+    },
   },
   emits: ['updateValue'],
   setup(props, { emit }) {
     const formItemContext = Form.useInjectFormItemContext();
-    const triggerChange = (changedValue: Partial<PriceValue>) => {
+    const triggerChange = (changedValue: Partial<CheckPointFailure>) => {
       emit('updateValue', { ...props.value, ...changedValue });
       formItemContext.onFieldChange();
     };
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/components/flinkSql.vue b/streampark-console/streampark-console-newui/src/views/flink/app/components/flinkSql.vue
index 89f1f4753..5fe73489e 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/components/flinkSql.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/components/flinkSql.vue
@@ -15,7 +15,13 @@
   limitations under the License.
 -->
 <script lang="ts">
-  import { defineComponent, reactive, ref, unref } from 'vue';
+  export default {
+    name: 'FlinkSql',
+  };
+</script>
+
+<script setup lang="ts" name="FlinkSql">
+  import { computed, reactive, ref, unref } from 'vue';
   import { getMonacoOptions } from '../data';
   import { Icon } from '/@/components/Icon';
   import { useMonaco } from '/@/hooks/web/useMonaco';
@@ -26,15 +32,7 @@
   import { format } from '../FlinkSqlFormatter';
   import { useFullscreen } from '@vueuse/core';
   import { useI18n } from '/@/hooks/web/useI18n';
-
   const ButtonGroup = Button.Group;
-
-  export default defineComponent({
-    name: 'FlinkSql',
-  });
-</script>
-
-<script setup lang="ts" name="FlinkSql">
   const { t } = useI18n();
   const vertifyRes = reactive({
     errorMsg: '',
@@ -45,8 +43,9 @@
   const flinkSql = ref();
   const flinkScreen = ref();
   const { isFullscreen, toggle } = useFullscreen(flinkScreen);
-  const emit = defineEmits(['update:value']);
+  const emit = defineEmits(['update:value', 'preview']);
   const { createMessage } = useMessage();
+
   const props = defineProps({
     value: {
       type: String,
@@ -55,6 +54,10 @@
     versionId: {
       type: String as PropType<Nullable<string>>,
     },
+    suggestions: {
+      type: Array as PropType<Array<{ text: string; description: string }>>,
+      default: () => [],
+    },
   });
   const defaultValue = '';
 
@@ -146,11 +149,16 @@
   const { onChange, setContent, getInstance, getMonacoInstance } = useMonaco(flinkSql, {
     language: 'sql',
     code: props.value || defaultValue,
+    suggestions: props.suggestions,
     options: {
       minimap: { enabled: true },
       ...(getMonacoOptions(false) as any),
+      autoClosingBrackets: 'never',
     },
   });
+  const canPreview = computed(() => {
+    return /\${.+}/.test(props.value);
+  });
 
   onChange((data) => {
     emit('update:value', data);
@@ -169,6 +177,15 @@
       ></div>
 
       <ButtonGroup class="flinksql-tool">
+        <a-button
+          class="flinksql-tool-item"
+          v-if="canPreview"
+          size="small"
+          @click="emit('preview', value)"
+        >
+          <Icon icon="ant-design:eye-outlined" />
+          preview
+        </a-button>
         <a-button class="flinksql-tool-item" type="primary" size="small" @click="handleVerifySql">
           <Icon icon="ant-design:check-outlined" />
           {{ t('flink.app.flinkSql.verify') }}
@@ -199,5 +216,3 @@
     </div>
   </div>
 </template>
-
-<style></style>
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/data/index.ts b/streampark-console/streampark-console-newui/src/views/flink/app/data/index.ts
index c1a6eaa07..9fe691425 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/data/index.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/data/index.ts
@@ -84,7 +84,8 @@ export const getMonacoOptions = (readOnly: boolean) => {
     selectOnLineNumbers: false,
     foldingStrategy: 'indentation', // code fragmentation
     overviewRulerBorder: false, // Don't scroll bar borders
-    autoClosingBrackets: true,
+    autoClosingBrackets: 'always',
+    autoClosingDelete: 'always',
     tabSize: 2, // tab indent length
     readOnly,
     inherit: true,
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useAppTable.ts b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useAppTable.ts
deleted file mode 100644
index 7cebb7e2a..000000000
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useAppTable.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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
- *
- *    https://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 { AppListRecord } from '/@/api/flink/app/app.type';
-import { ActionItem } from '/@/components/Table';
-
-export const useAppTable = () => {
-  /* Operation button */
-  function getTableActions(record: AppListRecord): ActionItem[] {
-    return [
-      {
-        tooltip: { title: 'Edit Application' },
-        auth: 'app:update',
-        icon: 'clarity:note-edit-line',
-        onClick: handleEdit.bind(null, record),
-      },
-      {
-        tooltip: { title: 'Launch Application' },
-        ifShow: [-1, 1, 4].includes(record.launch) && record['optionState'] === 0,
-        icon: 'ant-design:cloud-upload-outlined',
-        onClick: handleCheckLaunchApp.bind(null, record),
-      },
-      {
-        tooltip: { title: 'Launching Progress Detail' },
-        ifShow: [-1, 2].includes(record.launch) || record['optionState'] === 1,
-        auth: 'app:update',
-        icon: 'ant-design:container-outlined',
-        onClick: openBuildProgressDetailDrawer.bind(null, record),
-      },
-      {
-        tooltip: { title: 'Start Application' },
-        ifShow: handleIsStart(record, optionApps),
-        auth: 'app:start',
-        icon: 'ant-design:play-circle-outlined',
-        onClick: handleAppCheckStart.bind(null, record),
-      },
-      {
-        tooltip: { title: 'Cancel Application' },
-        ifShow: record.state === 5 && record['optionState'] === 0,
-        auth: 'app:cancel',
-        icon: 'ant-design:pause-circle-outlined',
-        onClick: handleCancel.bind(null, record),
-      },
-      {
-        tooltip: { title: 'View Application Detail' },
-        auth: 'app:detail',
-        icon: 'ant-design:eye-outlined',
-        onClick: handleDetail.bind(null, record),
-      },
-      {
-        tooltip: { title: 'See Flink Start log' },
-        ifShow: [5, 6].includes(record.executionMode),
-        auth: 'app:detail',
-        icon: 'ant-design:sync-outlined',
-        onClick: handleSeeLog.bind(null, record),
-      },
-      {
-        tooltip: { title: 'Forced Stop Application' },
-        ifShow: handleCanStop(record),
-        auth: 'app:cancel',
-        icon: 'ant-design:pause-circle-outlined',
-        onClick: handleForcedStop.bind(null, record),
-      },
-    ];
-  }
-  /* Click to edit */
-  function handleEdit(app: AppListRecord) {
-    flinkAppStore.setApplicationId(app.id);
-    if (app.appType === 1) {
-      // jobType( 1 custom code 2: flinkSQL)
-      router.push({ path: '/flink/app/edit_streampark', query: { appId: app.id } });
-    } else if (app.appType === 2) {
-      //Apache Flink
-      router.push({ path: '/flink/app/edit_flink' });
-    }
-  }
-  /* pull down button */
-  function getActionDropdown(record: AppListRecord): ActionItem[] {
-    return [
-      {
-        label: 'Copy Application',
-        auth: 'app:copy',
-        icon: 'ant-design:copy-outlined',
-        onClick: handleCopy.bind(null, record),
-      },
-      {
-        label: 'Remapping Application',
-        ifShow: [0, 7, 10, 11, 13].includes(record.state),
-        auth: 'app:mapping',
-        icon: 'ant-design:deployment-unit-outlined',
-        onClick: handleMapping.bind(null, record),
-      },
-      {
-        label: 'View FlameGraph',
-        ifShow: record.flameGraph,
-        auth: 'app:flameGraph',
-        icon: 'ant-design:fire-outlined',
-        onClick: handleFlameGraph.bind(null, record),
-      },
-      {
-        popConfirm: {
-          title: 'Are you sure delete this job ?',
-          confirm: handleDelete.bind(null, record),
-        },
-        label: 'Delete',
-        ifShow: [0, 7, 9, 10, 13, 18, 19].includes(record.state),
-        auth: 'app:delete',
-        icon: 'ant-design:delete-outlined',
-        color: 'error',
-      },
-    ];
-  }
-  return {};
-};
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useAppTableAction.ts b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useAppTableAction.ts
index 38ab6ba05..53091b507 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useAppTableAction.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useAppTableAction.ts
@@ -35,7 +35,7 @@ export const useAppTableAction = (
   openStopModal: Fn,
   openLogModal: Fn,
   openBuildDrawer: Fn,
-  reload: Fn,
+  handlePageDataReload: Fn,
   optionApps: Recordable,
 ) => {
   const tagsOptions = ref<Recordable>([]);
@@ -120,7 +120,7 @@ export const useAppTableAction = (
       router.push({ path: '/flink/app/edit_streampark', query: { appId: app.id } });
     } else if (app.appType === 2) {
       //Apache Flink
-      router.push({ path: '/flink/app/edit_flink' });
+      router.push({ path: '/flink/app/edit_flink', query: { appId: app.id } });
     }
   }
 
@@ -198,7 +198,7 @@ export const useAppTableAction = (
     try {
       await fetchAppRemove(app.id);
       createMessage.success('delete successful');
-      reload();
+      handlePageDataReload();
     } catch (error) {
       console.error(error);
     } finally {
@@ -229,6 +229,7 @@ export const useAppTableAction = (
             placeholder: 'Tags',
             showSearch: true,
             options: tagsOptions.value.map((t: Recordable) => ({ label: t, value: t })),
+            onChange: handlePageDataReload,
           },
         },
         {
@@ -241,6 +242,7 @@ export const useAppTableAction = (
             options: users.value.map((u: Recordable) => {
               return { label: u.nickName || u.username, value: u.userId };
             }),
+            onChange: handlePageDataReload,
           },
         },
         {
@@ -254,15 +256,17 @@ export const useAppTableAction = (
               { label: 'JAR', value: JobTypeEnum.JAR },
               { label: 'SQL', value: JobTypeEnum.SQL },
             ],
+            onChange: handlePageDataReload,
           },
         },
         {
-          label: 'keyWords',
-          field: 'searchText',
+          label: 'Name',
+          field: 'jobName',
           component: 'InputSearch',
           componentProps: {
             placeholder: 'Search',
-            onSearch: () => reload({ polling: true }),
+            onChange: handlePageDataReload,
+            onSearch: handlePageDataReload,
           },
         },
       ],
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useCreateAndEditSchema.ts b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useCreateAndEditSchema.ts
index 1fd185b05..d35e8c9b2 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useCreateAndEditSchema.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useCreateAndEditSchema.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import { FormSchema } from '/@/components/Table';
-import { computed, reactive, ref, unref, onMounted, h, Ref } from 'vue';
+import { computed, ref, unref, h, Ref, onMounted, reactive } from 'vue';
 import { k8sRestExposedType, resolveOrder } from '../data';
 import optionData from '../data/option';
 import {
@@ -27,47 +27,51 @@ import {
   renderOptionsItems,
   renderTotalMemory,
 } from './useFlinkRender';
-import { FlinkCluster } from '/@/api/flink/setting/types/flinkCluster.type';
 
+import { fetchCheckName } from '/@/api/flink/app/app';
+import { RuleObject } from 'ant-design-vue/lib/form';
+import { StoreValue } from 'ant-design-vue/lib/form/interface';
+import { useDrawer } from '/@/components/Drawer';
+import { Alert } from 'ant-design-vue';
+import Icon from '/@/components/Icon';
+import { useMessage } from '/@/hooks/web/useMessage';
+import { fetchVariableAll } from '/@/api/system/variable';
 import {
   fetchFlinkBaseImages,
   fetchK8sNamespaces,
   fetchSessionClusterIds,
 } from '/@/api/flink/app/flinkHistory';
-import { fetchCheckName } from '/@/api/flink/app/app';
-import { RuleObject } from 'ant-design-vue/lib/form';
-import { StoreValue } from 'ant-design-vue/lib/form/interface';
-import { AlertSetting } from '/@/api/flink/setting/types/alert.type';
+import { fetchSelect } from '/@/api/flink/project';
 import { fetchAlertSetting } from '/@/api/flink/setting/alert';
-import { useDrawer } from '/@/components/Drawer';
+import { fetchFlinkCluster } from '/@/api/flink/setting/flinkCluster';
 import { fetchFlinkEnv } from '/@/api/flink/setting/flinkEnv';
 import { FlinkEnv } from '/@/api/flink/setting/types/flinkEnv.type';
-import { fetchFlinkCluster } from '/@/api/flink/setting/flinkCluster';
-import { Alert } from 'ant-design-vue';
-import Icon from '/@/components/Icon';
-import { fetchSelect } from '/@/api/flink/project';
-import { useMessage } from '/@/hooks/web/useMessage';
+import { AlertSetting } from '/@/api/flink/setting/types/alert.type';
+import { FlinkCluster } from '/@/api/flink/setting/types/flinkCluster.type';
+export interface HistoryRecord {
+  k8sNamespace: Array<string>;
+  k8sSessionClusterId: Array<string>;
+  flinkImage: Array<string>;
+}
 
 export const useCreateAndEditSchema = (
   dependencyRef: Ref | null,
   edit?: { appId: string; mode: 'streampark' | 'flink' },
 ) => {
-  const { createErrorModal } = useMessage();
   const flinkEnvs = ref<FlinkEnv[]>([]);
   const alerts = ref<AlertSetting[]>([]);
   const flinkClusters = ref<FlinkCluster[]>([]);
   const projectList = ref<Array<any>>([]);
-  const scalaVersion = ref<string>();
-  const historyRecord = reactive<{
-    k8sNamespace: Array<string>;
-    k8sSessionClusterId: Array<string>;
-    flinkImage: Array<string>;
-  }>({
+  const historyRecord = reactive<HistoryRecord>({
     k8sNamespace: [],
     k8sSessionClusterId: [],
     flinkImage: [],
   });
 
+  const { createErrorModal } = useMessage();
+  let scalaVersion = '';
+  const suggestions = ref<Array<{ text: string; description: string; value: string }>>([]);
+
   const [registerConfDrawer, { openDrawer: openConfDrawer }] = useDrawer();
 
   /* 
@@ -123,6 +127,7 @@ export const useCreateAndEditSchema = (
           }
         },
       },
+      { field: 'configOverride', label: '', component: 'Input', show: false },
       {
         field: 'isSetConfig',
         label: 'Application Conf',
@@ -134,27 +139,28 @@ export const useCreateAndEditSchema = (
             return values?.jobType == 'sql' && ![5, 6].includes(values.executionMode);
           }
         },
-        render: ({ model, field }) =>
-          renderIsSetConfig(model, field, registerConfDrawer, openConfDrawer),
+        render({ model, field }) {
+          return renderIsSetConfig(model, field, registerConfDrawer, openConfDrawer);
+        },
       },
     ];
   });
 
   function handleFlinkVersion(id: number | string) {
     if (!dependencyRef) return;
-    scalaVersion.value = unref(flinkEnvs)?.find((v) => v.id === id)?.scalaVersion;
+    scalaVersion = unref(flinkEnvs)?.find((v) => v.id === id)?.scalaVersion || '';
     checkPomScalaVersion();
   }
 
   function checkPomScalaVersion() {
-    const pom = unref(dependencyRef)?.pom;
-    if (pom && pom.size > 0) {
+    const pom = unref(dependencyRef)?.dependencyRecords;
+    if (pom && pom.length > 0) {
       const invalidArtifact: Array<any> = [];
-      pom.forEach((v) => {
+      pom.forEach((v: Recordable) => {
         const artifactId = v.artifactId;
         if (/flink-(.*)_(.*)/.test(artifactId)) {
           const depScalaVersion = artifactId.substring(artifactId.lastIndexOf('_') + 1);
-          if (scalaVersion.value !== depScalaVersion) {
+          if (scalaVersion !== depScalaVersion) {
             invalidArtifact.push(artifactId);
           }
         }
@@ -165,7 +171,7 @@ export const useCreateAndEditSchema = (
     }
   }
 
-  function alertInvalidDependency(scalaVersion, invalidArtifact) {
+  function alertInvalidDependency(scalaVersion: string, invalidArtifact: string[]) {
     let depCode = '';
     invalidArtifact.forEach((dep) => {
       depCode += `<div style="font-size: 1rem;line-height: 1rem;padding-bottom: 0.3rem">${dep}</div>`;
@@ -230,7 +236,7 @@ export const useCreateAndEditSchema = (
         render: ({ model, field }) =>
           renderInputDropdown(model, field, {
             placeholder: 'default',
-            options: historyRecord.k8sNamespace,
+            options: unref(historyRecord)?.k8sNamespace || [],
           }),
       },
       {
@@ -266,7 +272,7 @@ export const useCreateAndEditSchema = (
           renderInputDropdown(model, field, {
             placeholder:
               'Please enter the tag of Flink base docker image, such as: flink:1.13.0-scala_2.11-java8',
-            options: historyRecord.k8sSessionClusterId,
+            options: unref(historyRecord)?.k8sSessionClusterId || [],
           }),
         rules: [{ required: true, message: 'Flink Base Docker Image is required' }],
       },
@@ -315,14 +321,17 @@ export const useCreateAndEditSchema = (
   }
 
   const getFlinkFormOtherSchemas = computed((): FormSchema[] => {
+    const commonInputNum = {
+      min: 1,
+      step: 1,
+      class: '!w-full',
+    };
     return [
       {
         field: 'jobName',
         label: 'Application Name',
         component: 'Input',
-        componentProps: {
-          placeholder: 'Please enter jobName',
-        },
+        componentProps: { placeholder: 'Please enter jobName' },
         dynamicRules: () => {
           return [{ required: true, trigger: 'blur', validator: getJobNameCheck }];
         },
@@ -348,21 +357,14 @@ export const useCreateAndEditSchema = (
         component: 'InputNumber',
         componentProps: {
           placeholder: 'The parallelism with which to run the program',
-          min: 1,
-          step: 1,
-          class: '!w-full',
+          ...commonInputNum,
         },
       },
       {
         field: 'slot',
         label: 'Task Slots',
         component: 'InputNumber',
-        componentProps: {
-          placeholder: 'Number of slots per TaskManager',
-          min: 1,
-          step: 1,
-          class: '!w-full',
-        },
+        componentProps: { placeholder: 'Number of slots per TaskManager', ...commonInputNum },
       },
       {
         field: 'restartSize',
@@ -370,18 +372,13 @@ export const useCreateAndEditSchema = (
         ifShow: ({ values }) =>
           edit?.mode == 'flink' ? true : ![5, 6].includes(values.executionMode),
         component: 'InputNumber',
-        componentProps: {
-          placeholder: 'restart max size',
-          min: 1,
-          step: 1,
-          class: '!w-full',
-        },
+        componentProps: { placeholder: 'restart max size', ...commonInputNum },
       },
       {
-        field: 'cpMaxFailureInterval',
+        field: 'checkPointFailure',
         label: 'CheckPoint Failure Options',
         component: 'InputNumber',
-        renderColContent: ({ model }) => renderInputGroup(model),
+        renderColContent: renderInputGroup,
         show: ({ values }) =>
           edit?.mode == 'flink' ? true : ![5, 6].includes(values.executionMode),
       },
@@ -400,13 +397,14 @@ export const useCreateAndEditSchema = (
         field: 'totalOptions',
         label: 'Total Memory Options',
         component: 'Select',
-        render: (renderCallbackParams) => renderTotalMemory(renderCallbackParams),
+        render: renderTotalMemory,
       },
       {
         field: 'totalItem',
         label: 'totalItem',
         component: 'Select',
-        renderColContent: ({ model }) => renderOptionsItems(model, 'totalOptions', '.memory'),
+        renderColContent: ({ model, field }) =>
+          renderOptionsItems(model, 'totalOptions', field, '.memory', true),
       },
       {
         field: 'jmOptions',
@@ -426,8 +424,8 @@ export const useCreateAndEditSchema = (
         field: 'jmOptionsItem',
         label: 'jmOptionsItem',
         component: 'Select',
-        renderColContent: ({ model }) =>
-          renderOptionsItems(model, 'jmOptions', 'jobmanager.memory.'),
+        renderColContent: ({ model, field }) =>
+          renderOptionsItems(model, 'jmOptions', field, 'jobmanager.memory.'),
       },
       {
         field: 'tmOptions',
@@ -447,16 +445,14 @@ export const useCreateAndEditSchema = (
         field: 'tmOptionsItem',
         label: 'tmOptionsItem',
         component: 'Select',
-        renderColContent: ({ model }) =>
-          renderOptionsItems(model, 'tmOptions', 'taskmanager.memory.'),
+        renderColContent: ({ model, field }) =>
+          renderOptionsItems(model, 'tmOptions', field, 'taskmanager.memory.'),
       },
       {
         field: 'yarnQueue',
         label: 'Yarn Queue',
         component: 'Input',
-        componentProps: {
-          placeholder: 'Please enter yarn queue',
-        },
+        componentProps: { placeholder: 'Please enter yarn queue' },
         ifShow: ({ values }) => values.executionMode == 4,
       },
       {
@@ -476,20 +472,15 @@ export const useCreateAndEditSchema = (
         field: 'args',
         label: 'Program Args',
         component: 'InputTextArea',
-        componentProps: {
-          rows: 4,
-          placeholder: '<arguments>',
-        },
+        defaultValue: '',
+        slot: 'args',
         ifShow: ({ values }) => (edit?.mode ? true : values.jobType == 'customcode'),
       },
       {
         field: 'description',
         label: 'Description',
         component: 'InputTextArea',
-        componentProps: {
-          rows: 4,
-          placeholder: 'Please enter description for this application',
-        },
+        componentProps: { rows: 4, placeholder: 'Please enter description for this application' },
       },
     ];
   });
@@ -501,7 +492,7 @@ export const useCreateAndEditSchema = (
         label: 'Development Mode',
         component: 'Input',
         render: ({ model }) => {
-          if (model.jobType === 1) {
+          if (model.jobType == 1) {
             return h(
               Alert,
               { type: 'info' },
@@ -529,28 +520,56 @@ export const useCreateAndEditSchema = (
     ];
   });
 
-  onMounted(async () => {
-    /* Get project data */
-    projectList.value = await fetchSelect({});
-    flinkEnvs.value = await fetchFlinkEnv();
+  onMounted(() => {
     /* Get project data */
-    alerts.value = await fetchAlertSetting();
-    flinkClusters.value = await fetchFlinkCluster();
-    historyRecord.k8sNamespace = await fetchK8sNamespaces();
-    historyRecord.k8sSessionClusterId = await fetchSessionClusterIds({ executionMode: 5 });
-    historyRecord.flinkImage = await fetchFlinkBaseImages();
-  });
+    fetchSelect({}).then((res) => {
+      projectList.value = res;
+    });
+
+    /* Get alert data */
+    fetchAlertSetting().then((res) => {
+      alerts.value = res;
+    });
 
+    //get flinkEnv
+    fetchFlinkEnv().then((res) => {
+      flinkEnvs.value = res;
+    });
+    //get flinkCluster
+    fetchFlinkCluster().then((res) => {
+      flinkClusters.value = res;
+    });
+    fetchK8sNamespaces().then((res) => {
+      historyRecord.k8sNamespace = res;
+    });
+    fetchSessionClusterIds({ executionMode: 5 }).then((res) => {
+      historyRecord.k8sSessionClusterId = res;
+    });
+    fetchFlinkBaseImages().then((res) => {
+      historyRecord.flinkImage = res;
+    });
+
+    fetchVariableAll().then((res) => {
+      suggestions.value = res.map((v) => {
+        return {
+          text: v.variableCode,
+          description: v.description,
+          value: v.variableValue,
+        };
+      });
+    });
+  });
   return {
+    projectList,
+    alerts,
+    flinkEnvs,
+    flinkClusters,
+    historyRecord,
+    suggestions,
     getFlinkSqlSchema,
     getFlinkClusterSchemas,
     getFlinkFormOtherSchemas,
     getFlinkTypeSchema,
     openConfDrawer,
-    alerts,
-    flinkEnvs,
-    flinkClusters,
-    historyRecord,
-    projectList,
   };
 };
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useCreateSchema.ts b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useCreateSchema.ts
index e0d6be723..37a390096 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useCreateSchema.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useCreateSchema.ts
@@ -21,9 +21,8 @@ import { fetchCheckHadoop } from '/@/api/flink/setting';
 
 import Icon, { SvgIcon } from '/@/components/Icon';
 import { useCreateAndEditSchema } from './useCreateAndEditSchema';
-import { fetchAppConf, fetchMain } from '/@/api/flink/app/app';
+import { fetchMain, fetchName } from '/@/api/flink/app/app';
 import { modules, fetchListConf, fetchListJars } from '/@/api/flink/project';
-import { decodeByBase64 } from '/@/utils/cipher';
 import { RuleObject } from 'ant-design-vue/lib/form';
 import { StoreValue } from 'ant-design-vue/lib/form/interface';
 import { renderResourceFrom } from './useFlinkRender';
@@ -52,23 +51,23 @@ export const useCreateSchema = (dependencyRef: Ref) => {
   const jars = ref<Array<any>>([]);
 
   const {
-    getFlinkSqlSchema,
-    getFlinkClusterSchemas,
-    getFlinkFormOtherSchemas,
     flinkEnvs,
     flinkClusters,
     projectList,
-    openConfDrawer,
+    getFlinkSqlSchema,
+    getFlinkClusterSchemas,
+    getFlinkFormOtherSchemas,
+    suggestions,
   } = useCreateAndEditSchema(dependencyRef);
 
-  async function handleEditConfig(config: string) {
-    console.log('config', config);
-    const res = await fetchAppConf({ config });
-    const conf = decodeByBase64(res);
-    openConfDrawer(true, {
-      configOverride: conf,
-    });
-  }
+  // async function handleEditConfig(config: string) {
+  //   console.log('config', config);
+  //   const res = await fetchAppConf({ config });
+  //   const conf = decodeByBase64(res);
+  //   openConfDrawer(true, {
+  //     configOverride: conf,
+  //   });
+  // }
   function handleCheckConfig(_rule: RuleObject, value: StoreValue) {
     if (value) {
       const isProp = value.endsWith('.properties');
@@ -145,7 +144,7 @@ export const useCreateSchema = (dependencyRef: Ref) => {
         component: 'Select',
         render: ({ model }) => renderResourceFrom(model),
         rules: [{ required: true, message: 'resource from is required' }],
-        ifShow: ({ values }) => values?.jobType != 'sql',
+        show: ({ values }) => values?.jobType != 'sql',
       },
       {
         field: 'uploadJobJar',
@@ -177,7 +176,7 @@ export const useCreateSchema = (dependencyRef: Ref) => {
             modules({
               id: value,
             }).then((res) => {
-              moduleList.value = res;
+              moduleList.value = res.map((i: string) => ({ label: i, value: i }));
             });
           },
         },
@@ -215,8 +214,8 @@ export const useCreateSchema = (dependencyRef: Ref) => {
           return {
             placeholder: 'Please select Application type',
             options: [
-              { label: 'StreamPark Flink', value: 1 },
-              { label: 'Apache Flink', value: 2 },
+              { label: 'StreamPark Flink', value: '1' },
+              { label: 'Apache Flink', value: '2' },
             ],
             onChange: () => {
               Object.assign(formModel, {
@@ -225,7 +224,7 @@ export const useCreateSchema = (dependencyRef: Ref) => {
                 configOverride: null,
               });
               fetchListJars({
-                id: formModel.projectId,
+                id: formModel.project,
                 module: formModel.module,
               }).then((res) => {
                 jars.value = res;
@@ -234,7 +233,7 @@ export const useCreateSchema = (dependencyRef: Ref) => {
           };
         },
         ifShow: ({ values }) => values?.jobType !== 'sql' && values?.resourceFrom !== 'upload',
-        rules: [{ required: true, message: 'Application Type is required' }],
+        dynamicRules: () => [{ required: true, message: 'Application Type is required' }],
       },
       {
         field: 'jar',
@@ -246,7 +245,7 @@ export const useCreateSchema = (dependencyRef: Ref) => {
             options: unref(jars).map((i) => ({ label: i, value: i })),
             onChange: (value) => {
               fetchMain({
-                projectId: formModel.projectId,
+                projectId: formModel.project,
                 module: formModel.module,
                 jar: value,
               }).then((res) => {
@@ -256,7 +255,7 @@ export const useCreateSchema = (dependencyRef: Ref) => {
           };
         },
         ifShow: ({ values }) =>
-          values?.jobType != 'sql' && values?.resourceFrom != 'upload' && values.appType == 2,
+          values?.jobType != 'sql' && values?.resourceFrom != 'upload' && values.appType == '2',
         rules: [{ required: true, message: 'Program Jar is required' }],
       },
       {
@@ -265,7 +264,7 @@ export const useCreateSchema = (dependencyRef: Ref) => {
         component: 'Input',
         componentProps: { placeholder: 'Please enter Main class' },
         ifShow: ({ values }) =>
-          values?.jobType != 'sql' && values?.resourceFrom != 'upload' && values.appType == 2,
+          values?.jobType != 'sql' && values?.resourceFrom != 'upload' && values.appType == '2',
         rules: [{ required: true, message: 'Program Main is required' }],
       },
       {
@@ -273,32 +272,24 @@ export const useCreateSchema = (dependencyRef: Ref) => {
         label: 'Application conf',
         component: 'ApiTreeSelect',
         componentProps: ({ formModel }) => {
-          const componentProps = {
+          return {
             api: fetchListConf,
-            beforeFetch: () => {
-              return {
-                id: formModel.projectId,
-                module: formModel.module,
-              };
-            },
+            params: { id: formModel.project, module: formModel.module },
             dropdownStyle: { maxHeight: '400px', overflow: 'auto' },
             placeholder: 'Please select config',
             treeDefaultExpandAll: true,
+            fieldNames: { children: 'children', label: 'title', key: 'value', value: 'value' },
+            onChange: (value: string) => {
+              fetchName({
+                config: value,
+              }).then((resp) => {
+                formModel.jobName = resp;
+              });
+            },
           };
-          if (formModel.config) {
-            Object.assign(componentProps, {
-              suffixIcon: h(Icon, {
-                icon: 'ant-design:setting-twotone',
-                twoToneColor: '#4a9ff5',
-                title: 'edit config',
-                onClick: handleEditConfig.bind(null, formModel.config),
-              }),
-            });
-          }
-          return componentProps;
         },
         ifShow: ({ values }) =>
-          values?.jobType != 'sql' && values?.resourceFrom != 'upload' && values.appType == 1,
+          values?.jobType != 'sql' && values?.resourceFrom != 'upload' && values.appType == '1',
         dynamicRules: () => [{ required: true, validator: handleCheckConfig }],
       },
       {
@@ -313,5 +304,5 @@ export const useCreateSchema = (dependencyRef: Ref) => {
     ];
   });
 
-  return { getCreateFormSchema, flinkEnvs, flinkClusters };
+  return { flinkEnvs, flinkClusters, getCreateFormSchema, suggestions };
 };
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEdit.ts b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEdit.ts
index e4ca7d9fd..16c754312 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEdit.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEdit.ts
@@ -14,18 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { reactive, Ref, ref, unref } from 'vue';
+import { reactive } from 'vue';
 import { useRoute } from 'vue-router';
 import { optionsValueMapping } from '../data/option';
 import { fetchGet } from '/@/api/flink/app/app';
 import { AppListRecord } from '/@/api/flink/app/app.type';
+import { isString } from '/@/utils/is';
 
-export const useEdit = (alerts?: Ref) => {
+export const useEdit = () => {
   const route = useRoute();
 
   const app = reactive<Partial<AppListRecord>>({});
   const defaultOptions = reactive<any>({});
-  const selectAlertId = ref<Nullable<number>>(null);
   const memoryItems = reactive<{
     totalItems: string[];
     jmMemoryItems: string[];
@@ -43,26 +43,27 @@ export const useEdit = (alerts?: Ref) => {
     Object.assign(app, res);
     Object.assign(defaultOptions, JSON.parse(app.options || '{}'));
     Object.assign(returnData, {
+      jobType: res.jobType,
       versionId: res.versionId,
       executionMode: res.executionMode,
       resourceFrom: res.resourceFrom,
     });
-    if (res.alertId) {
-      selectAlertId.value = unref(alerts)?.filter((t) => t.id == app.alertId)[0]?.id;
-    }
     return returnData;
   }
   /* Form reset */
   function handleResetApplication() {
     let parallelism: Nullable<number> = null;
     let slot: Nullable<number> = null;
-    const fieldValueOptions = {};
-
+    const fieldValueOptions = {
+      totalItem: {},
+      tmOptionsItem: {},
+      jmOptionsItem: {},
+    };
     for (const k in defaultOptions) {
-      const v = defaultOptions[k];
+      let v = defaultOptions[k];
+      if (isString(v)) v = v.replace(/[k|m|g]b$/g, '');
       const key = optionsValueMapping.get(k);
       if (key) {
-        fieldValueOptions[key] = v;
         if (
           k === 'jobmanager.memory.flink.size' ||
           k === 'taskmanager.memory.flink.size' ||
@@ -70,22 +71,27 @@ export const useEdit = (alerts?: Ref) => {
           k === 'taskmanager.memory.process.size'
         ) {
           memoryItems.totalItems.push(key);
+          fieldValueOptions.totalItem[key] = parseInt(v);
         } else {
           if (k.startsWith('jobmanager.memory.')) {
             memoryItems.jmMemoryItems.push(key);
+            fieldValueOptions.jmOptionsItem[key] = parseInt(v);
           }
           if (k.startsWith('taskmanager.memory.')) {
             memoryItems.tmMemoryItems.push(key);
+            fieldValueOptions.tmOptionsItem[key] = parseInt(v);
           }
-          if (k === 'taskmanager.numberOfTaskSlots') {
-            slot = parseInt(v);
-          }
-          if (k === 'parallelism.default') {
-            parallelism = parseInt(v);
-          }
+        }
+      } else {
+        if (k === 'taskmanager.numberOfTaskSlots') {
+          slot = parseInt(v);
+        }
+        if (k === 'parallelism.default') {
+          parallelism = parseInt(v);
         }
       }
     }
+
     return {
       parallelism,
       slot,
@@ -101,6 +107,5 @@ export const useEdit = (alerts?: Ref) => {
     defaultOptions,
     app,
     memoryItems,
-    selectAlertId,
   };
 };
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEditFlinkSchema.ts b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEditFlinkSchema.ts
index 2d7eb7daa..62e95d59f 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEditFlinkSchema.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEditFlinkSchema.ts
@@ -28,15 +28,15 @@ import { fetchMain } from '/@/api/flink/app/app';
 export const useEditFlinkSchema = (jars: Ref) => {
   const flinkSql = ref();
   const app = reactive<Partial<AppListRecord>>({});
-  const resourceFrom = ref<Nullable<number>>(null);
   const route = useRoute();
   const {
+    alerts,
+    flinkEnvs,
+    flinkClusters,
     getFlinkClusterSchemas,
     getFlinkFormOtherSchemas,
     getFlinkTypeSchema,
-    flinkEnvs,
-    flinkClusters,
-    alerts,
+    suggestions,
   } = useCreateAndEditSchema(null, { appId: route.query.appId as string, mode: 'streampark' });
 
   const getEditFlinkFormSchema = computed((): FormSchema[] => {
@@ -55,9 +55,9 @@ export const useEditFlinkSchema = (jars: Ref) => {
         field: 'resourceFrom',
         label: 'Resource From',
         component: 'Input',
-        render: () => {
-          if (unref(resourceFrom) === 1) return getAlertSvgIcon('github', 'CICD (build from CSV)');
-          else if (unref(resourceFrom) === 2)
+        render: ({ model }) => {
+          if (model.resourceFrom == 1) return getAlertSvgIcon('github', 'CICD (build from CSV)');
+          else if (model.resourceFrom == 2)
             return getAlertSvgIcon('upload', 'Upload (upload local job)');
           else return '';
         },
@@ -67,15 +67,15 @@ export const useEditFlinkSchema = (jars: Ref) => {
         field: 'projectName',
         label: 'Project',
         component: 'Input',
-        render: () => h(Alert, { message: app.projectName, type: 'info' }),
-        ifShow: unref(resourceFrom) === 1,
+        render: ({ model }) => h(Alert, { message: model.projectName, type: 'info' }),
+        ifShow: ({ model }) => model.resourceFrom == 1,
       },
       {
         field: 'module',
         label: 'Module',
         component: 'Input',
         render: () => h(Alert, { message: app.module, type: 'info' }),
-        ifShow: unref(resourceFrom) === 1,
+        ifShow: ({ model }) => model.resourceFrom == 1,
       },
       {
         field: 'jar',
@@ -85,10 +85,10 @@ export const useEditFlinkSchema = (jars: Ref) => {
           return {
             placeholder: 'Please select jar',
             options: unref(jars).map((i) => ({ label: i, value: i })),
-            onChange: (value) => {
+            onChange: (value: string) => {
               fetchMain({
-                projectId: app.projectId,
-                module: app.module,
+                projectId: formModel.projectId,
+                module: formModel.module,
                 jar: value,
               }).then((res) => {
                 formModel.mainClass = res;
@@ -96,7 +96,7 @@ export const useEditFlinkSchema = (jars: Ref) => {
             },
           };
         },
-        ifShow: unref(resourceFrom) === 1,
+        ifShow: ({ model }) => model.resourceFrom == 1,
         rules: [{ required: true, message: 'Please select jar' }],
       },
       {
@@ -104,14 +104,14 @@ export const useEditFlinkSchema = (jars: Ref) => {
         label: 'Upload Job Jar',
         component: 'Select',
         slot: 'uploadJobJar',
-        ifShow: unref(resourceFrom) !== 1,
+        ifShow: ({ model }) => model.resourceFrom != 1,
       },
       {
         field: 'jar',
         label: 'Program Jar',
         component: 'Input',
         dynamicDisabled: true,
-        ifShow: unref(resourceFrom) !== 1,
+        ifShow: ({ model }) => model.resourceFrom !== 1,
       },
       {
         field: 'mainClass',
@@ -132,5 +132,6 @@ export const useEditFlinkSchema = (jars: Ref) => {
     flinkClusters,
     flinkSql,
     alerts,
+    suggestions,
   };
 };
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEditStreamPark.ts b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEditStreamPark.ts
index 39dae2e3c..6ed0790fa 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEditStreamPark.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useEditStreamPark.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import { FormSchema } from '/@/components/Table';
-import { computed, h, reactive, Ref, ref, unref } from 'vue';
+import { computed, h, Ref, ref, unref } from 'vue';
 import { executionModes } from '../data';
 
 import { useCreateAndEditSchema } from './useCreateAndEditSchema';
@@ -27,7 +27,6 @@ import { fetchFlinkSql } from '/@/api/flink/app/flinkSql';
 import { toPomString } from '../utils/Pom';
 import { handleDependencyJsonToPom } from '../utils';
 import { useDrawer } from '/@/components/Drawer';
-import { AppListRecord } from '/@/api/flink/app/app.type';
 import { useRoute } from 'vue-router';
 
 export const useEditStreamParkSchema = (
@@ -36,21 +35,20 @@ export const useEditStreamParkSchema = (
   dependencyRef: Ref,
 ) => {
   const flinkSql = ref();
-  const app = reactive<Partial<AppListRecord>>({});
   const route = useRoute();
   const {
+    alerts,
+    flinkEnvs,
+    flinkClusters,
     getFlinkSqlSchema,
     getFlinkClusterSchemas,
     getFlinkFormOtherSchemas,
     getFlinkTypeSchema,
-    flinkEnvs,
-    flinkClusters,
-    alerts,
+    suggestions,
   } = useCreateAndEditSchema(dependencyRef, {
     appId: route.query.appId as string,
     mode: 'streampark',
   });
-
   const [registerDifferentDrawer, { openDrawer: openDiffDrawer }] = useDrawer();
 
   async function handleChangeSQL(v) {
@@ -137,16 +135,18 @@ export const useEditStreamParkSchema = (
         field: 'projectName',
         label: 'Project',
         component: 'Input',
-        render: () => h(Alert, { message: app.projectName, type: 'info' }),
+        render: ({ model }) => h(Alert, { message: model.projectName, type: 'info' }),
         ifShow: ({ values }) => values.jobType != 2,
       },
+      { field: 'project', label: 'ProjectId', component: 'Input', show: false },
       {
         field: 'module',
         label: 'Application',
         component: 'Input',
-        render: ({ values }) => h(Alert, { message: values.module, type: 'info' }),
+        render: ({ model }) => h(Alert, { message: model.module, type: 'info' }),
         ifShow: ({ values }) => values.jobType != 2,
       },
+      { field: 'configId', label: 'configId', component: 'Input', show: false },
       {
         field: 'appConf',
         label: 'Application conf',
@@ -176,11 +176,12 @@ export const useEditStreamParkSchema = (
     ];
   });
   return {
-    getEditStreamParkFormSchema,
+    alerts,
     flinkEnvs,
     flinkClusters,
+    getEditStreamParkFormSchema,
     flinkSql,
-    alerts,
     registerDifferentDrawer,
+    suggestions,
   };
 };
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useFlinkRender.tsx b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useFlinkRender.tsx
index 481274396..275b7be30 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useFlinkRender.tsx
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useFlinkRender.tsx
@@ -34,7 +34,7 @@ import {
 import { Button } from '/@/components/Button';
 import { descriptionFilter } from '../utils';
 import { SettingTwoTone } from '@ant-design/icons-vue';
-import { reactive, ref, unref } from 'vue';
+import { ref, unref } from 'vue';
 import { handleConfTemplate } from '/@/api/flink/config';
 import { decodeByBase64 } from '/@/utils/cipher';
 import { useMessage } from '/@/hooks/web/useMessage';
@@ -85,8 +85,7 @@ export const renderInputDropdown = (
 };
 
 export function handleCheckCheckpoint(values: Recordable) {
-  const { cpMaxFailureInterval, cpFailureRateInterval, cpFailureAction } = values;
-  console.log('values', cpMaxFailureInterval, cpFailureRateInterval, cpFailureAction);
+  const { cpMaxFailureInterval, cpFailureRateInterval, cpFailureAction } = values.checkPointFailure;
   if (cpMaxFailureInterval != null && cpFailureRateInterval != null && cpFailureAction != null) {
     if (cpFailureAction === 1) {
       const alertEmail = values.alertEmail;
@@ -115,21 +114,28 @@ export function handleCheckCheckpoint(values: Recordable) {
 }
 
 /* render input Group component */
-export const renderInputGroup = (model: Recordable) => {
-  const formValue = reactive({
-    cpMaxFailureInterval: model.cpMaxFailureInterval,
-    cpFailureRateInterval: model.cpFailureRateInterval,
-    cpFailureAction: model.cpFailureAction,
-  });
+export const renderInputGroup = ({ model }) => {
+  if (!Reflect.has(model, 'checkPointFailure')) {
+    model.checkPointFailure = {};
+  }
+  const handleUpdate = (value: any) => {
+    Object.assign(model, {
+      checkPointFailure: value,
+    });
+  };
   return (
     <Form.Item
       label="CheckPoint Failure Options"
-      name="CheckPointFailure"
+      name="checkPointFailure"
       rules={[{ validator: () => handleCheckCheckpoint(model) }]}
     >
       <CustomForm
-        value={formValue}
-        onUpdateValue={(value: any) => Object.assign(model, value)}
+        value={{
+          cpMaxFailureInterval: model.checkPointFailure.cpMaxFailureInterval,
+          cpFailureRateInterval: model.checkPointFailure.cpFailureRateInterval,
+          cpFailureAction: model.checkPointFailure.cpFailureAction,
+        }}
+        onUpdateValue={handleUpdate}
       ></CustomForm>
     </Form.Item>
   );
@@ -183,21 +189,41 @@ function hasOptions(items) {
   return options.filter((x) => items.includes(x.key)) as any;
 }
 /* render memory option */
-export const renderOptionsItems = (model: Recordable, field: string, reg: string) => {
-  return hasOptions(model[field] || []).map((conf) => {
-    const label = conf.name.replace(new RegExp(reg, 'g'), '').replace(/\./g, ' ');
+export const renderOptionsItems = (
+  model: Recordable,
+  parentField: string,
+  field: string,
+  reg: string,
+  replace = false,
+) => {
+  return hasOptions(model[parentField] || []).map((conf: Recordable) => {
+    let label = conf.name.replace(new RegExp(reg, 'g'), '');
+    if (replace) label = label.replace(/\./g, ' ');
+    if (!Reflect.has(model, field)) {
+      model[field] = {};
+    }
+    if (!model[field][conf.key]) {
+      model[field][conf.key] = conf.defaultValue || null;
+    }
+    if (!Reflect.has(model, conf.key)) {
+      model[conf.key] = model[field][conf.key] || conf.defaultValue || null;
+    }
+
+    function handleValueChange(value: string) {
+      model[conf.key] = value;
+      model[field][conf.key] = value;
+    }
     return (
-      <Form.Item label={label} key={conf.key}>
+      <Form.Item label={label} name={conf.key} key={`${field}.${conf.key}`}>
         {conf.type === 'number' && (
           <InputNumber
+            class="!w-full"
             min={conf.min}
             max={conf.max}
-            defaultValue={conf.defaultValue}
             step={conf.step}
-            value={model[conf.key]}
-            onChange={(value) => (model[conf.key] = value)}
+            value={model[field][conf.key]}
+            onChange={handleValueChange}
             rules={[{ validator: conf.validator }]}
-            name={conf.key}
           />
         )}
         {conf.type === 'switch' && <span class="conf-switch">({conf.placeholder})</span>}
@@ -216,7 +242,7 @@ export const renderProperties = ({ model, field }: RenderCallbackParams) => {
         name="properties"
         placeholder="$key=$value,If there are multiple parameters,you can new line enter them (-D <arg>)"
         value={model[field]}
-        onInput={(e) => (model[field] = e.target.value)}
+        onInput={(e: ChangeEvent) => (model[field] = e?.target?.value)}
       />
       <p class="conf-desc mt-10px">
         <span class="note-info">
@@ -285,6 +311,19 @@ export const renderIsSetConfig = (
       model.isSetConfig = false;
     }
   }
+  function handleMergeSubmit(data: { configOverride: string; isSetConfig: boolean }) {
+    if (data.configOverride == null || !data.configOverride.replace(/^\s+|\s+$/gm, '')) {
+      Object.assign(model, {
+        configOverride: null,
+        isSetConfig: false,
+      });
+    } else {
+      Object.assign(model, {
+        configOverride: data.configOverride,
+        isSetConfig: true,
+      });
+    }
+  }
   return (
     <div>
       <Switch
@@ -303,7 +342,7 @@ export const renderIsSetConfig = (
       )}
 
       <Mergely
-        onOk={(data) => Object.assign(model, data)}
+        onOk={handleMergeSubmit}
         onClose={() => handleEditConfClose()}
         onRegister={registerConfDrawer}
       />
@@ -426,7 +465,7 @@ export const renderCompareSelectTag = (ver: any) => {
 export const renderResourceFrom = (model: Recordable) => {
   return (
     <Select
-      onChange={(value) => (model.resourceFrom = value)}
+      onChange={(value: string) => (model.resourceFrom = value)}
       value={model.resourceFrom}
       placeholder="Please select resource from"
     >
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useFlinkSchema.ts b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useFlinkSchema.ts
index 10829e468..a78bd026e 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useFlinkSchema.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/hooks/useFlinkSchema.ts
@@ -255,16 +255,21 @@ export const useFlinkSchema = (editModel?: string) => {
       },
     },
     {
-      field: 'cpMaxFailureInterval',
+      field: 'checkPointFailure',
       label: 'CheckPoint Failure Options',
       component: 'InputNumber',
-      renderColContent: ({ model }) => renderInputGroup(model),
+      renderColContent: renderInputGroup,
       show: ({ values }) => (editModel == 'flink' ? true : ![5, 6].includes(values.executionMode)),
     },
     {
       field: 'alertId',
       label: 'Fault Alert Template',
       component: 'Select',
+      componentProps: {
+        placeholder: 'Alert Template',
+        options: unref(alerts),
+        fieldNames: { label: 'alertName', value: 'id', options: 'options' },
+      },
     },
     ...getConfigSchemas(),
     {
@@ -277,7 +282,8 @@ export const useFlinkSchema = (editModel?: string) => {
       field: 'totalItem',
       label: 'totalItem',
       component: 'Select',
-      renderColContent: ({ model }) => renderOptionsItems(model, 'totalOptions', '.memory'),
+      renderColContent: ({ model, field }) =>
+        renderOptionsItems(model, 'totalOptions', field, '.memory', true),
     },
     {
       field: 'jmOptions',
@@ -294,10 +300,11 @@ export const useFlinkSchema = (editModel?: string) => {
       },
     },
     {
-      field: 'jmOptionsItem',
-      label: 'jmOptionsItem',
+      field: 'jmMemoryItem',
+      label: 'jmMemoryItem',
       component: 'Select',
-      renderColContent: ({ model }) => renderOptionsItems(model, 'jmOptions', 'jobmanager.memory.'),
+      renderColContent: ({ model, field }) =>
+        renderOptionsItems(model, 'jmOptions', field, 'jobmanager.memory.'),
     },
     {
       field: 'tmOptions',
@@ -317,8 +324,8 @@ export const useFlinkSchema = (editModel?: string) => {
       field: 'tmOptionsItem',
       label: 'tmOptionsItem',
       component: 'Select',
-      renderColContent: ({ model }) =>
-        renderOptionsItems(model, 'tmOptions', 'taskmanager.memory.'),
+      renderColContent: ({ model, field }) =>
+        renderOptionsItems(model, 'tmOptions', field, 'taskmanager.memory.'),
     },
     {
       field: 'yarnQueue',
@@ -346,10 +353,8 @@ export const useFlinkSchema = (editModel?: string) => {
       field: 'args',
       label: 'Program Args',
       component: 'InputTextArea',
-      componentProps: {
-        rows: 4,
-        placeholder: '<arguments>',
-      },
+      defaultValue: '',
+      slot: 'args',
       ifShow: ({ values }) => (editModel ? true : values.jobType == 'customcode'),
     },
     {
@@ -371,7 +376,7 @@ export const useFlinkSchema = (editModel?: string) => {
         label: 'Development Mode',
         component: 'Input',
         render: ({ model }) => {
-          if (model.jobType === 1) {
+          if (model.jobType == 1) {
             return h(
               Alert,
               { type: 'info' },
@@ -428,6 +433,7 @@ export const useFlinkSchema = (editModel?: string) => {
         }
       },
     },
+    { field: 'configOverride', label: '', component: 'Input', show: false },
     {
       field: 'isSetConfig',
       label: 'Application Conf',
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/styles/Add.less b/streampark-console/streampark-console-newui/src/views/flink/app/styles/Add.less
index df09985fc..7781a1997 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/styles/Add.less
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/styles/Add.less
@@ -85,11 +85,6 @@
     line-height: 25px;
   }
 
-  .conf-switch {
-    color: darkgrey;
-    margin-left: 5px;
-  }
-
   .ant-input-number {
     width: 100%;
   }
@@ -122,6 +117,8 @@
 
 .flinksql-tool-item {
   font-size: 12px;
+  display: flex;
+  align-items: center;
 }
 
 .pod-template-tool {
@@ -185,7 +182,7 @@
   .verify-sql {
     z-index: 99;
     position: absolute;
-    bottom: 20px;
+    bottom: 40px;
     float: right;
     right: 20px;
     cursor: pointer;
@@ -206,8 +203,8 @@
     margin-top: 15px;
     width: 100%;
     border-radius: 5px;
-    background-color: @background-color-base;
-    border: 1px solid @border-color-base;
+    background-color: #e6f7ff;
+    border: 1px solid #d9d9d9;
     display: inline-block;
     margin-bottom: -25px;
 
@@ -278,11 +275,17 @@
   }
 
   .icon-close {
-    color: rgba(0 0 0 / 45%);
+    color: #00000073;
     font-size: 12px;
   }
 }
 
+[data-theme="dark"] {
+  .app_controller .icon-close {
+    color: #ffffff73;
+  }
+}
+
 .slide-fade-enter-active {
   transition: all 0.3s ease;
 }
diff --git a/streampark-console/streampark-console-newui/src/views/flink/app/utils/index.ts b/streampark-console/streampark-console-newui/src/views/flink/app/utils/index.ts
index c0d84d685..ef09cfc85 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/app/utils/index.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/app/utils/index.ts
@@ -14,12 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { omit } from 'lodash-es';
 import { optionsKeyMapping } from '../data/option';
 import { fetchYarn } from '/@/api/flink/app/app';
 import { AppListRecord } from '/@/api/flink/app/app.type';
 import { fetchActiveURL } from '/@/api/flink/setting/flinkCluster';
-import { useUserStore } from '/@/store/modules/user';
 
 export function handleAppBuildStatusColor(statusCode) {
   switch (statusCode) {
@@ -167,9 +165,9 @@ export function handleYarnQueue(values) {
 }
 
 /* Splice parameters */
-export function handleFormValue(values) {
+export function handleFormValue(values: Recordable) {
   const options = {};
-  for (const k in omit(values, ['totalOptions', 'jmOptions', 'tmOptions'])) {
+  for (const k in values) {
     const v = values[k];
     if (v != null && v !== '' && v !== undefined) {
       if (k === 'parallelism') {
@@ -179,8 +177,8 @@ export function handleFormValue(values) {
       } else {
         if (
           values.totalOptions?.includes(k) ||
-          values.jmMemoryItems?.includes(k) ||
-          values.tmMemoryItems?.includes(k)
+          values.jmOptions?.includes(k) ||
+          values.tmOptions?.includes(k)
         ) {
           const opt = optionsKeyMapping.get(k);
           const unit = opt?.['unit'] || '';
@@ -246,10 +244,8 @@ export function handleSubmitParams(
   values: Recordable,
   k8sTemplate: Recordable,
 ) {
-  const useStore = useUserStore();
   const options = handleFormValue(values);
   Object.assign(params, {
-    teamId: useStore?.getTeamId,
     executionMode: values.executionMode,
     versionId: values.versionId,
     jobName: values.jobName,
@@ -257,9 +253,9 @@ export function handleSubmitParams(
     args: values.args || null,
     options: JSON.stringify(options),
     yarnQueue: handleYarnQueue(values),
-    cpMaxFailureInterval: values.cpMaxFailureInterval || null,
-    cpFailureRateInterval: values.cpFailureRateInterval || null,
-    cpFailureAction: values.cpFailureAction || null,
+    cpMaxFailureInterval: values.checkPointFailure?.cpMaxFailureInterval || null,
+    cpFailureRateInterval: values.checkPointFailure?.cpFailureRateInterval || null,
+    cpFailureAction: values.checkPointFailure?.cpFailureAction || null,
     properties: values.properties || null,
     resolveOrder: values.resolveOrder,
     k8sRestExposedType: values.k8sRestExposedType,
diff --git a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertDetailModal.vue b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertDetailModal.vue
new file mode 100644
index 000000000..4abdc37dc
--- /dev/null
+++ b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertDetailModal.vue
@@ -0,0 +1,136 @@
+<!--
+  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
+
+      https://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.
+-->
+<script lang="ts">
+  export default defineComponent({
+    name: 'AlertDetailModal',
+  });
+</script>
+<script setup lang="ts" name="AlertDetailModal">
+  import { defineComponent, reactive, ref, h } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { SvgIcon } from '/@/components/Icon';
+  import { DescItem, Description } from '/@/components/Description';
+  import { Divider, Tag, Typography } from 'ant-design-vue';
+  const typographyParagraph = Typography.Paragraph;
+  interface DingTalkType {
+    token: string;
+    contacts: string;
+    isAtAll: boolean;
+    alertDingURL: string;
+    secretEnable: boolean;
+    secretToken: string;
+  }
+  interface LarkType {
+    token: string;
+    isAtAll: boolean;
+    secretEnable: boolean;
+    secretToken: string;
+  }
+
+  const emailInfo = ref<{ contacts: string }>({ contacts: '' });
+  const weChat = ref<{ contacts: string }>({ contacts: '' });
+  const alertTypeTags = ref<string[]>([]);
+  const dingTalk = reactive<Partial<DingTalkType>>({});
+  const lark = reactive<Partial<LarkType>>({});
+
+  const [registerModal] = useModalInner((data) => {
+    emailInfo.value = { contacts: '' };
+    weChat.value = { contacts: '' };
+    alertTypeTags.value = [];
+    if (data) {
+      alertTypeTags.value = data.alertTypeTags;
+      emailInfo.value = JSON.parse(data.emailParams || '{}');
+      weChat.value = JSON.parse(data.weComParams || '{}');
+      if (data.dingTalkParams) {
+        Object.assign(dingTalk, JSON.parse(data.dingTalkParams || '{}'));
+      }
+      if (data.larkParams) {
+        Object.assign(lark, JSON.parse(data.larkParams || '{}'));
+        console.log('lark', lark);
+      }
+    }
+  });
+  const dingTalkColumn: DescItem[] = [
+    { label: 'DingTalk Url', field: 'alertDingURL', span: 2, labelMinWidth: 50 },
+    { label: 'Access Token', field: 'token', span: 2, render: renderTypl },
+    { label: 'Secret Token', field: 'secretToken', span: 2, render: renderTypl },
+    { label: 'DingTalk User', field: 'contacts' },
+    { label: 'At All User', field: 'isAtAll', render: renderTag },
+  ];
+  const larkColumn: DescItem[] = [
+    { label: 'Lark Token', field: 'token', span: 2, render: renderTypl },
+    { label: 'Lark Secret Token', field: 'secretToken', span: 2, render: renderTypl },
+    { label: 'At All User', field: 'isAtAll', render: renderTag },
+  ];
+  function renderTag(value: boolean) {
+    return h(Tag, { color: value ? 'green' : 'red', class: '!leading-20px' }, () => String(value));
+  }
+
+  function renderTypl(value: string) {
+    return h(typographyParagraph, { copyable: true, class: '!mb-0' }, () => value);
+  }
+</script>
+
+<template>
+  <BasicModal :show-ok-btn="false" @register="registerModal" class="alert-detail">
+    <template #title>
+      <SvgIcon name="alarm" size="25" />
+      Alert Detail
+    </template>
+    <template v-if="alertTypeTags.includes('1')">
+      <Divider>
+        <SvgIcon name="mail" size="20" />
+        E-mail
+      </Divider>
+      <Description
+        class="alert-detail"
+        :column="1"
+        :data="emailInfo"
+        :schema="[{ label: 'Alert Email', field: 'contacts' }]"
+      />
+    </template>
+    <template v-if="alertTypeTags.includes('2')">
+      <Divider>
+        <SvgIcon name="dingtalk" size="20" />
+        Ding Talk
+      </Divider>
+      <Description class="alert-detail" :column="2" :data="dingTalk" :schema="dingTalkColumn" />
+    </template>
+    <template v-if="alertTypeTags.includes('4')">
+      <Divider><SvgIcon name="wecom" size="20" /> WeChat </Divider>
+      <Description
+        class="alert-detail"
+        :column="1"
+        :data="weChat"
+        :schema="[{ label: 'WeChat token', field: 'token', render: renderTypl }]"
+      />
+    </template>
+    <template v-if="alertTypeTags.includes('16')">
+      <Divider>
+        <SvgIcon name="dingtalk" size="20" />
+        Ding Talk
+      </Divider>
+      <Description :column="2" :data="lark" :schema="larkColumn" class="alert-detail" />
+    </template>
+  </BasicModal>
+</template>
+
+<style>
+  .alert-detail .ant-descriptions-item-label {
+    width: 150px;
+  }
+</style>
diff --git a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertModal.vue b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertModal.vue
index 014e802e8..549c5a671 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertModal.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertModal.vue
@@ -54,7 +54,7 @@
         label: 'Alert Name',
         component: 'Input',
         componentProps: { allowClear: true, placeholder: 'Please enter alert name' },
-        itemExtra: h(
+        afterItem: h(
           'span',
           { class: 'conf-switch' },
           'the alert name, e.g: StreamPark team alert',
@@ -217,7 +217,6 @@
           </SelectOption>
         </Select>
       </template>
-      {{ alertType }}
       <template #alertEmail="{ model, field }">
         <!-- Alert Email -->
         <template v-if="(alertType || []).includes('1')">
diff --git a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertSetting.vue b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertSetting.vue
index 5b5c9decd..1536bd48c 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertSetting.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertSetting.vue
@@ -26,6 +26,7 @@
   import { onMounted, ref } from 'vue';
   import { List, Popconfirm, Tooltip, Card, Tag } from 'ant-design-vue';
   import {
+    EyeOutlined,
     ThunderboltOutlined,
     EditOutlined,
     DeleteOutlined,
@@ -33,6 +34,7 @@
   } from '@ant-design/icons-vue';
   import { useModal } from '/@/components/Modal';
   import AlertModal from './AlertModal.vue';
+  import AlertDetailModal from './AlertDetailModal.vue';
   import { fetchAlertSetting, fetchSendAlert, fetchAlertDelete } from '/@/api/flink/setting/alert';
   import { AlertSetting } from '/@/api/flink/setting/types/alert.type';
   import { useMessage } from '/@/hooks/web/useMessage';
@@ -43,6 +45,7 @@
   const { t } = useI18n();
   const { Swal, createMessage } = useMessage();
   const [registerAlertModal, { openModal: openAlertModal }] = useModal();
+  const [registerAlertDetailModal, { openModal: openAlertDetailModal }] = useModal();
   const alerts = ref<AlertSetting[]>([]);
 
   /* Get alert configuration */
@@ -178,7 +181,7 @@
 
   <List
     class="alert-card-list"
-    :grid="{ gutter: 40, lg: 2, xxl: 3 }"
+    :grid="{ gutter: 40, xs: 1, sm: 2, md: 4, lg: 4, xl: 4, xxl: 4 }"
     :data-source="alerts"
     :pagination="false"
   >
@@ -187,7 +190,7 @@
         <Card
           class="shadow-xl alert-card"
           :bordered="false"
-          :bodyStyle="{ height: '260px', padding: '15px', overflowY: 'auto' }"
+          :bodyStyle="{ height: '240px', padding: '15px', overflowY: 'auto' }"
         >
           <template #title>
             {{ item.alertName }}
@@ -215,6 +218,17 @@
                 <ThunderboltOutlined />
               </a-button>
             </Tooltip>
+            <Tooltip title="Alert Detail">
+              <a-button
+                @click="openAlertDetailModal(true, item)"
+                shape="circle"
+                size="large"
+                style="margin-left: 3px"
+                class="control-button ctl-btn-color"
+              >
+                <EyeOutlined />
+              </a-button>
+            </Tooltip>
             <Tooltip title="Edit Alert Config">
               <a-button
                 @click="handleEditAlertConf(item)"
@@ -275,6 +289,7 @@
   </List>
 
   <AlertModal @register="registerAlertModal" @reload="getAlertSetting" width="850px" />
+  <AlertDetailModal @register="registerAlertDetailModal" width="850px" />
 </template>
 <style lang="less">
   .alert-card {
diff --git a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertTypeInfo.vue b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertTypeInfo.vue
index 5899f470b..9853eb13f 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertTypeInfo.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertTypeInfo.vue
@@ -61,22 +61,13 @@
       </span>
     </div>
   </BasicTitle>
-  <Descriptions size="small" :column="2" class="pl-15px mt-10px">
+  <Descriptions size="small" :column="1" class="pl-15px mt-10px">
     <template v-if="alertType === '1'">
-      <DescriptionsItem label="Alert Email" :span="2">
+      <DescriptionsItem label="Alert Email">
         <span class="text-blue-500">{{ emailInfo.contacts || '' }}</span>
       </DescriptionsItem>
     </template>
     <template v-else-if="alertType === '2'">
-      <DescriptionsItem label="DingTalk Url" :span="2">
-        {{ dingTalk.alertDingURL || '' }}
-      </DescriptionsItem>
-      <DescriptionsItem label="Access Token" :span="2">
-        {{ desensitization(dingTalk.token || '') }}
-      </DescriptionsItem>
-      <DescriptionsItem label="Secret Token" v-if="dingTalk.secretToken" :span="2">
-        {{ desensitization(dingTalk.secretToken || '') }}
-      </DescriptionsItem>
       <DescriptionsItem label="DingTalk User">
         {{ dingTalk.contacts || '' }}
       </DescriptionsItem>
@@ -87,17 +78,11 @@
       </DescriptionsItem>
     </template>
     <template v-else-if="alertType === '4'">
-      <DescriptionsItem label="WeChat token" :span="2">
+      <DescriptionsItem label="WeChat token">
         {{ desensitization(weChat.token || '') }}
       </DescriptionsItem>
     </template>
     <template v-else-if="alertType === '16'">
-      <DescriptionsItem label="Lark Token" :span="2">
-        {{ desensitization(lark.token || '') }}
-      </DescriptionsItem>
-      <DescriptionsItem label="Lark Secret Token" :span="2">
-        {{ desensitization(lark.secretToken || '') }}
-      </DescriptionsItem>
       <DescriptionsItem label="At All User">
         <Tag :color="lark.isAtAll ? 'green' : 'red'" class="!leading-20px">
           {{ lark.isAtAll }}
diff --git a/streampark-console/streampark-console-newui/src/views/flink/setting/components/FlinkEnvModal.vue b/streampark-console/streampark-console-newui/src/views/flink/setting/components/FlinkEnvModal.vue
index f05d9f898..9cc97b242 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/setting/components/FlinkEnvModal.vue
+++ b/streampark-console/streampark-console-newui/src/views/flink/setting/components/FlinkEnvModal.vue
@@ -54,7 +54,7 @@
           placeholder: 'Please enter flink name',
           allowClear: true,
         },
-        itemExtra: h('span', { class: 'conf-switch' }, 'the flink name, e.g: flink-1.12'),
+        afterItem: h('span', { class: 'conf-switch' }, 'the flink name, e.g: flink-1.12'),
         rules: [{ required: true, message: 'flink name is required' }],
       },
       {
@@ -65,7 +65,7 @@
           placeholder: 'Please enter flink home',
           allowClear: true,
         },
-        itemExtra: h('span', { class: 'conf-switch' }, 'The absolute path of the FLINK_HOME'),
+        afterItem: h('span', { class: 'conf-switch' }, 'The absolute path of the FLINK_HOME'),
         rules: [{ required: true, message: 'flink home is required' }],
       },
       {
diff --git a/streampark-console/streampark-console-newui/src/views/flink/setting/hooks/useClusterSetting.ts b/streampark-console/streampark-console-newui/src/views/flink/setting/hooks/useClusterSetting.ts
index d131f4867..fbbe197a2 100644
--- a/streampark-console/streampark-console-newui/src/views/flink/setting/hooks/useClusterSetting.ts
+++ b/streampark-console/streampark-console-newui/src/views/flink/setting/hooks/useClusterSetting.ts
@@ -257,7 +257,8 @@ export const useClusterSetting = () => {
         label: 'totalItem',
         ifShow: ({ values }) => [3, 5].includes(values.executionMode),
         component: 'Select',
-        renderColContent: ({ model }) => renderOptionsItems(model, 'totalOptions', '.memory'),
+        renderColContent: ({ model, field }) =>
+          renderOptionsItems(model, 'totalOptions', field, '.memory', true),
       },
       {
         field: 'jmOptions',
@@ -279,8 +280,8 @@ export const useClusterSetting = () => {
         label: 'jmOptionsItem',
         ifShow: ({ values }) => [3, 5].includes(values.executionMode),
         component: 'Select',
-        renderColContent: ({ model }) =>
-          renderOptionsItems(model, 'jmOptions', 'jobmanager.memory.'),
+        renderColContent: ({ model, field }) =>
+          renderOptionsItems(model, 'jmOptions', field, 'jobmanager.memory.'),
       },
       {
         field: 'tmOptions',
@@ -302,8 +303,8 @@ export const useClusterSetting = () => {
         label: 'tmOptionsItem',
         ifShow: ({ values }) => [3, 5].includes(values.executionMode),
         component: 'Select',
-        renderColContent: ({ model }) =>
-          renderOptionsItems(model, 'tmOptions', 'taskmanager.memory.'),
+        renderColContent: ({ model, field }) =>
+          renderOptionsItems(model, 'tmOptions', field, 'taskmanager.memory.'),
       },
       {
         field: 'properties',
diff --git a/streampark-console/streampark-console-newui/src/views/system/variable/DependApps.vue b/streampark-console/streampark-console-newui/src/views/system/variable/DependApps.vue
index 22bf4e5c5..e8c321141 100644
--- a/streampark-console/streampark-console-newui/src/views/system/variable/DependApps.vue
+++ b/streampark-console/streampark-console-newui/src/views/system/variable/DependApps.vue
@@ -20,19 +20,21 @@
   };
 </script>
 <script setup lang="ts" name="DependApp">
-  import { ref } from 'vue';
   import { useRoute, useRouter } from 'vue-router';
   import { fetchDependApps } from '/@/api/system/variable';
   import Icon from '/@/components/Icon';
   import { PageWrapper } from '/@/components/Page';
-  import { BasicTable } from '/@/components/Table';
+  import { BasicTable, useTable } from '/@/components/Table';
 
   const route = useRoute();
   const router = useRouter();
-  const tableConfig = ref({
+  const [registerTable] = useTable({
+    title: 'Variable Depend Apps',
     api: fetchDependApps,
     canResize: false,
     showIndexColumn: false,
+    showTableSetting: true,
+    tableSetting: { setting: true },
     beforeFetch(params: Recordable) {
       Object.assign(params, {
         variableCode: route.query.id,
@@ -48,14 +50,19 @@
 </script>
 
 <template>
-  <PageWrapper content-full-height content-background contentClass="p-24px">
-    <div class="mb-15px">
-      <a-button type="primary" shape="circle" @click="router.back()" class="mr-10px -mt-8px">
+  <PageWrapper content-full-height>
+    <div class="mb-15px py-24px px-10px bg-white">
+      <a-button
+        type="primary"
+        shape="circle"
+        @click="router.back()"
+        class="float-right mr-10px -mt-8px"
+      >
         <Icon icon="ant-design:arrow-left-outlined" />
       </a-button>
       <span class="app-bar">Variable "{{ route.query.id }}" used list</span>
     </div>
-    <BasicTable v-bind="tableConfig" />
+    <BasicTable @register="registerTable" />
   </PageWrapper>
 </template>
 
diff --git a/streampark-console/streampark-console-newui/src/views/system/variable/View.vue b/streampark-console/streampark-console-newui/src/views/system/variable/View.vue
index 90744f456..1e58ea9eb 100644
--- a/streampark-console/streampark-console-newui/src/views/system/variable/View.vue
+++ b/streampark-console/streampark-console-newui/src/views/system/variable/View.vue
@@ -23,6 +23,7 @@
           {{ t('common.add') }}
         </a-button>
       </template>
+      <template #resetBefore> 1111 </template>
       <template #bodyCell="{ column, record }">
         <template v-if="column.dataIndex === 'action'">
           <TableAction
diff --git a/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableDrawer.vue b/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableDrawer.vue
index 8a6f70b53..96b77de1c 100644
--- a/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableDrawer.vue
+++ b/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableDrawer.vue
@@ -103,8 +103,9 @@
       {
         field: 'variableValue',
         label: t('system.variable.table.variableValue'),
-        component: 'Input',
-        rules: [{ required: true, max: 100, message: 'please enter Variable Value' }],
+        component: 'InputTextArea',
+        componentProps: { rows: 4, placeholder: 'Please enter Variable Value' },
+        rules: [{ required: true, message: 'please enter Variable Value' }],
       },
       {
         field: 'description',
diff --git a/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableInfo.vue b/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableInfo.vue
index cd35960b7..c3525b673 100644
--- a/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableInfo.vue
+++ b/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableInfo.vue
@@ -27,6 +27,7 @@
       Variable Info
     </template>
     <Description
+      class="variable-desc"
       @register="registerDescription"
       :column="1"
       :data="variableInfo"
@@ -90,3 +91,10 @@
     closeDrawer();
   }
 </script>
+<style lang="less">
+  .variable-desc {
+    .ant-descriptions-item-label {
+      min-width: 160px;
+    }
+  }
+</style>