Browse Source

Merge pull request #6630 from nocodb/nc-fix/create-source

fix: disable closing create source modal while creating
pull/6631/head
mertmit 1 year ago committed by GitHub
parent
commit
6e719442cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      packages/nc-gui/components/dashboard/settings/DataSources.vue
  2. 518
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  3. 6
      packages/nc-gui/components/general/Modal.vue
  4. 6
      packages/nc-gui/components/project/AllTables.vue
  5. 11
      packages/nc-gui/components/workspace/View.vue

14
packages/nc-gui/components/dashboard/settings/DataSources.vue

@ -547,15 +547,11 @@ const isEditBaseModalOpen = computed({
</Draggable> </Draggable>
</div> </div>
</div> </div>
<GeneralModal v-model:visible="isNewBaseModalOpen" closable :mask-closable="false" size="medium"> <LazyDashboardSettingsDataSourcesCreateBase
<div class="py-6 px-8"> v-model:open="isNewBaseModalOpen"
<LazyDashboardSettingsDataSourcesCreateBase :connection-type="clientType"
:connection-type="clientType" @source-created="loadBases(true)"
@source-created="loadBases(true)" />
@close="isNewBaseModalOpen = false"
/>
</div>
</GeneralModal>
<GeneralModal v-model:visible="isErdModalOpen" size="large"> <GeneralModal v-model:visible="isErdModalOpen" size="large">
<div class="h-[80vh]"> <div class="h-[80vh]">
<LazyDashboardSettingsErd :source-id="activeBaseId" /> <LazyDashboardSettingsErd :source-id="activeBaseId" />

518
packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue

@ -27,9 +27,11 @@ import {
watch, watch,
} from '#imports' } from '#imports'
const props = defineProps<{ connectionType?: ClientType }>() const props = defineProps<{ open: boolean; connectionType?: ClientType }>()
const emit = defineEmits(['sourceCreated', 'close']) const emit = defineEmits(['update:open', 'sourceCreated'])
const vOpen = useVModel(props, 'open', emit)
const connectionType = computed(() => props.connectionType ?? ClientType.MYSQL) const connectionType = computed(() => props.connectionType ?? ClientType.MYSQL)
@ -284,7 +286,7 @@ const createSource = async () => {
} }
emit('sourceCreated') emit('sourceCreated')
emit('close') vOpen.value = false
creatingSource.value = false creatingSource.value = false
} else if (status === JobStatus.FAILED) { } else if (status === JobStatus.FAILED) {
message.error('Failed to create base') message.error('Failed to create base')
@ -405,263 +407,295 @@ watch(
}, },
{ immediate: true }, { immediate: true },
) )
const toggleModal = (val: boolean) => {
vOpen.value = val
}
</script> </script>
<template> <template>
<div class="create-source bg-white relative flex flex-col justify-center gap-2 w-full"> <GeneralModal
<h1 class="prose-xl font-bold self-start mb-4 flex items-center gap-2"> :visible="vOpen"
{{ $t('title.newBase') }} :closable="!creatingSource"
<DashboardSettingsDataSourcesInfo /> :keyboard="!creatingSource"
<span class="flex-grow"></span> :mask-closable="false"
</h1> size="medium"
@update:visible="toggleModal"
<a-form ref="form" :model="formState" name="external-base-create-form" layout="horizontal" no-style :label-col="{ span: 8 }"> >
<div <div class="py-6 px-8">
class="nc-scrollbar-md" <div class="create-source bg-white relative flex flex-col justify-center gap-2 w-full">
:style="{ <h1 class="prose-xl font-bold self-start mb-4 flex items-center gap-2">
maxHeight: '60vh', {{ $t('title.newBase') }}
}" <DashboardSettingsDataSourcesInfo />
> <span class="flex-grow"></span>
<a-form-item label="Source Name" v-bind="validateInfos.title"> </h1>
<a-input v-model:value="formState.title" class="nc-extdb-proj-name" />
</a-form-item> <a-form
ref="form"
<a-form-item :label="$t('labels.dbType')" v-bind="validateInfos['dataSource.client']"> :model="formState"
<a-select name="external-base-create-form"
v-model:value="formState.dataSource.client" layout="horizontal"
class="nc-extdb-db-type" no-style
dropdown-class-name="nc-dropdown-ext-db-type" :label-col="{ span: 8 }"
@change="onClientChange"
>
<a-select-option v-for="client in clientTypes" :key="client.value" :value="client.value"
>{{ client.text }}
</a-select-option>
</a-select>
</a-form-item>
<!-- SQLite File -->
<a-form-item
v-if="formState.dataSource.client === ClientType.SQLITE"
:label="$t('labels.sqliteFile')"
v-bind="validateInfos['dataSource.connection.connection.filename']"
> >
<a-input v-model:value="(formState.dataSource.connection as SQLiteConnection).connection.filename" /> <div
</a-form-item> class="nc-scrollbar-md"
:style="{
<template v-else> maxHeight: '60vh',
<!-- Host Address --> }"
<a-form-item :label="$t('labels.hostAddress')" v-bind="validateInfos['dataSource.connection.host']">
<a-input v-model:value="(formState.dataSource.connection as DefaultConnection).host" class="nc-extdb-host-address" />
</a-form-item>
<!-- Port Number -->
<a-form-item :label="$t('labels.port')" v-bind="validateInfos['dataSource.connection.port']">
<a-input-number
v-model:value="(formState.dataSource.connection as DefaultConnection).port"
class="!w-full nc-extdb-host-port"
/>
</a-form-item>
<!-- Username -->
<a-form-item :label="$t('labels.username')" v-bind="validateInfos['dataSource.connection.user']">
<a-input v-model:value="(formState.dataSource.connection as DefaultConnection).user" class="nc-extdb-host-user" />
</a-form-item>
<!-- Password -->
<a-form-item :label="$t('labels.password')">
<a-input-password
v-model:value="(formState.dataSource.connection as DefaultConnection).password"
class="nc-extdb-host-password"
/>
</a-form-item>
<!-- Database -->
<a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']">
<!-- Database : create if not exists -->
<a-input
v-model:value="formState.dataSource.connection.database"
:placeholder="$t('labels.dbCreateIfNotExists')"
class="nc-extdb-host-database"
/>
</a-form-item>
<!-- Schema name -->
<a-form-item
v-if="[ClientType.MSSQL, ClientType.PG].includes(formState.dataSource.client) && formState.dataSource.searchPath"
:label="$t('labels.schemaName')"
v-bind="validateInfos['dataSource.searchPath.0']"
> >
<a-input v-model:value="formState.dataSource.searchPath[0]" /> <a-form-item label="Source Name" v-bind="validateInfos.title">
</a-form-item> <a-input v-model:value="formState.title" class="nc-extdb-proj-name" />
<div class="flex items-right justify-end gap-2"> </a-form-item>
<!-- Use Connection URL -->
<NcButton type="ghost" size="small" class="nc-extdb-btn-import-url !rounded-md" @click.stop="importURLDlg = true"> <a-form-item :label="$t('labels.dbType')" v-bind="validateInfos['dataSource.client']">
{{ $t('activity.useConnectionUrl') }} <a-select
</NcButton> v-model:value="formState.dataSource.client"
</div> class="nc-extdb-db-type"
dropdown-class-name="nc-dropdown-ext-db-type"
<a-collapse ghost expand-icon-position="right" class="!mt-6"> @change="onClientChange"
<a-collapse-panel key="1"> >
<template #header> <a-select-option v-for="client in clientTypes" :key="client.value" :value="client.value"
<span>{{ $t('title.advancedParameters') }}</span> >{{ client.text }}
</template> </a-select-option>
<a-form-item label="SSL mode"> </a-select>
<a-select v-model:value="formState.sslUse" dropdown-class-name="nc-dropdown-ssl-mode" @select="onSSLModeChange"> </a-form-item>
<a-select-option v-for="opt in Object.values(SSLUsage)" :key="opt" :value="opt">{{ opt }} </a-select-option>
</a-select> <!-- SQLite File -->
<a-form-item
v-if="formState.dataSource.client === ClientType.SQLITE"
:label="$t('labels.sqliteFile')"
v-bind="validateInfos['dataSource.connection.connection.filename']"
>
<a-input v-model:value="(formState.dataSource.connection as SQLiteConnection).connection.filename" />
</a-form-item>
<template v-else>
<!-- Host Address -->
<a-form-item :label="$t('labels.hostAddress')" v-bind="validateInfos['dataSource.connection.host']">
<a-input
v-model:value="(formState.dataSource.connection as DefaultConnection).host"
class="nc-extdb-host-address"
/>
</a-form-item> </a-form-item>
<a-form-item label="SSL keys"> <!-- Port Number -->
<div class="flex gap-2"> <a-form-item :label="$t('labels.port')" v-bind="validateInfos['dataSource.connection.port']">
<a-tooltip placement="top"> <a-input-number
<!-- Select .cert file --> v-model:value="(formState.dataSource.connection as DefaultConnection).port"
<template #title> class="!w-full nc-extdb-host-port"
<span>{{ $t('tooltip.clientCert') }}</span> />
</template>
<NcButton size="small" :disabled="!sslFilesRequired" class="shadow" @click="certFileInput?.click()">
{{ $t('labels.clientCert') }}
</NcButton>
</a-tooltip>
<a-tooltip placement="top">
<!-- Select .key file -->
<template #title>
<span>{{ $t('tooltip.clientKey') }}</span>
</template>
<NcButton size="small" :disabled="!sslFilesRequired" class="shadow" @click="keyFileInput?.click()">
{{ $t('labels.clientKey') }}
</NcButton>
</a-tooltip>
<a-tooltip placement="top">
<!-- Select CA file -->
<template #title>
<span>{{ $t('tooltip.clientCA') }}</span>
</template>
<NcButton size="small" :disabled="!sslFilesRequired" class="shadow" @click="caFileInput?.click()">
{{ $t('labels.serverCA') }}
</NcButton>
</a-tooltip>
</div>
</a-form-item> </a-form-item>
<input ref="caFileInput" type="file" class="!hidden" @change="onFileSelect(CertTypes.ca, caFileInput)" /> <!-- Username -->
<a-form-item :label="$t('labels.username')" v-bind="validateInfos['dataSource.connection.user']">
<input ref="certFileInput" type="file" class="!hidden" @change="onFileSelect(CertTypes.cert, certFileInput)" /> <a-input v-model:value="(formState.dataSource.connection as DefaultConnection).user" class="nc-extdb-host-user" />
<input ref="keyFileInput" type="file" class="!hidden" @change="onFileSelect(CertTypes.key, keyFileInput)" />
<a-divider />
<!-- Extra connection parameters -->
<a-form-item class="mb-2" :label="$t('labels.extraConnectionParameters')" v-bind="validateInfos.extraParameters">
<a-card>
<div v-for="(item, index) of formState.extraParameters" :key="index">
<div class="flex py-1 items-center gap-1">
<a-input v-model:value="item.key" />
<span>:</span>
<a-input v-model:value="item.value" />
<component
:is="iconMap.close"
:style="{ 'font-size': '1.5em', 'color': 'red' }"
@click="removeParam(index)"
/>
</div>
</div>
<NcButton size="small" type="dashed" class="w-full caption mt-2" @click="addNewParam">
<div class="flex items-center justify-center">
<component :is="iconMap.plus" />
</div>
</NcButton>
</a-card>
</a-form-item> </a-form-item>
<a-divider /> <!-- Password -->
<a-form-item :label="$t('labels.password')">
<a-form-item :label="$t('labels.inflection.tableName')"> <a-input-password
<a-select v-model:value="(formState.dataSource.connection as DefaultConnection).password"
v-model:value="formState.inflection.inflectionTable" class="nc-extdb-host-password"
dropdown-class-name="nc-dropdown-inflection-table-name" />
>
<a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }} </a-select-option>
</a-select>
</a-form-item> </a-form-item>
<a-form-item :label="$t('labels.inflection.columnName')"> <!-- Database -->
<a-select <a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']">
v-model:value="formState.inflection.inflectionColumn" <!-- Database : create if not exists -->
dropdown-class-name="nc-dropdown-inflection-column-name" <a-input
> v-model:value="formState.dataSource.connection.database"
<a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }} </a-select-option> :placeholder="$t('labels.dbCreateIfNotExists')"
</a-select> class="nc-extdb-host-database"
/>
</a-form-item> </a-form-item>
<div class="flex justify-end"> <!-- Schema name -->
<NcButton type="primary" size="small" class="!rounded-md" @click="handleEditJSON()"> <a-form-item
<!-- Edit connection JSON --> v-if="[ClientType.MSSQL, ClientType.PG].includes(formState.dataSource.client) && formState.dataSource.searchPath"
{{ $t('activity.editConnJson') }} :label="$t('labels.schemaName')"
v-bind="validateInfos['dataSource.searchPath.0']"
>
<a-input v-model:value="formState.dataSource.searchPath[0]" />
</a-form-item>
<div class="flex items-right justify-end gap-2">
<!-- Use Connection URL -->
<NcButton type="ghost" size="small" class="nc-extdb-btn-import-url !rounded-md" @click.stop="importURLDlg = true">
{{ $t('activity.useConnectionUrl') }}
</NcButton> </NcButton>
</div> </div>
</a-collapse-panel>
</a-collapse>
</template>
</div>
<a-form-item class="flex justify-end !mt-5"> <a-collapse ghost expand-icon-position="right" class="!mt-6">
<div class="flex justify-end gap-2"> <a-collapse-panel key="1">
<NcButton <template #header>
:type="testSuccess ? 'ghost' : 'primary'" <span>{{ $t('title.advancedParameters') }}</span>
size="small" </template>
class="nc-extdb-btn-test-connection !rounded-md" <a-form-item label="SSL mode">
:loading="testingConnection" <a-select
@click="testConnection" v-model:value="formState.sslUse"
> dropdown-class-name="nc-dropdown-ssl-mode"
<GeneralIcon v-if="testSuccess" icon="circleCheck" class="text-primary mr-2" /> @select="onSSLModeChange"
{{ $t('activity.testDbConn') }} >
</NcButton> <a-select-option v-for="opt in Object.values(SSLUsage)" :key="opt" :value="opt">{{ opt }} </a-select-option>
</a-select>
<NcButton </a-form-item>
size="small"
type="primary" <a-form-item label="SSL keys">
:disabled="!testSuccess" <div class="flex gap-2">
:loading="creatingSource" <a-tooltip placement="top">
class="nc-extdb-btn-submit !rounded-md" <!-- Select .cert file -->
@click="createSource" <template #title>
> <span>{{ $t('tooltip.clientCert') }}</span>
{{ $t('general.submit') }} </template>
</NcButton>
</div> <NcButton size="small" :disabled="!sslFilesRequired" class="shadow" @click="certFileInput?.click()">
</a-form-item> {{ $t('labels.clientCert') }}
</a-form> </NcButton>
</a-tooltip>
<a-modal
v-model:visible="configEditDlg" <a-tooltip placement="top">
:title="$t('activity.editConnJson')" <!-- Select .key file -->
width="600px" <template #title>
wrap-class-name="nc-modal-edit-connection-json" <span>{{ $t('tooltip.clientKey') }}</span>
@ok="handleOk" </template>
> <NcButton size="small" :disabled="!sslFilesRequired" class="shadow" @click="keyFileInput?.click()">
<MonacoEditor v-if="configEditDlg" v-model="customFormState" class="h-[400px] w-full" /> {{ $t('labels.clientKey') }}
</a-modal> </NcButton>
</a-tooltip>
<!-- Use Connection URL -->
<a-modal <a-tooltip placement="top">
v-model:visible="importURLDlg" <!-- Select CA file -->
:title="$t('activity.useConnectionUrl')" <template #title>
width="500px" <span>{{ $t('tooltip.clientCA') }}</span>
:ok-text="$t('general.ok')" </template>
:cancel-text="$t('general.cancel')"
wrap-class-name="nc-modal-connection-url" <NcButton size="small" :disabled="!sslFilesRequired" class="shadow" @click="caFileInput?.click()">
@ok="handleImportURL" {{ $t('labels.serverCA') }}
> </NcButton>
<a-input v-model:value="importURL" /> </a-tooltip>
</a-modal> </div>
</div> </a-form-item>
<input ref="caFileInput" type="file" class="!hidden" @change="onFileSelect(CertTypes.ca, caFileInput)" />
<input ref="certFileInput" type="file" class="!hidden" @change="onFileSelect(CertTypes.cert, certFileInput)" />
<input ref="keyFileInput" type="file" class="!hidden" @change="onFileSelect(CertTypes.key, keyFileInput)" />
<a-divider />
<!-- Extra connection parameters -->
<a-form-item
class="mb-2"
:label="$t('labels.extraConnectionParameters')"
v-bind="validateInfos.extraParameters"
>
<a-card>
<div v-for="(item, index) of formState.extraParameters" :key="index">
<div class="flex py-1 items-center gap-1">
<a-input v-model:value="item.key" />
<span>:</span>
<a-input v-model:value="item.value" />
<component
:is="iconMap.close"
:style="{ 'font-size': '1.5em', 'color': 'red' }"
@click="removeParam(index)"
/>
</div>
</div>
<NcButton size="small" type="dashed" class="w-full caption mt-2" @click="addNewParam">
<div class="flex items-center justify-center">
<component :is="iconMap.plus" />
</div>
</NcButton>
</a-card>
</a-form-item>
<a-divider />
<a-form-item :label="$t('labels.inflection.tableName')">
<a-select
v-model:value="formState.inflection.inflectionTable"
dropdown-class-name="nc-dropdown-inflection-table-name"
>
<a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }} </a-select-option>
</a-select>
</a-form-item>
<a-form-item :label="$t('labels.inflection.columnName')">
<a-select
v-model:value="formState.inflection.inflectionColumn"
dropdown-class-name="nc-dropdown-inflection-column-name"
>
<a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }} </a-select-option>
</a-select>
</a-form-item>
<div class="flex justify-end">
<NcButton type="primary" size="small" class="!rounded-md" @click="handleEditJSON()">
<!-- Edit connection JSON -->
{{ $t('activity.editConnJson') }}
</NcButton>
</div>
</a-collapse-panel>
</a-collapse>
</template>
</div>
<a-form-item class="flex justify-end !mt-5">
<div class="flex justify-end gap-2">
<NcButton
:type="testSuccess ? 'ghost' : 'primary'"
size="small"
class="nc-extdb-btn-test-connection !rounded-md"
:loading="testingConnection"
@click="testConnection"
>
<GeneralIcon v-if="testSuccess" icon="circleCheck" class="text-primary mr-2" />
{{ $t('activity.testDbConn') }}
</NcButton>
<NcButton
size="small"
type="primary"
:disabled="!testSuccess"
:loading="creatingSource"
class="nc-extdb-btn-submit !rounded-md"
@click="createSource"
>
{{ $t('general.submit') }}
</NcButton>
</div>
</a-form-item>
</a-form>
<a-modal
v-model:visible="configEditDlg"
:title="$t('activity.editConnJson')"
width="600px"
wrap-class-name="nc-modal-edit-connection-json"
@ok="handleOk"
>
<MonacoEditor v-if="configEditDlg" v-model="customFormState" class="h-[400px] w-full" />
</a-modal>
<!-- Use Connection URL -->
<a-modal
v-model:visible="importURLDlg"
:title="$t('activity.useConnectionUrl')"
width="500px"
:ok-text="$t('general.ok')"
:cancel-text="$t('general.cancel')"
wrap-class-name="nc-modal-connection-url"
@ok="handleImportURL"
>
<a-input v-model:value="importURL" />
</a-modal>
</div>
</div>
</GeneralModal>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

