Amy0104
3 years ago
committed by
GitHub
17 changed files with 1328 additions and 40 deletions
@ -0,0 +1,332 @@ |
|||||||
|
/* |
||||||
|
* 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, watch } from 'vue' |
||||||
|
import { |
||||||
|
NButton, |
||||||
|
NSpin, |
||||||
|
NForm, |
||||||
|
NFormItem, |
||||||
|
NSelect, |
||||||
|
NInput, |
||||||
|
NInputNumber, |
||||||
|
NRadioGroup, |
||||||
|
NRadio, |
||||||
|
NSpace |
||||||
|
} from 'naive-ui' |
||||||
|
import Modal from '@/components/modal' |
||||||
|
import { useI18n } from 'vue-i18n' |
||||||
|
import { useForm, datasourceTypeList } from './use-form' |
||||||
|
import { useDetail } from './use-detail' |
||||||
|
|
||||||
|
const props = { |
||||||
|
show: { |
||||||
|
type: Boolean as PropType<boolean>, |
||||||
|
default: false |
||||||
|
}, |
||||||
|
id: { |
||||||
|
type: Number as PropType<number> |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const DetailModal = defineComponent({ |
||||||
|
name: 'DetailModal', |
||||||
|
props, |
||||||
|
emits: ['cancel', 'update'], |
||||||
|
setup(props, ctx) { |
||||||
|
const { t } = useI18n() |
||||||
|
|
||||||
|
const { |
||||||
|
state, |
||||||
|
changeType, |
||||||
|
changePort, |
||||||
|
resetFieldsValue, |
||||||
|
setFieldsValue, |
||||||
|
getFieldsValue |
||||||
|
} = useForm(props.id) |
||||||
|
|
||||||
|
const { status, queryById, testConnect, createOrUpdate } = |
||||||
|
useDetail(getFieldsValue) |
||||||
|
|
||||||
|
const onCancel = () => { |
||||||
|
resetFieldsValue() |
||||||
|
ctx.emit('cancel') |
||||||
|
} |
||||||
|
|
||||||
|
const onSubmit = async () => { |
||||||
|
await state.detailFormRef.validate() |
||||||
|
const res = await createOrUpdate(props.id) |
||||||
|
if (res) { |
||||||
|
onCancel() |
||||||
|
ctx.emit('update') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const onTest = async () => { |
||||||
|
await state.detailFormRef.validate() |
||||||
|
testConnect() |
||||||
|
} |
||||||
|
|
||||||
|
const onChangeType = changeType |
||||||
|
const onChangePort = changePort |
||||||
|
|
||||||
|
watch( |
||||||
|
() => props.show, |
||||||
|
async () => { |
||||||
|
props.show && props.id && setFieldsValue(await queryById(props.id)) |
||||||
|
} |
||||||
|
) |
||||||
|
|
||||||
|
return { |
||||||
|
t, |
||||||
|
...toRefs(state), |
||||||
|
...toRefs(status), |
||||||
|
onChangeType, |
||||||
|
onChangePort, |
||||||
|
onSubmit, |
||||||
|
onTest, |
||||||
|
onCancel |
||||||
|
} |
||||||
|
}, |
||||||
|
render() { |
||||||
|
const { |
||||||
|
show, |
||||||
|
id, |
||||||
|
t, |
||||||
|
detailForm, |
||||||
|
rules, |
||||||
|
requiredDataBase, |
||||||
|
showConnectType, |
||||||
|
showPrincipal, |
||||||
|
loading, |
||||||
|
saving, |
||||||
|
testing, |
||||||
|
onChangeType, |
||||||
|
onChangePort, |
||||||
|
onCancel, |
||||||
|
onTest, |
||||||
|
onSubmit |
||||||
|
} = this |
||||||
|
return ( |
||||||
|
<Modal |
||||||
|
show={show} |
||||||
|
title={`${t(id ? 'datasource.edit' : 'datasource.create')}${t( |
||||||
|
'datasource.datasource' |
||||||
|
)}`}
|
||||||
|
onConfirm={onSubmit} |
||||||
|
confirmLoading={saving || loading} |
||||||
|
onCancel={onCancel} |
||||||
|
> |
||||||
|
{{ |
||||||
|
default: () => ( |
||||||
|
<NSpin show={loading}> |
||||||
|
<NForm |
||||||
|
rules={rules} |
||||||
|
ref='detailFormRef' |
||||||
|
require-mark-placement='left' |
||||||
|
label-placement='left' |
||||||
|
label-width={180} |
||||||
|
label-align='right' |
||||||
|
> |
||||||
|
<NFormItem |
||||||
|
label={t('datasource.datasource')} |
||||||
|
path='type' |
||||||
|
show-require-mark |
||||||
|
> |
||||||
|
<NSelect |
||||||
|
v-model={[detailForm.type, 'value']} |
||||||
|
options={datasourceTypeList} |
||||||
|
disabled={!!id} |
||||||
|
on-update:value={onChangeType} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
label={t('datasource.datasource_name')} |
||||||
|
path='name' |
||||||
|
show-require-mark |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.name, 'value']} |
||||||
|
maxlength={60} |
||||||
|
placeholder={t('datasource.datasource_name_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem label={t('datasource.description')} path='note'> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.note, 'value']} |
||||||
|
type='textarea' |
||||||
|
placeholder={t('datasource.description_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
label={t('datasource.ip')} |
||||||
|
path='host' |
||||||
|
show-require-mark |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.host, 'value']} |
||||||
|
type='text' |
||||||
|
maxlength={255} |
||||||
|
placeholder={t('datasource.ip_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
label={t('datasource.port')} |
||||||
|
path='port' |
||||||
|
show-require-mark |
||||||
|
> |
||||||
|
<NInputNumber |
||||||
|
v-model={[detailForm.port, 'value']} |
||||||
|
show-button={false} |
||||||
|
placeholder={t('datasource.port_tips')} |
||||||
|
on-blur={onChangePort} |
||||||
|
style={{ width: '100%' }} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
v-show={showPrincipal} |
||||||
|
label='Principal' |
||||||
|
path='principal' |
||||||
|
show-require-mark |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.principal, 'value']} |
||||||
|
type='text' |
||||||
|
placeholder={t('datasource.principal_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
v-show={showPrincipal} |
||||||
|
label='krb5.conf' |
||||||
|
path='javaSecurityKrb5Conf' |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.javaSecurityKrb5Conf, 'value']} |
||||||
|
type='text' |
||||||
|
placeholder={t('datasource.krb5_conf_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
v-show={showPrincipal} |
||||||
|
label='keytab.username' |
||||||
|
path='loginUserKeytabUsername' |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.loginUserKeytabUsername, 'value']} |
||||||
|
type='text' |
||||||
|
placeholder={t('datasource.keytab_username_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
v-show={showPrincipal} |
||||||
|
label='keytab.path' |
||||||
|
path='loginUserKeytabPath' |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.loginUserKeytabPath, 'value']} |
||||||
|
type='text' |
||||||
|
placeholder={t('datasource.keytab_path_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
label={t('datasource.user_name')} |
||||||
|
path='userName' |
||||||
|
show-require-mark |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.userName, 'value']} |
||||||
|
type='text' |
||||||
|
maxlength={60} |
||||||
|
placeholder={t('datasource.user_name_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
label={t('datasource.user_password')} |
||||||
|
path='password' |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.password, 'value']} |
||||||
|
type='password' |
||||||
|
placeholder={t('datasource.user_password_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
label={t('datasource.database_name')} |
||||||
|
path='database' |
||||||
|
show-require-mark={requiredDataBase} |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.database, 'value']} |
||||||
|
type='text' |
||||||
|
maxlength={60} |
||||||
|
placeholder={t('datasource.database_name_tips')} |
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
v-show={showConnectType} |
||||||
|
label={t('datasource.oracle_connect_type')} |
||||||
|
path='connectType' |
||||||
|
show-require-mark |
||||||
|
> |
||||||
|
<NRadioGroup v-model={[detailForm.connectType, 'value']}> |
||||||
|
<NSpace> |
||||||
|
<NRadio value='ORACLE_SERVICE_NAME'> |
||||||
|
{t('datasource.oracle_service_name')} |
||||||
|
</NRadio> |
||||||
|
<NRadio value='ORACLE_SID'> |
||||||
|
{t('datasource.oracle_sid')} |
||||||
|
</NRadio> |
||||||
|
</NSpace> |
||||||
|
</NRadioGroup> |
||||||
|
</NFormItem> |
||||||
|
<NFormItem |
||||||
|
label={t('datasource.jdbc_connect_parameters')} |
||||||
|
path='other' |
||||||
|
> |
||||||
|
<NInput |
||||||
|
v-model={[detailForm.other, 'value']} |
||||||
|
type='textarea' |
||||||
|
autosize={{ |
||||||
|
minRows: 2 |
||||||
|
}} |
||||||
|
placeholder={`${t( |
||||||
|
'datasource.format_tips' |
||||||
|
)} {"key1":"value1","key2":"value2"...} ${t( |
||||||
|
'datasource.connection_parameter' |
||||||
|
)}`}
|
||||||
|
/> |
||||||
|
</NFormItem> |
||||||
|
</NForm> |
||||||
|
</NSpin> |
||||||
|
), |
||||||
|
'btn-middle': () => ( |
||||||
|
<NButton |
||||||
|
type='primary' |
||||||
|
size='small' |
||||||
|
onClick={onTest} |
||||||
|
loading={testing || loading} |
||||||
|
> |
||||||
|
{t('datasource.test_connect')} |
||||||
|
</NButton> |
||||||
|
) |
||||||
|
}} |
||||||
|
</Modal> |
||||||
|
) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
export default DetailModal |
@ -0,0 +1,32 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
.conditions { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
.conditions-search-input { |
||||||
|
width: 250px; |
||||||
|
} |
||||||
|
.pagination { |
||||||
|
margin-top: 20px; |
||||||
|
justify-content: center; |
||||||
|
} |
||||||
|
.mt-8 { |
||||||
|
margin-top: 8px; |
||||||
|
} |
@ -0,0 +1,150 @@ |
|||||||
|
/* |
||||||
|
* 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, onMounted, ref, toRefs } from 'vue' |
||||||
|
import { |
||||||
|
NButton, |
||||||
|
NInput, |
||||||
|
NIcon, |
||||||
|
NDataTable, |
||||||
|
NPagination, |
||||||
|
NSpace |
||||||
|
} from 'naive-ui' |
||||||
|
import Card from '@/components/card' |
||||||
|
import DetailModal from './detail' |
||||||
|
import { SearchOutlined } from '@vicons/antd' |
||||||
|
import { useI18n } from 'vue-i18n' |
||||||
|
import { useColumns } from './use-columns' |
||||||
|
import { useTable } from './use-table' |
||||||
|
import styles from './index.module.scss' |
||||||
|
|
||||||
|
const list = defineComponent({ |
||||||
|
name: 'list', |
||||||
|
setup() { |
||||||
|
const { t } = useI18n() |
||||||
|
let showDetailModal = ref(false) |
||||||
|
let selectId = ref() |
||||||
|
|
||||||
|
const { columnsRef } = useColumns((id: number, type: 'edit' | 'delete') => { |
||||||
|
if (type === 'edit') { |
||||||
|
showDetailModal.value = true |
||||||
|
selectId.value = id |
||||||
|
} else { |
||||||
|
deleteRecord(id) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
const { data, changePage, changePageSize, deleteRecord, updateList } = |
||||||
|
useTable() |
||||||
|
|
||||||
|
const onCreate = () => { |
||||||
|
selectId.value = null |
||||||
|
showDetailModal.value = true |
||||||
|
} |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
changePage(1) |
||||||
|
}) |
||||||
|
|
||||||
|
return { |
||||||
|
t, |
||||||
|
showDetailModal, |
||||||
|
id: selectId, |
||||||
|
columnsRef, |
||||||
|
...toRefs(data), |
||||||
|
changePage, |
||||||
|
changePageSize, |
||||||
|
onCreate, |
||||||
|
onUpdatedList: updateList |
||||||
|
} |
||||||
|
}, |
||||||
|
render() { |
||||||
|
const { |
||||||
|
t, |
||||||
|
id, |
||||||
|
showDetailModal, |
||||||
|
columnsRef, |
||||||
|
list, |
||||||
|
page, |
||||||
|
pageSize, |
||||||
|
itemCount, |
||||||
|
loading, |
||||||
|
changePage, |
||||||
|
changePageSize, |
||||||
|
onCreate, |
||||||
|
onUpdatedList |
||||||
|
} = this |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Card title=''> |
||||||
|
{{ |
||||||
|
default: () => ( |
||||||
|
<div class={styles['conditions']}> |
||||||
|
<NButton onClick={onCreate} type='primary'>{`${t( |
||||||
|
'datasource.create_datasource' |
||||||
|
)}`}</NButton>
|
||||||
|
|
||||||
|
<NSpace |
||||||
|
class={styles['conditions-search']} |
||||||
|
justify='end' |
||||||
|
wrap={false} |
||||||
|
> |
||||||
|
<div class={styles['conditions-search-input']}> |
||||||
|
<NInput |
||||||
|
v-model={[this.searchVal, 'value']} |
||||||
|
placeholder={`${t('datasource.search_input_tips')}`} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<NButton type='primary' onClick={onUpdatedList}> |
||||||
|
<NIcon> |
||||||
|
<SearchOutlined /> |
||||||
|
</NIcon> |
||||||
|
</NButton> |
||||||
|
</NSpace> |
||||||
|
</div> |
||||||
|
) |
||||||
|
}} |
||||||
|
</Card> |
||||||
|
<Card title='' class={styles['mt-8']}> |
||||||
|
<NDataTable |
||||||
|
columns={columnsRef} |
||||||
|
data={list} |
||||||
|
loading={loading} |
||||||
|
striped |
||||||
|
/> |
||||||
|
<NPagination |
||||||
|
page={page} |
||||||
|
page-size={pageSize} |
||||||
|
item-count={itemCount} |
||||||
|
show-quick-jumper |
||||||
|
class={styles['pagination']} |
||||||
|
on-update:page={changePage} |
||||||
|
on-update:page-size={changePageSize} |
||||||
|
/> |
||||||
|
</Card> |
||||||
|
<DetailModal |
||||||
|
show={showDetailModal} |
||||||
|
id={id} |
||||||
|
onCancel={() => void (this.showDetailModal = false)} |
||||||
|
onUpdate={onUpdatedList} |
||||||
|
/> |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
|
}) |
||||||
|
export default list |
@ -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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
.json-highlight { |
||||||
|
display: block; |
||||||
|
line-height: 1.5; |
||||||
|
font-size: 12px; |
||||||
|
padding: 5px; |
||||||
|
} |
||||||
|
.line { |
||||||
|
padding-left: 8px; |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* 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, h } from 'vue' |
||||||
|
import { NText } from 'naive-ui' |
||||||
|
import { isBoolean, isNumber, isPlainObject } from 'lodash' |
||||||
|
import styles from './json-highlight.module.scss' |
||||||
|
|
||||||
|
const props = { |
||||||
|
json: { |
||||||
|
type: String as PropType<string>, |
||||||
|
default: '' |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const JsonHighlight = defineComponent({ |
||||||
|
name: 'JsonHighlight', |
||||||
|
props, |
||||||
|
render() { |
||||||
|
return ( |
||||||
|
<pre class={styles['json-highlight']}>{syntaxHighlight(this.json)}</pre> |
||||||
|
) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
const syntaxHighlight = (json: string) => { |
||||||
|
if (!isPlainObject(JSON.parse(json))) return '' |
||||||
|
const lines = [<NText v-html='{'></NText>] |
||||||
|
const entries = Object.entries(JSON.parse(json)) |
||||||
|
for (let i = 0, len = entries.length; i < len; i++) { |
||||||
|
const [key, value] = entries[i] |
||||||
|
let type: string = '' |
||||||
|
if (isBoolean(value) || value === null) { |
||||||
|
type = 'info' |
||||||
|
} else if (isNumber(value)) { |
||||||
|
type = 'warning' |
||||||
|
} else { |
||||||
|
type = 'success' |
||||||
|
} |
||||||
|
lines.push( |
||||||
|
<NText tag='div' class={styles['line']}> |
||||||
|
<NText type='error'>"{key}": </NText> |
||||||
|
<NText type={type}> |
||||||
|
"{value}"{i !== len - 1 ? ',' : ''} |
||||||
|
</NText> |
||||||
|
</NText> |
||||||
|
) |
||||||
|
} |
||||||
|
lines.push(<NText v-html='}'></NText>) |
||||||
|
return lines |
||||||
|
} |
||||||
|
|
||||||
|
export default JsonHighlight |
@ -0,0 +1,47 @@ |
|||||||
|
/* |
||||||
|
* 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 type { |
||||||
|
IDataSource, |
||||||
|
IDataBase |
||||||
|
} from '@/service/modules/data-source/types' |
||||||
|
import type { TableColumns } from 'naive-ui/es/data-table/src/interface' |
||||||
|
import type { SelectBaseOption } from 'naive-ui/es/select/src/interface' |
||||||
|
|
||||||
|
interface IDataSourceDetail extends Omit<IDataSource, 'other'> { |
||||||
|
other?: string |
||||||
|
} |
||||||
|
|
||||||
|
interface IDataBaseOption extends SelectBaseOption { |
||||||
|
label: string |
||||||
|
value: string |
||||||
|
defaultPort: number |
||||||
|
previousPort?: number |
||||||
|
} |
||||||
|
|
||||||
|
type IDataBaseOptionKeys = { |
||||||
|
[key in IDataBase]: IDataBaseOption |
||||||
|
} |
||||||
|
|
||||||
|
export { |
||||||
|
IDataSource, |
||||||
|
IDataSourceDetail, |
||||||
|
IDataBase, |
||||||
|
IDataBaseOption, |
||||||
|
IDataBaseOptionKeys, |
||||||
|
TableColumns |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import { h } from 'vue' |
||||||
|
import { useI18n } from 'vue-i18n' |
||||||
|
import { NPopover, NButton, NIcon, NPopconfirm, NSpace } from 'naive-ui' |
||||||
|
import { EditOutlined, DeleteOutlined } from '@vicons/antd' |
||||||
|
import JsonHighlight from './json-highlight' |
||||||
|
import styles from './index.module.scss' |
||||||
|
import { TableColumns } from './types' |
||||||
|
|
||||||
|
export function useColumns(onCallback: Function) { |
||||||
|
const { t } = useI18n() |
||||||
|
|
||||||
|
const columnsRef: TableColumns = [ |
||||||
|
{ |
||||||
|
title: t('datasource.serial_number'), |
||||||
|
key: 'index', |
||||||
|
render: (rowData, rowIndex) => rowIndex + 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: t('datasource.datasource_name'), |
||||||
|
key: 'name' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: t('datasource.datasource_user_name'), |
||||||
|
key: 'userName' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: t('datasource.datasource_type'), |
||||||
|
key: 'type' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: t('datasource.datasource_parameter'), |
||||||
|
key: 'parameter', |
||||||
|
render: (rowData) => { |
||||||
|
return h( |
||||||
|
NPopover, |
||||||
|
{ trigger: 'click' }, |
||||||
|
{ |
||||||
|
trigger: () => |
||||||
|
h( |
||||||
|
NButton, |
||||||
|
{ |
||||||
|
quaternary: true, |
||||||
|
type: 'primary' |
||||||
|
}, |
||||||
|
{ |
||||||
|
default: () => t('datasource.click_to_view') |
||||||
|
} |
||||||
|
), |
||||||
|
default: () => |
||||||
|
h(JsonHighlight, { json: rowData.connectionParams }, null) |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: t('datasource.description'), |
||||||
|
key: 'note' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: t('datasource.create_time'), |
||||||
|
key: 'createTime' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: t('datasource.update_time'), |
||||||
|
key: 'updateTime' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: t('datasource.operation'), |
||||||
|
key: 'operation', |
||||||
|
width: 150, |
||||||
|
render: (rowData, rowIndex) => { |
||||||
|
return h(NSpace, null, { |
||||||
|
default: () => [ |
||||||
|
h( |
||||||
|
NButton, |
||||||
|
{ |
||||||
|
circle: true, |
||||||
|
class: styles['mr-10'], |
||||||
|
type: 'info', |
||||||
|
onClick: () => void onCallback(rowData.id, 'edit') |
||||||
|
}, |
||||||
|
{ |
||||||
|
default: () => |
||||||
|
h(NIcon, null, { default: () => h(EditOutlined) }) |
||||||
|
} |
||||||
|
), |
||||||
|
h( |
||||||
|
NPopconfirm, |
||||||
|
{ |
||||||
|
onPositiveClick: () => void onCallback(rowData.id, 'delete'), |
||||||
|
negativeText: t('datasource.cancel'), |
||||||
|
positiveText: t('datasource.confirm') |
||||||
|
}, |
||||||
|
{ |
||||||
|
trigger: () => |
||||||
|
h( |
||||||
|
NButton, |
||||||
|
{ |
||||||
|
circle: true, |
||||||
|
type: 'error' |
||||||
|
}, |
||||||
|
{ |
||||||
|
default: () => |
||||||
|
h(NIcon, null, { default: () => h(DeleteOutlined) }) |
||||||
|
} |
||||||
|
), |
||||||
|
default: () => t('datasource.delete') |
||||||
|
} |
||||||
|
) |
||||||
|
] |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
return { |
||||||
|
columnsRef |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,103 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import { reactive } from 'vue' |
||||||
|
import { |
||||||
|
queryDataSource, |
||||||
|
createDataSource, |
||||||
|
updateDataSource, |
||||||
|
connectDataSource, |
||||||
|
verifyDataSourceName |
||||||
|
} from '@/service/modules/data-source' |
||||||
|
import { useI18n } from 'vue-i18n' |
||||||
|
import type { IDataSource } from './types' |
||||||
|
|
||||||
|
export function useDetail(getFieldsValue: Function) { |
||||||
|
const { t } = useI18n() |
||||||
|
const status = reactive({ |
||||||
|
saving: false, |
||||||
|
testing: false, |
||||||
|
loading: false |
||||||
|
}) |
||||||
|
|
||||||
|
let PREV_NAME: string |
||||||
|
|
||||||
|
const formatParams = (): IDataSource => { |
||||||
|
const values = getFieldsValue() |
||||||
|
return { |
||||||
|
...values, |
||||||
|
other: values.other ? JSON.parse(values.other) : null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const queryById = async (id: number) => { |
||||||
|
if (status.loading) return {} |
||||||
|
status.loading = true |
||||||
|
try { |
||||||
|
const dataSourceRes = await queryDataSource(id) |
||||||
|
status.loading = false |
||||||
|
PREV_NAME = dataSourceRes.name |
||||||
|
return dataSourceRes |
||||||
|
} catch (e) { |
||||||
|
window.$message.error((e as Error).message) |
||||||
|
status.loading = false |
||||||
|
return {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const testConnect = async () => { |
||||||
|
if (status.testing) return |
||||||
|
status.testing = true |
||||||
|
try { |
||||||
|
const res = await connectDataSource(formatParams()) |
||||||
|
window.$message.success( |
||||||
|
res |
||||||
|
? res.msg |
||||||
|
: `${t('datasource.test_connect')} ${t('datasource.success')}` |
||||||
|
) |
||||||
|
status.testing = false |
||||||
|
} catch (e) { |
||||||
|
window.$message.error((e as Error).message) |
||||||
|
status.testing = false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const createOrUpdate = async (id?: number) => { |
||||||
|
const values = getFieldsValue() |
||||||
|
if (status.saving || !values.name) return false |
||||||
|
status.saving = true |
||||||
|
|
||||||
|
try { |
||||||
|
if (PREV_NAME !== values.name) { |
||||||
|
await verifyDataSourceName({ name: values.name }) |
||||||
|
} |
||||||
|
|
||||||
|
id |
||||||
|
? await updateDataSource(formatParams(), id) |
||||||
|
: await createDataSource(formatParams()) |
||||||
|
|
||||||
|
status.saving = false |
||||||
|
return true |
||||||
|
} catch (e) { |
||||||
|
window.$message.error((e as Error).message) |
||||||
|
status.saving = false |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return { status, queryById, testConnect, createOrUpdate } |
||||||
|
} |
@ -0,0 +1,209 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import { reactive, ref } from 'vue' |
||||||
|
import { useI18n } from 'vue-i18n' |
||||||
|
import { getKerberosStartupState } from '@/service/modules/data-source' |
||||||
|
import type { FormRules } from 'naive-ui' |
||||||
|
import type { |
||||||
|
IDataSourceDetail, |
||||||
|
IDataBase, |
||||||
|
IDataBaseOption, |
||||||
|
IDataBaseOptionKeys |
||||||
|
} from './types' |
||||||
|
|
||||||
|
export function useForm(id?: number) { |
||||||
|
const { t } = useI18n() |
||||||
|
|
||||||
|
const initialValues = { |
||||||
|
type: 'MYSQL', |
||||||
|
name: '', |
||||||
|
note: '', |
||||||
|
host: '', |
||||||
|
port: datasourceType['MYSQL'].defaultPort, |
||||||
|
principal: '', |
||||||
|
javaSecurityKrb5Conf: '', |
||||||
|
loginUserKeytabUsername: '', |
||||||
|
loginUserKeytabPath: '', |
||||||
|
userName: '', |
||||||
|
password: '', |
||||||
|
database: '', |
||||||
|
connectType: '', |
||||||
|
other: '' |
||||||
|
} as IDataSourceDetail |
||||||
|
|
||||||
|
const state = reactive({ |
||||||
|
detailFormRef: ref(), |
||||||
|
detailForm: { ...initialValues }, |
||||||
|
requiredDataBase: true, |
||||||
|
showConnectType: false, |
||||||
|
showPrincipal: false, |
||||||
|
rules: { |
||||||
|
name: { |
||||||
|
trigger: ['input'], |
||||||
|
validator() { |
||||||
|
if (!state.detailForm.name) { |
||||||
|
return new Error(t('datasource.datasource_name_tips')) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
host: { |
||||||
|
trigger: ['input'], |
||||||
|
validator() { |
||||||
|
if (!state.detailForm.host) { |
||||||
|
return new Error(t('datasource.ip_tips')) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
port: { |
||||||
|
trigger: ['input'], |
||||||
|
validator() { |
||||||
|
if (!state.detailForm.port) { |
||||||
|
return new Error(t('datasource.port_tips')) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
principal: { |
||||||
|
trigger: ['input'], |
||||||
|
validator() { |
||||||
|
if (!state.detailForm.principal && state.showPrincipal) { |
||||||
|
return new Error(t('datasource.principal_tips')) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
userName: { |
||||||
|
trigger: ['input'], |
||||||
|
validator() { |
||||||
|
if (!state.detailForm.userName) { |
||||||
|
return new Error(t('datasource.user_name_tips')) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
database: { |
||||||
|
trigger: ['input'], |
||||||
|
validator() { |
||||||
|
if (!state.detailForm.database && state.requiredDataBase) { |
||||||
|
return new Error(t('datasource.database_name_tips')) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
connectType: { |
||||||
|
trigger: ['update'], |
||||||
|
validator() { |
||||||
|
if (!state.detailForm.connectType && state.showConnectType) { |
||||||
|
return new Error(t('datasource.oracle_connect_type_tips')) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} as FormRules |
||||||
|
}) |
||||||
|
|
||||||
|
const changeType = async (type: IDataBase, options: IDataBaseOption) => { |
||||||
|
state.detailForm.port = options.previousPort || options.defaultPort |
||||||
|
state.detailForm.type = type |
||||||
|
|
||||||
|
if (type === 'ORACLE' && !id) { |
||||||
|
state.detailForm.connectType = 'ORACLE_SERVICE_NAME' |
||||||
|
} |
||||||
|
state.requiredDataBase = type !== 'POSTGRESQL' |
||||||
|
state.showConnectType = type === 'ORACLE' |
||||||
|
|
||||||
|
if (type === 'HIVE' || type === 'SPARK') { |
||||||
|
try { |
||||||
|
state.showPrincipal = await getKerberosStartupState() |
||||||
|
} catch (e) { |
||||||
|
window.$message.error((e as Error).message) |
||||||
|
} |
||||||
|
} else { |
||||||
|
state.showPrincipal = false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const changePort = async () => { |
||||||
|
if (!state.detailForm.type) return |
||||||
|
const currentDataBaseOption = datasourceType[state.detailForm.type] |
||||||
|
currentDataBaseOption.previousPort = state.detailForm.port |
||||||
|
} |
||||||
|
|
||||||
|
const resetFieldsValue = () => { |
||||||
|
state.detailForm = { ...initialValues } |
||||||
|
} |
||||||
|
const setFieldsValue = (values: object) => { |
||||||
|
state.detailForm = { ...state.detailForm, ...values } |
||||||
|
} |
||||||
|
const getFieldsValue = () => state.detailForm |
||||||
|
|
||||||
|
return { |
||||||
|
state, |
||||||
|
changeType, |
||||||
|
changePort, |
||||||
|
resetFieldsValue, |
||||||
|
setFieldsValue, |
||||||
|
getFieldsValue |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const datasourceType: IDataBaseOptionKeys = { |
||||||
|
MYSQL: { |
||||||
|
value: 'MYSQL', |
||||||
|
label: 'MYSQL', |
||||||
|
defaultPort: 3306 |
||||||
|
}, |
||||||
|
POSTGRESQL: { |
||||||
|
value: 'POSTGRESQL', |
||||||
|
label: 'POSTGRESQL', |
||||||
|
defaultPort: 5432 |
||||||
|
}, |
||||||
|
HIVE: { |
||||||
|
value: 'HIVE', |
||||||
|
label: 'HIVE/IMPALA', |
||||||
|
defaultPort: 10000 |
||||||
|
}, |
||||||
|
SPARK: { |
||||||
|
value: 'SPARK', |
||||||
|
label: 'SPARK', |
||||||
|
defaultPort: 10015 |
||||||
|
}, |
||||||
|
CLICKHOUSE: { |
||||||
|
value: 'CLICKHOUSE', |
||||||
|
label: 'CLICKHOUSE', |
||||||
|
defaultPort: 8123 |
||||||
|
}, |
||||||
|
ORACLE: { |
||||||
|
value: 'ORACLE', |
||||||
|
label: 'ORACLE', |
||||||
|
defaultPort: 1521 |
||||||
|
}, |
||||||
|
SQLSERVER: { |
||||||
|
value: 'SQLSERVER', |
||||||
|
label: 'SQLSERVER', |
||||||
|
defaultPort: 1433 |
||||||
|
}, |
||||||
|
DB2: { |
||||||
|
value: 'DB2', |
||||||
|
label: 'DB2', |
||||||
|
defaultPort: 50000 |
||||||
|
}, |
||||||
|
PRESTO: { |
||||||
|
value: 'PRESTO', |
||||||
|
label: 'PRESTO', |
||||||
|
defaultPort: 8080 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export const datasourceTypeList: IDataBaseOption[] = |
||||||
|
Object.values(datasourceType) |
@ -0,0 +1,82 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import { reactive } from 'vue' |
||||||
|
import { |
||||||
|
queryDataSourceListPaging, |
||||||
|
deleteDataSource |
||||||
|
} from '@/service/modules/data-source' |
||||||
|
|
||||||
|
export function useTable() { |
||||||
|
const data = reactive({ |
||||||
|
page: 1, |
||||||
|
pageSize: 10, |
||||||
|
itemCount: 0, |
||||||
|
searchVal: '', |
||||||
|
list: [], |
||||||
|
loading: false |
||||||
|
}) |
||||||
|
|
||||||
|
const getList = async () => { |
||||||
|
if (data.loading) return |
||||||
|
data.loading = true |
||||||
|
|
||||||
|
try { |
||||||
|
const listRes = await queryDataSourceListPaging({ |
||||||
|
pageNo: data.page, |
||||||
|
pageSize: data.pageSize, |
||||||
|
searchVal: data.searchVal |
||||||
|
}) |
||||||
|
data.loading = false |
||||||
|
data.list = listRes.totalList |
||||||
|
data.itemCount = listRes.total |
||||||
|
} catch (e) { |
||||||
|
window.$message.error((e as Error).message) |
||||||
|
data.loading = false |
||||||
|
data.list = [] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const updateList = () => { |
||||||
|
if (data.list.length === 1 && data.page > 1) { |
||||||
|
--data.page |
||||||
|
} |
||||||
|
getList() |
||||||
|
} |
||||||
|
|
||||||
|
const deleteRecord = async (id: number) => { |
||||||
|
try { |
||||||
|
const res = await deleteDataSource(id) |
||||||
|
updateList() |
||||||
|
} catch (e) { |
||||||
|
window.$message.error((e as Error).message) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const changePage = (page: number) => { |
||||||
|
data.page = page |
||||||
|
getList() |
||||||
|
} |
||||||
|
|
||||||
|
const changePageSize = (pageSize: number) => { |
||||||
|
data.page = 1 |
||||||
|
data.pageSize = pageSize |
||||||
|
getList() |
||||||
|
} |
||||||
|
|
||||||
|
return { data, changePage, changePageSize, deleteRecord, updateList } |
||||||
|
} |
Loading…
Reference in new issue