Browse Source

Merge pull request #9161 from nocodb/nc-fix/integration-corrections

Nc fix/integration corrections
pull/9170/head
Ramesh Mane 4 months ago committed by GitHub
parent
commit
79609d5ec5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 313
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  2. 418
      packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue
  3. 4
      packages/nc-gui/components/dashboard/settings/data-sources/SourceRestrictions.vue
  4. 46
      packages/nc-gui/components/project/AllTables.vue
  5. 2
      packages/nc-gui/components/project/SyncDataModal.vue
  6. 2
      packages/nc-gui/components/workspace/integrations/List.vue
  7. 5
      packages/nc-gui/components/workspace/integrations/newAvailableList.vue
  8. 4
      packages/nc-gui/lang/en.json

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

@ -139,16 +139,10 @@ const validators = computed(() => {
} }
}) })
const { validate, validateInfos } = useForm(formState.value, validators) const { validate, validateInfos, clearValidate } = useForm(formState.value, validators)
const populateName = (v: string) => {
if (selectedIntegration.value) return
formState.value.dataSource.connection.database = `${v.trim()}_noco`
}
const onClientChange = () => { const onClientChange = () => {
formState.value.dataSource = { ...getDefaultConnectionConfig(formState.value.dataSource.client) } formState.value.dataSource = { ...getDefaultConnectionConfig(formState.value.dataSource.client) }
populateName(formState.value.title)
} }
const inflectionTypes = ['camelize', 'none'] const inflectionTypes = ['camelize', 'none']
@ -322,7 +316,6 @@ watch(
onMounted(async () => { onMounted(async () => {
await loadIntegrations(true, base.value?.id) await loadIntegrations(true, base.value?.id)
formState.value.title = await generateUniqueName() formState.value.title = await generateUniqueName()
populateName(formState.value.title)
nextTick(() => { nextTick(() => {
// todo: replace setTimeout and follow better approach // todo: replace setTimeout and follow better approach
@ -435,10 +428,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
<div class="h-6 self-start flex items-center"> <div class="h-6 self-start flex items-center">
<GeneralIcon icon="server1" class="!text-green-700 !h-4 !w-4" /> <GeneralIcon icon="server1" class="!text-green-700 !h-4 !w-4" />
</div> </div>
<div class="flex-1"> <div class="flex-1 text-base font-weight-700">Add Data Source</div>
<div class="flex-1 text-base font-weight-700">New Source</div>
<div class="text-xs text-gray-600">Connect with a new external data source, directly in real time.</div>
</div>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div class="w-[15px] h-[15px] cursor-pointer" @dblclick="onEasterEgg"></div> <div class="w-[15px] h-[15px] cursor-pointer" @dblclick="onEasterEgg"></div>
@ -471,7 +461,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
<NcButton <NcButton
size="small" size="small"
type="primary" type="primary"
:disabled="!testSuccess" :disabled="!testSuccess || !selectedIntegration"
:loading="creatingSource" :loading="creatingSource"
class="nc-extdb-btn-submit" class="nc-extdb-btn-submit"
@click="createSource" @click="createSource"
@ -483,7 +473,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
</NcButton> </NcButton>
</div> </div>
</div> </div>
<div class="h-[calc(100%_-_66px)] flex"> <div class="h-[calc(100%_-_58px)] flex">
<div class="nc-add-source-left-panel nc-scrollbar-thin"> <div class="nc-add-source-left-panel nc-scrollbar-thin">
<div class="create-source bg-white relative flex flex-col gap-2 w-full max-w-[768px]"> <div class="create-source bg-white relative flex flex-col gap-2 w-full max-w-[768px]">
<a-form <a-form
@ -496,12 +486,11 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
class="flex flex-col gap-5.5" class="flex flex-col gap-5.5"
> >
<div class="nc-form-section"> <div class="nc-form-section">
<div class="nc-form-section-title">Source details</div>
<div class="nc-form-section-body"> <div class="nc-form-section-body">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="12"> <a-col :span="12">
<a-form-item label="Source name" v-bind="validateInfos.title"> <a-form-item label="Data Source Name" v-bind="validateInfos.title">
<a-input v-model:value="formState.title" @input="populateName(formState.title)" /> <a-input v-model:value="formState.title" />
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -560,162 +549,156 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
</div> </div>
</div> </div>
<div class="nc-form-section"> <template v-if="selectedIntegration">
<div class="flex items-center justify-between"> <div class="nc-form-section">
<div class="nc-form-section-title">Connection details</div> <div class="nc-form-section-body">
</div> <!-- SQLite File -->
<div class="nc-form-section-body"> <template v-if="formState.dataSource.client === ClientType.SQLITE"> </template>
<!-- SQLite File --> <template v-else-if="formState.dataSource.client === ClientType.SNOWFLAKE">
<template v-if="formState.dataSource.client === ClientType.SQLITE"> </template> <a-row :gutter="24">
<template v-else-if="formState.dataSource.client === ClientType.SNOWFLAKE"> <a-col :span="12">
<a-row :gutter="24"> <!-- Database -->
<a-col :span="12"> <a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']">
<!-- Database --> <a-input
<a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']"> v-model:value="(formState.dataSource.connection as SnowflakeConnection).database"
<a-input class="nc-extdb-host-database"
v-model:value="(formState.dataSource.connection as SnowflakeConnection).database" />
class="nc-extdb-host-database" </a-form-item>
/> </a-col>
</a-form-item> <a-col :span="12">
</a-col> <!-- Schema -->
<a-col :span="12"> <a-form-item label="Schema" v-bind="validateInfos['dataSource.connection.schema']">
<!-- Schema --> <a-input
<a-form-item label="Schema" v-bind="validateInfos['dataSource.connection.schema']"> v-model:value="(formState.dataSource.connection as SnowflakeConnection).schema"
<a-input class="nc-extdb-host-database"
v-model:value="(formState.dataSource.connection as SnowflakeConnection).schema" />
class="nc-extdb-host-database" </a-form-item>
/> </a-col>
</a-form-item> </a-row>
</a-col> </template>
</a-row>
</template> <template v-else-if="formState.dataSource.client === ClientType.DATABRICKS">
<a-row :gutter="24">
<template v-else-if="formState.dataSource.client === ClientType.DATABRICKS"> <a-col :span="12">
<a-row :gutter="24"> <a-form-item label="Database" v-bind="validateInfos['dataSource.connection.database']">
<a-col :span="12"> <a-input
<a-form-item label="Database" v-bind="validateInfos['dataSource.connection.database']"> v-model:value="(formState.dataSource.connection as DatabricksConnection).database"
<a-input class="nc-extdb-host-database"
v-model:value="(formState.dataSource.connection as DatabricksConnection).database" />
class="nc-extdb-host-database" </a-form-item>
/> </a-col>
</a-form-item> <a-col :span="12">
</a-col> <a-form-item label="Schema" v-bind="validateInfos['dataSource.connection.schema']">
<a-col :span="12"> <a-input
<a-form-item label="Schema" v-bind="validateInfos['dataSource.connection.schema']"> v-model:value="(formState.dataSource.connection as DatabricksConnection).schema"
<a-input class="nc-extdb-host-schema"
v-model:value="(formState.dataSource.connection as DatabricksConnection).schema" />
class="nc-extdb-host-schema" </a-form-item>
/> </a-col>
</a-form-item> </a-row>
</a-col> </template>
</a-row> <template v-else>
</template> <a-row :gutter="24">
<template v-else> <a-col :span="12">
<a-row :gutter="24"> <!-- Database -->
<a-col :span="12"> <a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']">
<!-- Database --> <!-- Database : create if not exists -->
<a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']"> <a-input
<!-- Database : create if not exists --> v-model:value="formState.dataSource.connection.database"
<a-input :placeholder="$t('labels.dbCreateIfNotExists')"
v-model:value="formState.dataSource.connection.database" class="nc-extdb-host-database"
:placeholder="$t('labels.dbCreateIfNotExists')" />
class="nc-extdb-host-database" </a-form-item>
/> </a-col>
</a-form-item> <a-col :span="12">
</a-col> <!-- Schema name -->
<a-col :span="12"> <a-form-item
<!-- Schema name --> v-if="
<a-form-item ([ClientType.MSSQL, ClientType.PG].includes(formState.dataSource.client) ||
v-if=" [ClientType.MSSQL, ClientType.PG].includes(selectedIntegration?.sub_type)) &&
([ClientType.MSSQL, ClientType.PG].includes(formState.dataSource.client) || formState.dataSource.searchPath
[ClientType.MSSQL, ClientType.PG].includes(selectedIntegration?.sub_type)) && "
formState.dataSource.searchPath :label="$t('labels.schemaName')"
" v-bind="validateInfos['dataSource.searchPath.0']"
:label="$t('labels.schemaName')" >
v-bind="validateInfos['dataSource.searchPath.0']" <a-input
> v-model:value="formState.dataSource.searchPath[0]"
<a-input :placeholder="selectedIntegrationSchema && `${selectedIntegrationSchema} (default)`"
v-model:value="formState.dataSource.searchPath[0]" />
:placeholder="selectedIntegrationSchema && `${selectedIntegrationSchema} (default)`" </a-form-item>
/> </a-col>
</a-form-item> </a-row>
</a-col> </template>
</a-row> </div>
</template>
</div> </div>
</div>
<div class="nc-form-section"> <div class="nc-form-section">
<div class="nc-form-section-title">Permissions</div> <div class="nc-form-section-title">Permissions</div>
<div class="nc-form-section-body"> <div class="nc-form-section-body">
<DashboardSettingsDataSourcesSourceRestrictions <DashboardSettingsDataSourcesSourceRestrictions
v-model:allowMetaWrite="allowMetaWrite" v-model:allowMetaWrite="allowMetaWrite"
v-model:allowDataWrite="allowDataWrite" v-model:allowDataWrite="allowDataWrite"
/> />
</div>
</div> </div>
</div>
<template <template
v-if="![ClientType.SQLITE, ClientType.SNOWFLAKE, ClientType.DATABRICKS].includes(formState.dataSource.client)" v-if="![ClientType.SQLITE, ClientType.SNOWFLAKE, ClientType.DATABRICKS].includes(formState.dataSource.client)"
>
<a-collapse
v-model:active-key="advancedOptionsExpansionPanel"
ghost
class="nc-source-advanced-options !mt-4"
> >
<template #expandIcon="{ isActive }"> <a-collapse v-model:active-key="advancedOptionsExpansionPanel" ghost class="nc-source-advanced-options !mt-4">
<NcButton <template #expandIcon="{ isActive }">
type="text" <NcButton
size="small" type="text"
class="!-ml-1.5" size="small"
@click="handleUpdateAdvancedOptionsExpansionPanel(!advancedOptionsExpansionPanel.length)" class="!-ml-1.5"
> @click="handleUpdateAdvancedOptionsExpansionPanel(!advancedOptionsExpansionPanel.length)"
<div class="nc-form-section-title">Advanced options</div> >
<div class="nc-form-section-title">Advanced options</div>
<GeneralIcon
icon="chevronDown" <GeneralIcon
class="ml-2 flex-none cursor-pointer transform transition-transform duration-500" icon="chevronDown"
:class="{ '!rotate-180': isActive }" class="ml-2 flex-none cursor-pointer transform transition-transform duration-500"
/> :class="{ '!rotate-180': isActive }"
</NcButton> />
</template> </NcButton>
<a-collapse-panel key="1" collapsible="disabled">
<template #header>
<span></span>
</template> </template>
<a-collapse-panel key="1" collapsible="disabled">
<template #header>
<span></span>
</template>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<a-row :gutter="24"> <div class="flex flex-col gap-4">
<a-col :span="12"> <a-row :gutter="24">
<a-form-item :label="$t('labels.inflection.tableName')"> <a-col :span="12">
<NcSelect <a-form-item :label="$t('labels.inflection.tableName')">
v-model:value="formState.inflection.inflectionTable" <NcSelect
class="nc-select-shadow" v-model:value="formState.inflection.inflectionTable"
dropdown-class-name="nc-dropdown-inflection-table-name" class="nc-select-shadow"
> dropdown-class-name="nc-dropdown-inflection-table-name"
<a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }}</a-select-option> >
</NcSelect> <a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }}</a-select-option>
</a-form-item> </NcSelect>
</a-col> </a-form-item>
<a-col :span="12"> </a-col>
<a-form-item :label="$t('labels.inflection.columnName')"> <a-col :span="12">
<NcSelect <a-form-item :label="$t('labels.inflection.columnName')">
v-model:value="formState.inflection.inflectionColumn" <NcSelect
class="nc-select-shadow" v-model:value="formState.inflection.inflectionColumn"
dropdown-class-name="nc-dropdown-inflection-column-name" class="nc-select-shadow"
> dropdown-class-name="nc-dropdown-inflection-column-name"
<a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }}</a-select-option> >
</NcSelect> <a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }}</a-select-option>
</a-form-item> </NcSelect>
</a-col> </a-form-item>
</a-row> </a-col>
</a-row>
</div>
</div> </div>
</div> </a-collapse-panel>
</a-collapse-panel> </a-collapse>
</a-collapse> </template>
</template> </template>
<div> <div>
<!-- For spacing --> <!-- For spacing -->
</div> </div>
@ -726,7 +709,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
</div> </div>
</div> </div>
<div class="nc-add-source-right-panel"> <div class="nc-add-source-right-panel">
<DashboardSettingsDataSourcesSupportedDocs/> <DashboardSettingsDataSourcesSupportedDocs />
<NcDivider /> <NcDivider />
</div> </div>
</div> </div>
@ -739,7 +722,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
@apply p-6 flex-1 flex justify-center; @apply p-6 flex-1 flex justify-center;
} }
.nc-add-source-right-panel { .nc-add-source-right-panel {
@apply p-5 w-[320px] border-l-1 border-gray-200 flex flex-col gap-4 bg-gray-50 rounded-br-2xl; @apply p-4 w-[320px] border-l-1 border-gray-200 flex flex-col gap-4 bg-gray-50 rounded-br-2xl;
} }
:deep(.ant-collapse-header) { :deep(.ant-collapse-header) {
@apply !-mt-4 !p-0 flex items-center !cursor-default children:first:flex; @apply !-mt-4 !p-0 flex items-center !cursor-default children:first:flex;

418
packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue

@ -48,6 +48,8 @@ const easterEgg = ref(false)
const easterEggCount = ref(0) const easterEggCount = ref(0)
const advancedOptionsExpansionPanel = ref<string[]>([])
const onEasterEgg = () => { const onEasterEgg = () => {
easterEggCount.value += 1 easterEggCount.value += 1
if (easterEggCount.value >= 2) { if (easterEggCount.value >= 2) {
@ -335,8 +337,17 @@ const allowDataWrite = computed({
}, },
}) })
const handleUpdateAdvancedOptionsExpansionPanel = (open: boolean) => {
if (open) {
advancedOptionsExpansionPanel.value = ['1']
handleAutoScroll(true, 'nc-source-advanced-options')
} else {
advancedOptionsExpansionPanel.value = []
}
}
let timer: any let timer: any
const handleAutoScroll = (scroll: boolean, className: string) => { function handleAutoScroll(scroll: boolean, className: string) {
if (scroll) { if (scroll) {
if (timer) { if (timer) {
clearTimeout(timer) clearTimeout(timer)
@ -357,221 +368,224 @@ const handleAutoScroll = (scroll: boolean, className: string) => {
<template> <template>
<div class="edit-source bg-white relative h-full flex flex-col w-full"> <div class="edit-source bg-white relative h-full flex flex-col w-full">
<div class="h-full max-h-[calc(100%_-_65px)] nc-scrollbar-thin"> <div class="h-full max-h-[calc(100%_-_65px)] flex">
<div class="h-full max-w-[992px] p-6 mx-auto"> <div class="nc-edit-source-left-panel nc-scrollbar-thin">
<a-form <div class="h-full max-w-[768px] mx-auto">
ref="form" <a-form
:model="formState" ref="form"
hide-required-mark :model="formState"
name="external-base-create-form" hide-required-mark
layout="vertical" name="external-base-create-form"
no-style layout="vertical"
class="flex flex-col gap-5.5" no-style
> class="flex flex-col gap-5.5"
<div class="nc-form-section"> >
<div class="nc-form-section-title">Source details</div> <div class="nc-form-section">
<div class="nc-form-section-body"> <div class="nc-form-section-body">
<a-row :gutter="24">
<a-col :span="12">
<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-col>
</a-row>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="Select connection">
<NcSelect
:value="formState.fk_integration_id"
disabled
class="nc-extdb-db-type nc-select-shadow"
dropdown-class-name="nc-dropdown-ext-db-type"
placeholder="Select connection"
allow-clear
show-search
dropdown-match-select-width
>
<a-select-option v-for="integration in integrations" :key="integration.id" :value="integration.id">
<div class="w-full flex gap-2 items-center" :data-testid="integration.title">
<GeneralBaseLogo
v-if="integration.type"
:source-type="integration.sub_type"
class="flex-none h-4 w-4"
/>
<NcTooltip class="flex-1 truncate" show-on-truncate-only>
<template #title>
{{ integration.title }}
</template>
{{ integration.title }}
</NcTooltip>
<component
:is="iconMap.check"
v-if="formState.fk_integration_id === integration.id"
id="nc-selected-item-icon"
class="text-primary w-4 h-4"
/>
</div>
</a-select-option>
</NcSelect>
</a-form-item>
</a-col>
</a-row>
</div>
</div>
<div class="nc-form-section">
<div class="nc-form-section-title">Connection details</div>
<div class="nc-form-section-body">
<!-- SQLite File -->
<template v-if="formState.dataSource.client === ClientType.SQLITE"> </template>
<template v-else-if="formState.dataSource.client === ClientType.SNOWFLAKE">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="12"> <a-col :span="12">
<!-- Database --> <a-form-item label="Data Source Name" v-bind="validateInfos.title">
<a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']"> <a-input v-model:value="formState.title" class="nc-extdb-proj-name" />
<a-input
v-model:value="(formState.dataSource.connection as SnowflakeConnection).database"
class="nc-extdb-host-database"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<!-- Schema -->
<a-form-item label="Schema" v-bind="validateInfos['dataSource.connection.schema']">
<a-input
v-model:value="(formState.dataSource.connection as SnowflakeConnection).schema"
class="nc-extdb-host-database"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
</template>
<template v-else-if="formState.dataSource.client === ClientType.DATABRICKS">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="12"> <a-col :span="12">
<a-form-item label="Database" v-bind="validateInfos['dataSource.connection.database']"> <a-form-item label="Select connection">
<a-input <NcSelect
v-model:value="(formState.dataSource.connection as DatabricksConnection).database" :value="formState.fk_integration_id"
class="nc-extdb-host-database" disabled
/> class="nc-extdb-db-type nc-select-shadow"
</a-form-item> dropdown-class-name="nc-dropdown-ext-db-type"
</a-col> placeholder="Select connection"
<a-col :span="12"> allow-clear
<a-form-item label="Schema" v-bind="validateInfos['dataSource.connection.schema']"> show-search
<a-input dropdown-match-select-width
v-model:value="(formState.dataSource.connection as DatabricksConnection).schema" >
class="nc-extdb-host-schema" <a-select-option v-for="integration in integrations" :key="integration.id" :value="integration.id">
/> <div class="w-full flex gap-2 items-center" :data-testid="integration.title">
</a-form-item> <GeneralBaseLogo
</a-col> v-if="integration.type"
</a-row> :source-type="integration.sub_type"
</template> class="flex-none h-4 w-4"
<template v-else> />
<a-row :gutter="24"> <NcTooltip class="flex-1 truncate" show-on-truncate-only>
<a-col :span="12"> <template #title>
<!-- Database --> {{ integration.title }}
<a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']"> </template>
<!-- Database : create if not exists --> {{ integration.title }}
<a-input </NcTooltip>
v-model:value="formState.dataSource.connection.database" <component
:placeholder="$t('labels.dbCreateIfNotExists')" :is="iconMap.check"
class="nc-extdb-host-database" v-if="formState.fk_integration_id === integration.id"
/> id="nc-selected-item-icon"
</a-form-item> class="text-primary w-4 h-4"
</a-col> />
<a-col :span="12"> </div>
<!-- Schema name --> </a-select-option>
<a-form-item </NcSelect>
v-if="
([ClientType.MSSQL, ClientType.PG].includes(formState.dataSource.client) ||
[ClientType.MSSQL, ClientType.PG].includes(selectedIntegration?.sub_type)) &&
formState.dataSource.searchPath
"
:label="$t('labels.schemaName')"
v-bind="validateInfos['dataSource.searchPath.0']"
>
<a-input
v-model:value="formState.dataSource.searchPath[0]"
:placeholder="selectedIntegrationSchema && `${selectedIntegrationSchema} (default)`"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
</template> </div>
</div>
<div class="nc-form-section">
<div class="nc-form-section-body">
<!-- SQLite File -->
<template v-if="formState.dataSource.client === ClientType.SQLITE"> </template>
<template v-else-if="formState.dataSource.client === ClientType.SNOWFLAKE">
<a-row :gutter="24">
<a-col :span="12">
<!-- Database -->
<a-form-item :label="$t('labels.database')" v-bind="validateInfos['dataSource.connection.database']">
<a-input
v-model:value="(formState.dataSource.connection as SnowflakeConnection).database"
class="nc-extdb-host-database"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<!-- Schema -->
<a-form-item label="Schema" v-bind="validateInfos['dataSource.connection.schema']">
<a-input
v-model:value="(formState.dataSource.connection as SnowflakeConnection).schema"
class="nc-extdb-host-database"
/>
</a-form-item>
</a-col>
</a-row>
</template>
<template v-else-if="formState.dataSource.client === ClientType.DATABRICKS">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="Database" v-bind="validateInfos['dataSource.connection.database']">
<a-input
v-model:value="(formState.dataSource.connection as DatabricksConnection).database"
class="nc-extdb-host-database"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="Schema" v-bind="validateInfos['dataSource.connection.schema']">
<a-input
v-model:value="(formState.dataSource.connection as DatabricksConnection).schema"
class="nc-extdb-host-schema"
/>
</a-form-item>
</a-col>
</a-row>
</template>
<template v-else>
<a-row :gutter="24">
<a-col :span="12">
<!-- 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>
</a-col>
<a-col :span="12">
<!-- Schema name -->
<a-form-item
v-if="
([ClientType.MSSQL, ClientType.PG].includes(formState.dataSource.client) ||
[ClientType.MSSQL, ClientType.PG].includes(selectedIntegration?.sub_type)) &&
formState.dataSource.searchPath
"
:label="$t('labels.schemaName')"
v-bind="validateInfos['dataSource.searchPath.0']"
>
<a-input
v-model:value="formState.dataSource.searchPath[0]"
:placeholder="selectedIntegrationSchema && `${selectedIntegrationSchema} (default)`"
/>
</a-form-item>
</a-col>
</a-row>
</template>
</div>
</div> </div>
</div>
<div class="nc-form-section">
<div class="nc-form-section"> <div class="nc-form-section-title">Permissions</div>
<div class="nc-form-section-title">Permissions</div> <div class="nc-form-section-body">
<div class="nc-form-section-body"> <DashboardSettingsDataSourcesSourceRestrictions
<DashboardSettingsDataSourcesSourceRestrictions v-model:allowMetaWrite="allowMetaWrite"
v-model:allowMetaWrite="allowMetaWrite" v-model:allowDataWrite="allowDataWrite"
v-model:allowDataWrite="allowDataWrite" />
/> </div>
</div> </div>
</div> <template
<template v-if="![ClientType.SQLITE, ClientType.SNOWFLAKE, ClientType.DATABRICKS].includes(formState.dataSource.client)"
v-if="![ClientType.SQLITE, ClientType.SNOWFLAKE, ClientType.DATABRICKS].includes(formState.dataSource.client)"
>
<a-collapse
ghost
expand-icon-position="right"
class="nc-source-advanced-options !mt-4"
@change="handleAutoScroll(!!$event?.length, 'nc-source-advanced-options')"
> >
<template #expandIcon="{ isActive }"> <a-collapse v-model:active-key="advancedOptionsExpansionPanel" ghost class="nc-source-advanced-options !mt-4">
<NcButton type="text" size="xsmall"> <template #expandIcon="{ isActive }">
<GeneralIcon <NcButton
icon="chevronDown" type="text"
class="flex-none cursor-pointer transform transition-transform duration-500" size="small"
:class="{ '!rotate-180': isActive }" class="!-ml-1.5"
/> @click="handleUpdateAdvancedOptionsExpansionPanel(!advancedOptionsExpansionPanel.length)"
</NcButton> >
</template>
<a-collapse-panel key="1">
<template #header>
<div class="flex">
<div class="nc-form-section-title">Advanced options</div> <div class="nc-form-section-title">Advanced options</div>
</div>
<GeneralIcon
icon="chevronDown"
class="ml-2 flex-none cursor-pointer transform transition-transform duration-500"
:class="{ '!rotate-180': isActive }"
/>
</NcButton>
</template> </template>
<a-collapse-panel key="1" collapsible="disabled">
<template #header>
<span></span>
</template>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<a-row :gutter="24"> <div class="flex flex-col gap-4">
<a-col :span="12"> <a-row :gutter="24">
<a-form-item :label="$t('labels.inflection.tableName')"> <a-col :span="12">
<NcSelect <a-form-item :label="$t('labels.inflection.tableName')">
v-model:value="formState.inflection.inflectionTable" <NcSelect
class="nc-select-shadow" v-model:value="formState.inflection.inflectionTable"
dropdown-class-name="nc-dropdown-inflection-table-name" class="nc-select-shadow"
> dropdown-class-name="nc-dropdown-inflection-table-name"
<a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }}</a-select-option> >
</NcSelect> <a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }}</a-select-option>
</a-form-item> </NcSelect>
</a-col> </a-form-item>
<a-col :span="12"> </a-col>
<a-form-item :label="$t('labels.inflection.columnName')"> <a-col :span="12">
<NcSelect <a-form-item :label="$t('labels.inflection.columnName')">
v-model:value="formState.inflection.inflectionColumn" <NcSelect
class="nc-select-shadow" v-model:value="formState.inflection.inflectionColumn"
dropdown-class-name="nc-dropdown-inflection-column-name" class="nc-select-shadow"
> dropdown-class-name="nc-dropdown-inflection-column-name"
<a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }}</a-select-option> >
</NcSelect> <a-select-option v-for="tp in inflectionTypes" :key="tp" :value="tp">{{ tp }}</a-select-option>
</a-form-item> </NcSelect>
</a-col> </a-form-item>
</a-row> </a-col>
</a-row>
</div>
</div> </div>
</div> </a-collapse-panel>
</a-collapse-panel> </a-collapse>
</a-collapse> </template>
</template> <div>
<div> <!-- For spacing -->
<!-- For spacing --> </div>
</div> </a-form>
</a-form> </div>
</div>
<div class="nc-edit-source-right-panel">
<DashboardSettingsDataSourcesSupportedDocs />
<NcDivider />
</div> </div>
</div> </div>
<div class="p-4 w-full flex items-center justify-between gap-3 border-t-1 border-gray-200"> <div class="p-4 w-full flex items-center justify-between gap-3 border-t-1 border-gray-200">
@ -624,14 +638,14 @@ const handleAutoScroll = (scroll: boolean, className: string) => {
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.nc-add-source-left-panel { .nc-edit-source-left-panel {
@apply p-6 flex-1 flex justify-center; @apply p-6 flex-1 flex justify-center;
} }
.nc-add-source-right-panel { .nc-edit-source-right-panel {
@apply p-5 w-[320px] border-l-1 border-gray-200 flex flex-col gap-4 bg-gray-50 rounded-br-2xl; @apply p-4 w-[320px] border-l-1 border-gray-200 flex flex-col gap-4 bg-gray-50 rounded-br-2xl;
} }
:deep(.ant-collapse-header) { :deep(.ant-collapse-header) {
@apply !-mt-4 !p-0 flex items-center; @apply !-mt-4 !p-0 flex items-center !cursor-default children:first:flex;
} }
:deep(.ant-collapse-icon-position-right > .ant-collapse-item > .ant-collapse-header .ant-collapse-arrow) { :deep(.ant-collapse-icon-position-right > .ant-collapse-item > .ant-collapse-header .ant-collapse-arrow) {
@apply !right-0; @apply !right-0;

4
packages/nc-gui/components/dashboard/settings/data-sources/SourceRestrictions.vue

@ -12,7 +12,7 @@ const metaWrite = useVModel(props, 'allowMetaWrite', emits)
<template> <template>
<a-form-item class="nc-source-restictions-card"> <a-form-item class="nc-source-restictions-card">
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-1">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<NcTooltip :disabled="!metaWrite" placement="topLeft" class="flex"> <NcTooltip :disabled="!metaWrite" placement="topLeft" class="flex">
<template #title> <template #title>
@ -30,7 +30,7 @@ const metaWrite = useVModel(props, 'allowMetaWrite', emits)
</div> </div>
</a-form-item> </a-form-item>
<a-form-item class="nc-source-restictions-card"> <a-form-item class="nc-source-restictions-card">
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-1">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<a-switch <a-switch
v-model:checked="metaWrite" v-model:checked="metaWrite"

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

@ -125,12 +125,11 @@ const onCreateBaseClick = () => {
data-testid="proj-view-btn__add-new-table" data-testid="proj-view-btn__add-new-table"
@click="openTableCreateDialog()" @click="openTableCreateDialog()"
> >
<div class="flex items-center gap-3"> <GeneralIcon icon="addOutlineBox" class="!h-8 !w-8 !text-brand-500" />
<GeneralIcon icon="addOutlineBox" class="!text-brand-500 !h-5 !w-5" /> <div class="flex flex-col gap-1">
<div class="label">{{ $t('general.create') }} {{ $t('general.new') }} {{ $t('objects.table') }}</div> <div class="label">{{ $t('general.create') }} {{ $t('general.new') }} {{ $t('objects.table') }}</div>
<div class="subtext">Start from scratch.</div>
</div> </div>
<div class="subtext">Start from scratch by creating a new table.</div>
</div> </div>
<div <div
@ -141,13 +140,19 @@ const onCreateBaseClick = () => {
data-testid="proj-view-btn__import-data" data-testid="proj-view-btn__import-data"
@click="isImportModalOpen = true" @click="isImportModalOpen = true"
> >
<div class="flex items-center gap-3"> <GeneralIcon icon="download" class="!h-7.5 !w-7.5 !text-orange-700" />
<GeneralIcon icon="download" class="!text-orange-700 !h-5 !w-5" /> <div class="flex flex-col gap-1">
<div class="label">{{ $t('activity.import') }} {{ $t('general.data') }}</div> <div class="label">{{ $t('activity.import') }} {{ $t('general.data') }}</div>
<div class="subtext">From files & external sources</div>
</div> </div>
<div class="subtext">Quickly bring in existing data from various files & external sources.</div>
</div> </div>
<NcTooltip v-if="isUIAllowed('sourceCreate')" placement="bottom" :disabled="!isDataSourceLimitReached" class="flex-none flex"> <NcTooltip
v-if="isUIAllowed('sourceCreate')"
placement="bottom"
:disabled="!isDataSourceLimitReached"
class="flex-none flex"
>
<template #title> <template #title>
{{ $t('tooltip.reachedSourceLimit') }} {{ $t('tooltip.reachedSourceLimit') }}
</template> </template>
@ -161,28 +166,13 @@ const onCreateBaseClick = () => {
}" }"
@click="onCreateBaseClick" @click="onCreateBaseClick"
> >
<div class="flex items-center gap-3"> <GeneralIcon icon="server1" class="!h-7 !w-7 !text-green-700" />
<GeneralIcon icon="server1" class="!text-green-700 !h-5 !w-5" /> <div class="flex flex-col gap-1">
<div class="label">{{ $t('labels.connectDataSource') }}</div> <div class="label">{{ $t('labels.connectDataSource') }}</div>
<div class="subtext">In realtime to external databases.</div>
</div> </div>
<div class="subtext">Connect directly in realtime to external databases.</div>
</div> </div>
</NcTooltip> </NcTooltip>
<div
v-if="isUIAllowed('tableCreate', { source: base?.sources?.[0] })"
v-e="['c:table:create-source']"
role="button"
class="nc-base-view-all-table-btn"
data-testid="proj-view-btn__create-source"
@click="syncDataModalOpen = true"
>
<div class="flex items-center gap-3">
<GeneralIcon icon="refresh" class="!text-blue-700 !h-5 !w-5" />
<div class="label capitalize">{{ $t('labels.syncData') }}</div>
</div>
<div class="subtext">Keep your data updated and in sync across multiple sources.</div>
</div>
</div> </div>
<div <div
v-if="base?.isLoading" v-if="base?.isLoading"
@ -277,13 +267,13 @@ const onCreateBaseClick = () => {
<style lang="scss" scoped> <style lang="scss" scoped>
.nc-base-view-all-table-btn { .nc-base-view-all-table-btn {
@apply flex-none flex flex-col gap-y-3 px-3 py-5 bg-gray-50 rounded-xl border-1 border-gray-100 min-w-[230px] max-w-[245px] cursor-pointer text-gray-800 hover:(bg-gray-100 border-gray-200) transition-all duration-300; @apply flex-none flex flex-col gap-y-3 p-4 bg-gray-50 rounded-xl border-1 border-gray-100 min-w-[230px] max-w-[245px] cursor-pointer text-gray-800 hover:(bg-gray-100 border-gray-200) transition-all duration-300;
&:hover { &:hover {
box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.08); box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.08);
} }
.nc-icon { .nc-icon {
@apply h-6 w-6; @apply h-10 w-10;
} }
.label { .label {

2
packages/nc-gui/components/project/SyncDataModal.vue

@ -22,7 +22,7 @@ const upvotesData = computed(() => {
const handleUpvote = (syncDataType: SyncDataType) => { const handleUpvote = (syncDataType: SyncDataType) => {
if (upvotesData.value.has(syncDataType)) return if (upvotesData.value.has(syncDataType)) return
$e(`a:sync-request:${syncDataType}`) $e(`a:integration-request:${syncDataType}`)
updateSyncDataUpvotes([...syncDataUpvotes.value, syncDataType]) updateSyncDataUpvotes([...syncDataUpvotes.value, syncDataType])
} }

2
packages/nc-gui/components/workspace/integrations/List.vue

@ -225,7 +225,7 @@ onKeyStroke('ArrowDown', onDown)
<div class="flex justify-between gap-12"> <div class="flex justify-between gap-12">
<div class="text-sm font-normal text-gray-600"> <div class="text-sm font-normal text-gray-600">
<div> <div>
Connections simplify managing stored configurations for different integrations. Manage connections for your integrations.
<a target="_blank" rel="noopener noreferrer"> Learn more </a> <a target="_blank" rel="noopener noreferrer"> Learn more </a>
</div> </div>
</div> </div>

5
packages/nc-gui/components/workspace/integrations/newAvailableList.vue

@ -83,10 +83,7 @@ const handleAddIntegration = (type: typeof integrationType) => {
'max-w-[740px]': !isModal, 'max-w-[740px]': !isModal,
}" }"
> >
<div> <div>Connect integrations with NocoDB. <a target="_blank" rel="noopener noreferrer"> Learn more </a></div>
Centralise your operations by aggregating information from various external platforms into NocoDB. Select from the
available integrations below to get started. <a target="_blank" rel="noopener noreferrer"> Learn more </a>
</div>
</div> </div>
<div class="integration-type-wrapper"> <div class="integration-type-wrapper">

4
packages/nc-gui/lang/en.json

@ -1787,8 +1787,8 @@
"passwordChanged": "Password changed successfully. Please login again.", "passwordChanged": "Password changed successfully. Please login again.",
"settingsSaved": "Settings saved successfully", "settingsSaved": "Settings saved successfully",
"roleUpdated": "Role updated successfully", "roleUpdated": "Role updated successfully",
"connectionAdded": "Connection Successfully Created", "connectionAdded": "Integration connected successfully",
"connectionAddedDesc": "All Base owners & creators in this Workspace can now use this connection to easily add a new Data Source to their Base." "connectionAddedDesc": "Base owners and creators can now add a data source without re-entering credentials."
} }
} }
} }

Loading…
Cancel
Save