Browse Source

[Feature] Optimizing data source centers (#12292)

* feat: Optimizing data source centers

* add e2e class

* update datasource e2e

* fix hive e2e

* fix: Modify the source type parameter

Co-authored-by: caishunfeng <caishunfeng2021@gmail.com>
3.2.0-release
labbomb 2 years ago committed by GitHub
parent
commit
a11892aea0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/HiveDataSourceE2ETest.java
  2. 16
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/datasource/DataSourcePage.java
  3. 6
      dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java
  4. 26
      dolphinscheduler-ui/src/components/modal/index.tsx
  5. 1
      dolphinscheduler-ui/src/locales/en_US/datasource.ts
  6. 9
      dolphinscheduler-ui/src/locales/zh_CN/datasource.ts
  7. 2
      dolphinscheduler-ui/src/locales/zh_CN/menu.ts
  8. 14
      dolphinscheduler-ui/src/service/modules/data-source/types.ts
  9. 46
      dolphinscheduler-ui/src/views/datasource/list/detail.tsx
  10. 56
      dolphinscheduler-ui/src/views/datasource/list/index.module.scss
  11. 30
      dolphinscheduler-ui/src/views/datasource/list/index.tsx
  12. 93
      dolphinscheduler-ui/src/views/datasource/list/source-modal.tsx
  13. 1
      dolphinscheduler-ui/src/views/datasource/list/use-form.ts

2
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/HiveDataSourceE2ETest.java

@ -46,7 +46,7 @@ public class HiveDataSourceE2ETest {
private static final String password = "dolphinscheduler123"; private static final String password = "dolphinscheduler123";
private static final String dataSourceType = "HIVE"; private static final String dataSourceType = "HIVE/IMPALA";
private static final String dataSourceName = "hive_test"; private static final String dataSourceName = "hive_test";

16
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/datasource/DataSourcePage.java

@ -56,6 +56,11 @@ public class DataSourcePage extends NavBarPage implements NavBarPage.NavBarItem
}) })
private WebElement buttonConfirm; private WebElement buttonConfirm;
@FindBys({
@FindBy(className = "dialog-source-modal"),
})
private WebElement dataSourceModal;
private final CreateDataSourceForm createDataSourceForm; private final CreateDataSourceForm createDataSourceForm;
public DataSourcePage(RemoteWebDriver driver) { public DataSourcePage(RemoteWebDriver driver) {
@ -69,19 +74,12 @@ public class DataSourcePage extends NavBarPage implements NavBarPage.NavBarItem
buttonCreateDataSource().click(); buttonCreateDataSource().click();
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated( new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(
new By.ByClassName("dialog-create-data-source"))); new By.ByClassName("dialog-source-modal")));
createDataSourceForm().btnDataSourceTypeDropdown().click(); dataSourceModal().findElement(By.className(dataSourceType.toUpperCase()+"-box")).click();
new WebDriverWait(driver, 10).until(ExpectedConditions.textToBePresentInElement(driver.findElement(By.className("dialog-create-data-source")), dataSourceType.toUpperCase())); new WebDriverWait(driver, 10).until(ExpectedConditions.textToBePresentInElement(driver.findElement(By.className("dialog-create-data-source")), dataSourceType.toUpperCase()));
createDataSourceForm().selectDataSourceType()
.stream()
.filter(it -> it.getText().contains(dataSourceType.toUpperCase()))
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("No %s in data source type list", dataSourceType.toUpperCase())))
.click();
createDataSourceForm().inputDataSourceName().sendKeys(dataSourceName); createDataSourceForm().inputDataSourceName().sendKeys(dataSourceName);
createDataSourceForm().inputDataSourceDescription().sendKeys(dataSourceDescription); createDataSourceForm().inputDataSourceDescription().sendKeys(dataSourceDescription);
createDataSourceForm().inputIP().sendKeys(ip); createDataSourceForm().inputIP().sendKeys(ip);

6
dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java

@ -67,6 +67,8 @@ final class DolphinSchedulerExtension implements BeforeAllCallback, AfterAllCall
private final boolean M1_CHIP_FLAG = Objects.equals(System.getProperty("m1_chip"), "true"); private final boolean M1_CHIP_FLAG = Objects.equals(System.getProperty("m1_chip"), "true");
private final int LOCAL_PORT = 5173;
private RemoteWebDriver driver; private RemoteWebDriver driver;
private DockerComposeContainer<?> compose; private DockerComposeContainer<?> compose;
private BrowserWebDriverContainer<?> browser; private BrowserWebDriverContainer<?> browser;
@ -117,8 +119,8 @@ final class DolphinSchedulerExtension implements BeforeAllCallback, AfterAllCall
} }
private void runInLocal() { private void runInLocal() {
Testcontainers.exposeHostPorts(3000); Testcontainers.exposeHostPorts(LOCAL_PORT);
address = HostAndPort.fromParts("host.testcontainers.internal", 3000); address = HostAndPort.fromParts("host.testcontainers.internal", LOCAL_PORT);
rootPath = "/"; rootPath = "/";
} }

