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>