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>
</div>
</div>
<GeneralModal v-model:visible="isNewBaseModalOpen" closable :mask-closable="false" size="medium">
<div class="py-6 px-8">
<LazyDashboardSettingsDataSourcesCreateBase
:connection-type="clientType"
@source-created="loadBases(true)"
@close="isNewBaseModalOpen = false"
/>
</div>
</GeneralModal>
<LazyDashboardSettingsDataSourcesCreateBase
v-model:open="isNewBaseModalOpen"
:connection-type="clientType"
@source-created="loadBases(true)"
/>
<GeneralModal v-model:visible="isErdModalOpen" size="large">
<div class="h-[80vh]">
<LazyDashboardSettingsErd :source-id="activeBaseId" />

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

@ -27,9 +27,11 @@ import {
watch,
} 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)
@ -284,7 +286,7 @@ const createSource = async () => {
}
emit('sourceCreated')
emit('close')
vOpen.value = false
creatingSource.value = false
} else if (status === JobStatus.FAILED) {
message.error('Failed to create base')
@ -405,263 +407,295 @@ watch(
},
{ immediate: true },
)
const toggleModal = (val: boolean) => {
vOpen.value = val
}
</script>
<template>
<div class="create-source bg-white relative flex flex-col justify-center gap-2 w-full">
<h1 class="prose-xl font-bold self-start mb-4 flex items-center gap-2">
{{ $t('title.newBase') }}
<DashboardSettingsDataSourcesInfo />
<span class="flex-grow"></span>
</h1>
<a-form ref="form" :model="formState" name="external-base-create-form" layout="horizontal" no-style :label-col="{ span: 8 }">
<div
class="nc-scrollbar-md"
:style="{
maxHeight: '60vh',
}"
>
<a-form-item label="Source Name" v-bind="validateInfos.title">
<a-input v-model:value="formState.title" class="nc-extdb-proj-name" />
</a-form-item>
<a-form-item :label="$t('labels.dbType')" v-bind="validateInfos['dataSource.client']">
<a-select
v-model:value="formState.dataSource.client"
class="nc-extdb-db-type"
dropdown-class-name="nc-dropdown-ext-db-type"
@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']"
<GeneralModal
:visible="vOpen"
:closable="!creatingSource"
:keyboard="!creatingSource"
:mask-closable="false"
size="medium"
@update:visible="toggleModal"
>
<div class="py-6 px-8">
<div class="create-source bg-white relative flex flex-col justify-center gap-2 w-full">
<h1 class="prose-xl font-bold self-start mb-4 flex items-center gap-2">
{{ $t('title.newBase') }}
<DashboardSettingsDataSourcesInfo />
<span class="flex-grow"></span>
</h1>
<a-form
ref="form"
:model="formState"
name="external-base-create-form"
layout="horizontal"
no-style
:label-col="{ span: 8 }"
>
<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>
<!-- 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']"
<div
class="nc-scrollbar-md"
:style="{
maxHeight: '60vh',
}"
>
<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>
</div>
<a-collapse ghost expand-icon-position="right" class="!mt-6">
<a-collapse-panel key="1">
<template #header>
<span>{{ $t('title.advancedParameters') }}</span>
</template>
<a-form-item label="SSL mode">
<a-select v-model:value="formState.sslUse" dropdown-class-name="nc-dropdown-ssl-mode" @select="onSSLModeChange">
<a-select-option v-for="opt in Object.values(SSLUsage)" :key="opt" :value="opt">{{ opt }} </a-select-option>
</a-select>
<a-form-item label="Source Name" v-bind="validateInfos.title">
<a-input v-model:value="formState.title" class="nc-extdb-proj-name" />
</a-form-item>
<a-form-item :label="$t('labels.dbType')" v-bind="validateInfos['dataSource.client']">
<a-select
v-model:value="formState.dataSource.client"
class="nc-extdb-db-type"
dropdown-class-name="nc-dropdown-ext-db-type"
@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" />
</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 label="SSL keys">
<div class="flex gap-2">
<a-tooltip placement="top">
<!-- Select .cert file -->
<template #title>
<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>
<!-- 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>
<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>
<!-- 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>
<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>
<!-- 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>
<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>
<!-- 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>
<div class="flex justify-end">
<NcButton type="primary" size="small" class="!rounded-md" @click="handleEditJSON()">
<!-- Edit connection JSON -->
{{ $t('activity.editConnJson') }}
<!-- 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>
<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>
</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>
<a-collapse ghost expand-icon-position="right" class="!mt-6">
<a-collapse-panel key="1">
<template #header>
<span>{{ $t('title.advancedParameters') }}</span>
</template>
<a-form-item label="SSL mode">
<a-select
v-model:value="formState.sslUse"
dropdown-class-name="nc-dropdown-ssl-mode"
@select="onSSLModeChange"
>
<a-select-option v-for="opt in Object.values(SSLUsage)" :key="opt" :value="opt">{{ opt }} </a-select-option>
</a-select>
</a-form-item>
<a-form-item label="SSL keys">
<div class="flex gap-2">
<a-tooltip placement="top">
<!-- Select .cert file -->
<template #title>
<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>
<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>
<style lang="scss" scoped>

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

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

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

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

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

@ -69,17 +69,6 @@ onMounted(() => {
</a-tab-pane>
</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')">
<a-tab-pane key="settings" class="w-full">
<template #tab>

Loading…
Cancel
Save