6
packages/nc-gui/components/general/Modal.vue

@ -7,18 +7,21 @@ const props = withDefaults(
destroyOnClose?: boolean destroyOnClose?: boolean
maskClosable?: boolean maskClosable?: boolean
closable?: boolean closable?: boolean
keyboard?: boolean
}>(), }>(),
{ {
size: 'medium', size: 'medium',
destroyOnClose: true, destroyOnClose: true,
maskClosable: true, maskClosable: true,
closable: false, closable: false,
keyboard: true,
}, },
) )
const emits = defineEmits(['update:visible']) const emits = defineEmits(['update:visible'])
const { width: propWidth, destroyOnClose, closable, maskClosable } = props const { width: propWidth, destroyOnClose } = props
const { maskClosable, closable, keyboard } = toRefs(props)
const width = computed(() => { const width = computed(() => {
if (propWidth) { if (propWidth) {
@ -65,6 +68,7 @@ const visible = useVModel(props, 'visible', emits)
:class="{ active: visible }" :class="{ active: visible }"
:width="width" :width="width"
:closable="closable" :closable="closable"
:keyboard="keyboard"
wrap-class-name="nc-modal-wrapper" wrap-class-name="nc-modal-wrapper"
:footer="null" :footer="null"
:destroy-on-close="destroyOnClose" :destroy-on-close="destroyOnClose"

6
packages/nc-gui/components/project/AllTables.vue

@ -158,11 +158,7 @@ const onCreateBaseClick = () => {
</div> </div>
</div> </div>
<ProjectImportModal v-if="defaultBase" v-model:visible="isImportModalOpen" :source="defaultBase" /> <ProjectImportModal v-if="defaultBase" v-model:visible="isImportModalOpen" :source="defaultBase" />
<GeneralModal v-model:visible="isNewBaseModalOpen" size="medium"> <LazyDashboardSettingsDataSourcesCreateBase v-model:open="isNewBaseModalOpen" />
<div class="py-6 px-8">
<LazyDashboardSettingsDataSourcesCreateBase @close="isNewBaseModalOpen = false" />
</div>
</GeneralModal>
</div> </div>
</template> </template>

11
packages/nc-gui/components/workspace/View.vue

@ -69,17 +69,6 @@ onMounted(() => {
</a-tab-pane> </a-tab-pane>
</template> </template>
<template v-if="isUIAllowed('workspaceBilling')">
<a-tab-pane key="billing" class="w-full">
<template #tab>
<div class="flex flex-row items-center px-2 pb-1 gap-x-1.5">
<MaterialSymbolsCreditCardOutline />
Billing
</div>
</template>
<WorkspaceBilling />
</a-tab-pane>
</template>
<template v-if="isUIAllowed('workspaceManage')"> <template v-if="isUIAllowed('workspaceManage')">
<a-tab-pane key="settings" class="w-full"> <a-tab-pane key="settings" class="w-full">
<template #tab> <template #tab>

Loading…
Cancel
Save