26
dolphinscheduler-ui/src/components/modal/index.tsx

@ -38,6 +38,10 @@ const props = {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
default: true default: true
}, },
confirmShow: {
type: Boolean as PropType<boolean>,
default: true
},
confirmText: { confirmText: {
type: String as PropType<string> type: String as PropType<string>
}, },
@ -136,16 +140,18 @@ const Modal = defineComponent({
)} )}
{/* TODO: Add left and right slots later */} {/* TODO: Add left and right slots later */}
{renderSlot($slots, 'btn-middle')} {renderSlot($slots, 'btn-middle')}
<NButton {this.confirmShow && (
class={[this.confirmClassName, 'btn-submit']} <NButton
type='info' class={[this.confirmClassName, 'btn-submit']}
size='small' type='info'
onClick={onConfirm} size='small'
disabled={confirmDisabled} onClick={onConfirm}
loading={confirmLoading} disabled={confirmDisabled}
> loading={confirmLoading}
{this.confirmText || t('modal.confirm')} >
</NButton> {this.confirmText || t('modal.confirm')}
</NButton>
)}
</NSpace> </NSpace>
) )
}} }}

1
dolphinscheduler-ui/src/locales/en_US/datasource.ts

@ -18,6 +18,7 @@
export default { export default {
datasource: 'DataSource', datasource: 'DataSource',
create_datasource: 'Create DataSource', create_datasource: 'Create DataSource',
choose_datasource_type: 'Choose DataSource Type',
search_input_tips: 'Please input the keywords', search_input_tips: 'Please input the keywords',
datasource_name: 'Datasource Name', datasource_name: 'Datasource Name',
datasource_name_tips: 'Please enter datasource name', datasource_name_tips: 'Please enter datasource name',

9
dolphinscheduler-ui/src/locales/zh_CN/datasource.ts

@ -17,13 +17,14 @@
export default { export default {
datasource: '数据源', datasource: '数据源',
create_datasource: '创建数据源', create_datasource: '创建源',
choose_datasource_type: '选择源类型',
search_input_tips: '请输入关键字', search_input_tips: '请输入关键字',
datasource_name: '数据源名称', datasource_name: '源名称',
datasource_name_tips: '请输入数据源名称', datasource_name_tips: '请输入数据源名称',
datasource_user_name: '所属用户', datasource_user_name: '所属用户',
datasource_type: '数据源类型', datasource_type: '源类型',
datasource_parameter: '数据源参数', datasource_parameter: '参数',
description: '描述', description: '描述',
description_tips: '请输入描述', description_tips: '请输入描述',
test_datasource: '测试数据源', test_datasource: '测试数据源',

2
dolphinscheduler-ui/src/locales/zh_CN/menu.ts

@ -19,7 +19,7 @@ export default {
home: '首页', home: '首页',
project: '项目管理', project: '项目管理',
resources: '资源中心', resources: '资源中心',
datasource: '数据源中心', datasource: '源中心',
monitor: '监控中心', monitor: '监控中心',
security: '安全中心', security: '安全中心',
ui_setting: '界面设置', ui_setting: '界面设置',

14
dolphinscheduler-ui/src/service/modules/data-source/types.ts

@ -28,9 +28,23 @@ type IDataBase =
| 'REDSHIFT' | 'REDSHIFT'
| 'ATHENA' | 'ATHENA'
type IDataBaseLabel =
| 'MYSQL'
| 'POSTGRESQL'
| 'HIVE'
| 'SPARK'
| 'CLICKHOUSE'
| 'ORACLE'
| 'SQLSERVER'
| 'DB2'
| 'PRESTO'
| 'REDSHIFT'
| 'ATHENA'
interface IDataSource { interface IDataSource {
id?: number id?: number
type?: IDataBase type?: IDataBase
label?: IDataBaseLabel
name?: string name?: string
note?: string note?: string
host?: string host?: string

46
dolphinscheduler-ui/src/views/datasource/list/detail.tsx

@ -36,8 +36,9 @@ import {
} from 'naive-ui' } from 'naive-ui'
import Modal from '@/components/modal' import Modal from '@/components/modal'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useForm, datasourceType, datasourceTypeList } from './use-form' import { useForm, datasourceType } from './use-form'
import { useDetail } from './use-detail' import { useDetail } from './use-detail'
import styles from './index.module.scss'
const props = { const props = {
show: { show: {
@ -46,13 +47,17 @@ const props = {
}, },
id: { id: {
type: Number as PropType<number> type: Number as PropType<number>
},
selectType: {
type: String as PropType<any>,
default: 'MYSQL'
} }
} }
const DetailModal = defineComponent({ const DetailModal = defineComponent({
name: 'DetailModal', name: 'DetailModal',
props, props,
emits: ['cancel', 'update'], emits: ['cancel', 'update', 'open'],
setup(props, ctx) { setup(props, ctx) {
const { t } = useI18n() const { t } = useI18n()
@ -95,9 +100,15 @@ const DetailModal = defineComponent({
const trim = getCurrentInstance()?.appContext.config.globalProperties.trim const trim = getCurrentInstance()?.appContext.config.globalProperties.trim
const handleSourceModalOpen = () => {
ctx.emit('open')
}
watch( watch(
() => props.show, () => props.show,
async () => { async () => {
state.detailForm.type = props.selectType
state.detailForm.label = props.selectType === 'HIVE' ? 'HIVE/IMPALA' : props.selectType
props.show && props.show &&
state.detailForm.type && state.detailForm.type &&
(await changeType( (await changeType(
@ -109,6 +120,19 @@ const DetailModal = defineComponent({
} }
) )
watch(
() => props.selectType,
async () => {
state.detailForm.type = props.selectType
state.detailForm.label = props.selectType === 'HIVE' ? 'HIVE/IMPALA' : props.selectType
state.detailForm.type &&
(await changeType(
state.detailForm.type,
datasourceType[state.detailForm.type]
))
}
)
return { return {
t, t,
...toRefs(state), ...toRefs(state),
@ -119,7 +143,8 @@ const DetailModal = defineComponent({
onSubmit, onSubmit,
onTest, onTest,
onCancel, onCancel,
trim trim,
handleSourceModalOpen
} }
}, },
render() { render() {
@ -138,12 +163,12 @@ const DetailModal = defineComponent({
loading, loading,
saving, saving,
testing, testing,
onChangeType,
onChangeTestFlag, onChangeTestFlag,
onChangePort, onChangePort,
onCancel, onCancel,
onTest, onTest,
onSubmit onSubmit,
handleSourceModalOpen
} = this } = this
return ( return (
<Modal <Modal
@ -172,13 +197,10 @@ const DetailModal = defineComponent({
path='type' path='type'
show-require-mark show-require-mark
> >
<NSelect <div class={[styles.typeBox, !!id && styles.disabledBox]}>
class='btn-data-source-type-drop-down' <div v-model={[detailForm.type, 'value']}>{detailForm.label}</div>
v-model={[detailForm.type, 'value']} <div class={[styles['text-color'], 'btn-data-source-type-drop-down']} onClick={handleSourceModalOpen}></div>
options={datasourceTypeList} </div>
disabled={!!id}
on-update:value={onChangeType}
/>
</NFormItem> </NFormItem>
<NFormItem <NFormItem
label={t('datasource.datasource_name')} label={t('datasource.datasource_name')}

56
dolphinscheduler-ui/src/views/datasource/list/index.module.scss

@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.content {
display: flex;
flex-wrap: wrap;
.itemBox {
padding: 5px 14px;
border: 1px solid rgb(224, 224, 230);
width: 120px;
text-align: center;
cursor: pointer;
&:hover {
color: #40a9ff;
border: 1px solid #40a9ff;
}
}
}
.typeBox {
display: flex;
justify-content: space-between;
width: 100%;
padding: 5px 14px;
border: 1px solid rgb(224, 224, 230);
&:hover {
border: 1px solid #40a9ff;
}
.text-color {
color: #1890ff;
cursor: pointer;
}
}
.disabledBox {
pointer-events: none;
opacity: 0.5;
}

30
dolphinscheduler-ui/src/views/datasource/list/index.tsx

@ -39,12 +39,15 @@ import { DefaultTableWidth } from '@/common/column-width-config'
import Card from '@/components/card' import Card from '@/components/card'
import DetailModal from './detail' import DetailModal from './detail'
import type { TableColumns } from './types' import type { TableColumns } from './types'
import SourceModal from './source-modal'
const list = defineComponent({ const list = defineComponent({
name: 'list', name: 'list',
setup() { setup() {
const { t } = useI18n() const { t } = useI18n()
const showDetailModal = ref(false) const showDetailModal = ref(false)
const showSourceModal = ref(false)
const selectType = ref('MYSQL')
const selectId = ref() const selectId = ref()
const columns = ref({ const columns = ref({
columns: [] as TableColumns, columns: [] as TableColumns,
@ -64,11 +67,21 @@ const list = defineComponent({
const onCreate = () => { const onCreate = () => {
selectId.value = null selectId.value = null
showDetailModal.value = true showSourceModal.value = true
} }
const trim = getCurrentInstance()?.appContext.config.globalProperties.trim const trim = getCurrentInstance()?.appContext.config.globalProperties.trim
const handleSelectSourceType = (value: string) => {
selectType.value = value
showSourceModal.value = false
showDetailModal.value = true
}
const handleSourceModalOpen = () => {
showSourceModal.value = true
}
onMounted(() => { onMounted(() => {
changePage(1) changePage(1)
columns.value = getColumns() columns.value = getColumns()
@ -81,6 +94,7 @@ const list = defineComponent({
return { return {
t, t,
showDetailModal, showDetailModal,
showSourceModal,
id: selectId, id: selectId,
columns, columns,
...toRefs(data), ...toRefs(data),
@ -88,7 +102,10 @@ const list = defineComponent({
changePageSize, changePageSize,
onCreate, onCreate,
onUpdatedList: updateList, onUpdatedList: updateList,
trim trim,
handleSelectSourceType,
selectType,
handleSourceModalOpen
} }
}, },
render() { render() {
@ -96,6 +113,7 @@ const list = defineComponent({
t, t,
id, id,
showDetailModal, showDetailModal,
showSourceModal,
columns, columns,
list, list,
page, page,
@ -105,7 +123,10 @@ const list = defineComponent({
changePage, changePage,
changePageSize, changePageSize,
onCreate, onCreate,
onUpdatedList onUpdatedList,
handleSelectSourceType,
selectType,
handleSourceModalOpen
} = this } = this
return ( return (
@ -159,11 +180,14 @@ const list = defineComponent({
</NSpace> </NSpace>
</NSpace> </NSpace>
</Card> </Card>
<SourceModal show={showSourceModal} onChange={handleSelectSourceType}></SourceModal>
<DetailModal <DetailModal
show={showDetailModal} show={showDetailModal}
id={id} id={id}
selectType={selectType}
onCancel={() => void (this.showDetailModal = false)} onCancel={() => void (this.showDetailModal = false)}
onUpdate={onUpdatedList} onUpdate={onUpdatedList}
onOpen={handleSourceModalOpen}
/> />
</NSpace> </NSpace>
) )

93
dolphinscheduler-ui/src/views/datasource/list/source-modal.tsx

@ -0,0 +1,93 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
defineComponent,
PropType,
toRefs
} from 'vue'
import {
NSpace
} from 'naive-ui'
import Modal from '@/components/modal'
import { useI18n } from 'vue-i18n'
import { useForm, datasourceTypeList } from './use-form'
import styles from './index.module.scss'
const props = {
show: {
type: Boolean as PropType<boolean>,
default: false
},
id: {
type: Number as PropType<number>
}
}
const SourceModal = defineComponent({
name: 'SourceModal',
props,
emits: ['change'],
setup(props, ctx) {
const { t } = useI18n()
const { state } = useForm(props.id)
const handleTypeSelect = (value: string) => {
ctx.emit('change', value)
}
return {
t,
...toRefs(state),
handleTypeSelect
}
},
render() {
const {
show,
t,
handleTypeSelect
} = this
return (
<Modal
class='dialog-source-modal'
show={show}
title={t('datasource.choose_datasource_type')}
cancelShow={false}
confirmShow={false}
>
{{
default: () => (
<div class={styles.content}>
<NSpace>
{datasourceTypeList.map((item) => (
<div class={[styles.itemBox, `${item.label}-box`]} onClick={() => handleTypeSelect(item.value)}>
{item.label}
</div>
))}
</NSpace>
</div>
)
}}
</Modal>
)
}
})
export default SourceModal

1
dolphinscheduler-ui/src/views/datasource/list/use-form.ts

@ -36,6 +36,7 @@ export function useForm(id?: number) {
const initialValues = { const initialValues = {
type: 'MYSQL', type: 'MYSQL',
label: 'MYSQL',
name: '', name: '',
note: '', note: '',
host: '', host: '',

Loading…
Cancel
Save