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 a0453e66e feat: add spark home (#3977)
a0453e66e is described below

commit a0453e66ef21a7fe4b19486d0ffe955da6f10c0b
Author: Kriszu <[email protected]>
AuthorDate: Wed Aug 21 08:05:28 2024 +0800

    feat: add spark home (#3977)
---
 .../src/api/spark/home.ts                          |  87 +++++++++++
 .../src/api/spark/home.type.ts                     |  37 +++++
 .../src/enums/sparkEnum.ts                         |   7 +
 .../src/locales/lang/en/spark/home.ts              |  45 ++++++
 .../src/locales/lang/zh-CN/spark/home.ts           |  43 +++++
 .../src/views/spark/app.vue                        |  26 +++
 .../src/views/spark/components/Modal.vue           | 172 ++++++++++++++++++++
 .../src/views/spark/components/index.ts            |  17 ++
 .../src/views/spark/home.vue                       | 174 +++++++++++++++++++++
 9 files changed, 608 insertions(+)

diff --git a/streampark-console/streampark-console-webapp/src/api/spark/home.ts 
b/streampark-console/streampark-console-webapp/src/api/spark/home.ts
new file mode 100644
index 000000000..5ff145196
--- /dev/null
+++ b/streampark-console/streampark-console-webapp/src/api/spark/home.ts
@@ -0,0 +1,87 @@
+/*
+ * 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 { SparkCreate, SparkEnv } from './home.type';
+import { defHttp } from '/@/utils/http/axios';
+
+enum FLINK_API {
+  LIST = '/spark/env/list',
+  CHECK = '/spark/env/check',
+  CREATE = '/spark/env/create',
+  UPDATE = '/spark/env/update',
+  DELETE = '/spark/env/delete',
+  DEFAULT = '/spark/env/default',
+}
+/**
+ * spark environment data
+ * @returns Promise<SparkEnv[]>
+ */
+export function fetchSparkEnvList() {
+  return defHttp.post<SparkEnv[]>({
+    url: FLINK_API.LIST,
+  });
+}
+
+/**
+ * Set the default
+ * @param {String} id
+ */
+export function fetchSetDefault(id: string) {
+  return defHttp.post({
+    url: FLINK_API.DEFAULT,
+    data: { id },
+  });
+}
+
+/**
+ * delete flink env
+ * @param {String} id
+ */
+export function fetchSparkEnvRemove(id: string) {
+  return defHttp.post({
+    url: FLINK_API.DELETE,
+    data: { id },
+  });
+}
+
+/**
+ * Check if the environment exists
+ * @param {Recordable} data
+ */
+export function fetchSparkEnvCheck(data: {
+  id: string | null;
+  sparkName: string;
+  sparkHome: string;
+}) {
+  return defHttp.post({ url: FLINK_API.CHECK, data });
+}
+
+/**
+ * Create spark
+ *
+ */
+export function fetchSparkEnvCreate(data: SparkCreate) {
+  return defHttp.post({ url: FLINK_API.CREATE, data }, { isTransformResponse: 
false });
+}
+
+/**
+ * update spark
+ * @param data
+ */
+export function fetchSparkEnvUpdate(data: SparkCreate) {
+  return defHttp.post({ url: FLINK_API.UPDATE, data }, { isTransformResponse: 
false });
+}
diff --git 
a/streampark-console/streampark-console-webapp/src/api/spark/home.type.ts 
b/streampark-console/streampark-console-webapp/src/api/spark/home.type.ts
new file mode 100644
index 000000000..fa9dfc5dd
--- /dev/null
+++ b/streampark-console/streampark-console-webapp/src/api/spark/home.type.ts
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+// flink home data
+export interface SparkEnv {
+  id: string;
+  sparkName: string;
+  sparkHome: string;
+  sparkConf: string;
+  description: string;
+  scalaVersion: string;
+  version: string;
+  isDefault: boolean;
+  createTime: string;
+  streamParkScalaVersion: string;
+  versionOfMiddle?: any;
+}
+
+export interface SparkCreate {
+  id?: string | null;
+  flinkName: string;
+  flinkHome: string;
+  description: string;
+}
diff --git 
a/streampark-console/streampark-console-webapp/src/enums/sparkEnum.ts 
b/streampark-console/streampark-console-webapp/src/enums/sparkEnum.ts
new file mode 100644
index 000000000..96e1d180a
--- /dev/null
+++ b/streampark-console/streampark-console-webapp/src/enums/sparkEnum.ts
@@ -0,0 +1,7 @@
+export enum SparkEnvCheckEnum {
+  INVALID_PATH = -1,
+  OK = 0,
+  NAME_REPEATED = 1,
+  SPARK_DIST_NOT_FOUND = 2,
+  SPARK_DIST_REPEATED = 3,
+}
diff --git 
a/streampark-console/streampark-console-webapp/src/locales/lang/en/spark/home.ts
 
b/streampark-console/streampark-console-webapp/src/locales/lang/en/spark/home.ts
new file mode 100644
index 000000000..878e55e6f
--- /dev/null
+++ 
b/streampark-console/streampark-console-webapp/src/locales/lang/en/spark/home.ts
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+export default {
+  title: 'Spark Home',
+  tips: {
+    remove: 'The current spark home has been successfully deleted.',
+    setDefault: 'Successfully set the default spark home.',
+    sparkName: 'Spark alias, for example: Spark-1.12',
+    sparkHome:
+      'The absolute path of the server where Spark is located, for example: 
/usr/local/spark',
+    sparkNameIsRequired: 'Spark name is required',
+    sparkHomeIsRequired: 'Spark Home is required',
+    sparkNameIsRepeated: 'Spark name already exists',
+    sparkHomePathIsInvalid: 'Spark Home path is invalid',
+    sparkDistNotFound: 'spark-dist jar file not found in spark/lib path',
+    sparkDistIsRepeated:
+      'Multiple spark-dist jar files exist in spark/lib path, there must be 
only one!',
+    createSparkHomeSuccessful: 'Creation successful!',
+    updateSparkHomeSuccessful: 'Update successful!',
+  },
+  form: {
+    sparkName: 'Spark Name',
+    sparkHome: 'Installation Path',
+    description: 'Description',
+  },
+  placeholder: {
+    sparkName: 'Please enter Spark alias',
+    sparkHome: 'Please enter Spark installation path',
+    description: 'Spark description',
+  },
+};
diff --git 
a/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/spark/home.ts
 
b/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/spark/home.ts
new file mode 100644
index 000000000..1f18dc9c3
--- /dev/null
+++ 
b/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/spark/home.ts
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+export default {
+  title: 'Spark Home',
+  tips: {
+    remove: '当前的 spark home 已被成功删除。',
+    setDefault: '成功设置默认spark home',
+    sparkName: 'Spark别名,举例: Spark-1.12',
+    sparkHome: 'Spark所在服务器的绝对路径,举例: /usr/local/spark',
+    sparkNameIsRequired: 'Spark名称必填',
+    sparkHomeIsRequired: 'Spark Home 不能为空',
+    sparkNameIsRepeated: 'Spark名称已存在',
+    sparkHomePathIsInvalid: 'Spark Home路径无效',
+    sparkDistNotFound: 'spark/lib 路径下未找到 spark-dist jar文件',
+    sparkDistIsRepeated: 'spark/lib 路径下存在多个spark-dist jar文件, 必须只能有一个!',
+    createSparkHomeSuccessful: '创建成功!',
+    updateSparkHomeSuccessful: '更新成功!',
+  },
+  form: {
+    sparkName: 'Spark 名称',
+    sparkHome: '安装路径',
+    description: '描述',
+  },
+  placeholder: {
+    sparkName: '请输入Spark别名',
+    sparkHome: '请输入Spark安装路径',
+    description: 'Spark描述',
+  },
+};
diff --git 
a/streampark-console/streampark-console-webapp/src/views/spark/app.vue 
b/streampark-console/streampark-console-webapp/src/views/spark/app.vue
new file mode 100644
index 000000000..67aa94dd8
--- /dev/null
+++ b/streampark-console/streampark-console-webapp/src/views/spark/app.vue
@@ -0,0 +1,26 @@
+<!--
+  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" setup>
+  defineOptions({
+    name: 'SparkApplication',
+  });
+</script>
+<template>
+  <PageWrapper contentFullHeight>
+    <div>Coming soon</div>
+  </PageWrapper>
+</template>
diff --git 
a/streampark-console/streampark-console-webapp/src/views/spark/components/Modal.vue
 
b/streampark-console/streampark-console-webapp/src/views/spark/components/Modal.vue
new file mode 100644
index 000000000..4e0aa1d2c
--- /dev/null
+++ 
b/streampark-console/streampark-console-webapp/src/views/spark/components/Modal.vue
@@ -0,0 +1,172 @@
+<!--
+  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" setup>
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { h, ref } from 'vue';
+  import { BasicForm, useForm } from '/@/components/Form';
+  import { SvgIcon } from '/@/components/Icon';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { SparkEnvCheckEnum } from '/@/enums/sparkEnum';
+  import { fetchSparkEnvCheck, fetchSparkEnvUpdate } from '/@/api/spark/home';
+  import { fetchSparkEnvCreate } from '/@/api/spark/home';
+
+  defineOptions({
+    name: 'FlinkModal',
+  });
+  const emit = defineEmits(['reload', 'register']);
+  const versionId = ref<string | null>(null);
+  const { t } = useI18n();
+  const { Swal } = useMessage();
+  const [registerForm, { setFieldsValue, validate, resetFields }] = useForm({
+    labelWidth: 120,
+    colon: true,
+    showActionButtonGroup: false,
+    labelCol: { lg: 7, sm: 7 },
+    wrapperCol: { lg: 16, sm: 4 },
+    baseColProps: { span: 24 },
+    schemas: [
+      {
+        field: 'sparkName',
+        label: t('spark.home.form.sparkName'),
+        component: 'Input',
+        componentProps: {
+          placeholder: t('spark.home.placeholder.sparkName'),
+          allowClear: true,
+        },
+        afterItem: () => h('span', { class: 'tip-info' }, 
t('spark.home.tips.sparkName')),
+        rules: [{ required: true, message: 
t('spark.home.tips.sparkNameIsRequired') }],
+      },
+      {
+        field: 'sparkHome',
+        label: t('spark.home.form.sparkHome'),
+        component: 'Input',
+        componentProps: {
+          placeholder: t('spark.home.placeholder.sparkHome'),
+          allowClear: true,
+        },
+        afterItem: () => h('span', { class: 'tip-info' }, 
t('spark.home.tips.sparkHome')),
+        rules: [{ required: true, message: 
t('spark.home.tips.sparkHomeIsRequired') }],
+      },
+      {
+        field: 'description',
+        label: t('spark.home.form.description'),
+        component: 'InputTextArea',
+        componentProps: {
+          placeholder: t('spark.home.placeholder.description'),
+          allowClear: true,
+        },
+      },
+    ],
+  });
+  const [registerModalInner, { changeOkLoading, closeModal }] = 
useModalInner(async (data) => {
+    resetFields();
+    if (data) {
+      versionId.value = data.versionId;
+      setFieldsValue(data);
+    }
+  });
+
+  /* form submit */
+  async function handleSubmit() {
+    changeOkLoading(true);
+    let formValue;
+    try {
+      formValue = await validate();
+    } catch (error) {
+      console.warn('validate error:', error);
+      return;
+    } finally {
+      changeOkLoading(false);
+    }
+    // Detection environment
+    const { data: resp } = await fetchSparkEnvCheck({
+      id: versionId.value,
+      sparkName: formValue.sparkName,
+      sparkHome: formValue.sparkHome,
+    });
+    const checkResp = parseInt(resp.data);
+    if (checkResp !== SparkEnvCheckEnum.OK) {
+      switch (checkResp) {
+        case SparkEnvCheckEnum.INVALID_PATH:
+          Swal.fire('Failed', t('spark.home.tips.sparkHomePathIsInvalid'), 
'error');
+          break;
+        case SparkEnvCheckEnum.NAME_REPEATED:
+          Swal.fire('Failed', t('spark.home.tips.sparkNameIsRepeated'), 
'error');
+          break;
+        case SparkEnvCheckEnum.SPARK_DIST_NOT_FOUND:
+          Swal.fire('Failed', t('spark.home.tips.sparkDistNotFound'), 'error');
+          break;
+        case SparkEnvCheckEnum.SPARK_DIST_REPEATED:
+          Swal.fire('Failed', t('spark.home.tips.sparkDistIsRepeated'), 
'error');
+          break;
+      }
+      changeOkLoading(false);
+      return;
+    }
+
+    try {
+      let message: string;
+      let success = false;
+      // create
+      if (versionId.value == null) {
+        const res = await fetchSparkEnvCreate(formValue);
+        if (res.data) {
+          success = true;
+          message = 
formValue.flinkName.concat(t('spark.home.tips.createSparkHomeSuccessful'));
+        } else {
+          message = res.message;
+        }
+      } else {
+        // update
+        const res = await fetchSparkEnvUpdate({
+          id: versionId.value,
+          ...formValue,
+        });
+        if (res.data) {
+          message = 
formValue.flinkName.concat(t('spark.home.tips.updateSparkHomeSuccessful'));
+          success = true;
+        } else {
+          message = res.message;
+        }
+      }
+      if (success) {
+        Swal.fire({
+          icon: 'success',
+          title: message,
+          showConfirmButton: false,
+          timer: 2000,
+        });
+        closeModal();
+        emit('reload');
+      } else {
+        Swal.fire('Failed', message.replaceAll(/\[StreamPark]/g, ''), 'error');
+      }
+    } finally {
+      changeOkLoading(false);
+    }
+  }
+</script>
+<template>
+  <BasicModal @register="registerModalInner" v-bind="$attrs" 
@ok="handleSubmit">
+    <template #title>
+      <SvgIcon name="spark" />
+      {{ t('common.add') }}
+    </template>
+    <BasicForm @register="registerForm" />
+  </BasicModal>
+</template>
diff --git 
a/streampark-console/streampark-console-webapp/src/views/spark/components/index.ts
 
b/streampark-console/streampark-console-webapp/src/views/spark/components/index.ts
new file mode 100644
index 000000000..fc6df83d1
--- /dev/null
+++ 
b/streampark-console/streampark-console-webapp/src/views/spark/components/index.ts
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+export { default as SparkEnvModal } from './Modal.vue';
diff --git 
a/streampark-console/streampark-console-webapp/src/views/spark/home.vue 
b/streampark-console/streampark-console-webapp/src/views/spark/home.vue
new file mode 100644
index 000000000..94b7fe88a
--- /dev/null
+++ b/streampark-console/streampark-console-webapp/src/views/spark/home.vue
@@ -0,0 +1,174 @@
+<!--
+  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" setup>
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { onMounted, ref } from 'vue';
+  import { useModal } from '/@/components/Modal';
+  import { SvgIcon } from '/@/components/Icon';
+  import { List, Switch, Card, Popconfirm, Tooltip } from 'ant-design-vue';
+  import {
+    CheckOutlined,
+    CloseOutlined,
+    DeleteOutlined,
+    EditOutlined,
+    PlusOutlined,
+  } from '@ant-design/icons-vue';
+  import { SparkEnvModal } from './components';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
+  import { BasicTitle } from '/@/components/Basic';
+  import { fetchSetDefault, fetchSparkEnvList, fetchSparkEnvRemove } from 
'/@/api/spark/home';
+  import { SparkEnv } from '/@/api/spark/home.type';
+
+  defineOptions({
+    name: 'SparkEnvSetting',
+  });
+
+  const { t } = useI18n();
+  const versionId = ref<string | null>(null);
+  const { Swal, createMessage } = useMessage();
+  const sparkEnvs = ref<SparkEnv[]>([]);
+  const [registerModal, { openModal: openFlinkModal }] = useModal();
+  /* Edit button */
+  async function handleEditSpark(item: SparkEnv) {
+    versionId.value = item.id;
+    openFlinkModal(true, {
+      versionId: item.id,
+      sparkName: item.sparkName,
+      sparkHome: item.sparkHome,
+      description: item.description || null,
+    });
+  }
+
+  /* delete spark home */
+  async function handleDelete(item: SparkEnv) {
+    await fetchSparkEnvRemove(item.id);
+    await getSparkEnv();
+    createMessage.success(t('spark.home.tips.remove'));
+  }
+
+  /* set as default environment */
+  async function handleSetDefault(item: SparkEnv) {
+    if (item.isDefault) {
+      await fetchSetDefault(item.id);
+      Swal.fire({
+        icon: 'success',
+        title: item.sparkName.concat(t('spark.home.tips.setDefault')),
+        showConfirmButton: false,
+        timer: 2000,
+      });
+      getSparkEnv();
+    }
+  }
+
+  /* Get spark environment data */
+  async function getSparkEnv() {
+    sparkEnvs.value = await fetchSparkEnvList();
+  }
+
+  onMounted(() => {
+    getSparkEnv();
+  });
+</script>
+<template>
+  <PageWrapper contentFullHeight>
+    <Card :bordered="false">
+      <BasicTitle>{{ t('spark.home.title') }}</BasicTitle>
+      <div>
+        <a-button
+          type="dashed"
+          style="width: 100%; margin-top: 20px"
+          @click="openFlinkModal(true, {})"
+        >
+          <PlusOutlined />
+          {{ t('common.add') }}
+        </a-button>
+      </div>
+      <List>
+        <List.Item v-for="(item, index) in sparkEnvs" :key="index">
+          <List.Item.Meta
+            style="width: 60%"
+            :title="item.sparkName"
+            :description="item.description"
+          >
+            <template #avatar>
+              <SvgIcon class="avatar p-15px" name="spark" size="60" />
+            </template>
+          </List.Item.Meta>
+
+          <div class="list-content flex" style="width: 40%">
+            <div class="list-content-item" style="width: 60%">
+              <span>{{ t('spark.home.title') }}</span>
+              <p style="margin-top: 10px">
+                {{ item.sparkHome }}
+              </p>
+            </div>
+            <div class="list-content-item">
+              <span>Default</span>
+              <p style="margin-top: 10px">
+                <Switch
+                  :disabled="item.isDefault"
+                  @click="handleSetDefault(item)"
+                  v-model:checked="item.isDefault"
+                >
+                  <template #checkedChildren>
+                    <CheckOutlined />
+                  </template>
+                  <template #unCheckedChildren>
+                    <CloseOutlined />
+                  </template>
+                </Switch>
+              </p>
+            </div>
+          </div>
+
+          <template #actions>
+            <Tooltip :title="t('common.edit')">
+              <a-button
+                @click="handleEditSpark(item)"
+                shape="circle"
+                size="large"
+                class="control-button"
+              >
+                <EditOutlined />
+              </a-button>
+            </Tooltip>
+            <Popconfirm
+              :title="t('common.delText')"
+              :cancel-text="t('common.no')"
+              :ok-text="t('common.yes')"
+              @confirm="handleDelete(item)"
+            >
+              <a-button
+                :disabled="item.isDefault && sparkEnvs.length > 1"
+                type="danger"
+                shape="circle"
+                size="large"
+                class="control-button"
+              >
+                <DeleteOutlined />
+              </a-button>
+            </Popconfirm>
+          </template>
+        </List.Item>
+      </List>
+    </Card>
+
+    <SparkEnvModal @register="registerModal" @reload="getSparkEnv" />
+  </PageWrapper>
+</template>
+<style lang="less"></style>

Reply via email to