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 populateName = (v: string) => {
if (selectedIntegration.value) return
formState.value.dataSource.connection.database = `${v.trim()}_noco`
}
const { validate, validateInfos, clearValidate } = useForm(formState.value, validators)
const onClientChange = () => {
formState.value.dataSource = { ...getDefaultConnectionConfig(formState.value.dataSource.client) }
populateName(formState.value.title)
}
const inflectionTypes = ['camelize', 'none']
@ -322,7 +316,6 @@ watch(
onMounted(async () => {
await loadIntegrations(true, base.value?.id)
formState.value.title = await generateUniqueName()
populateName(formState.value.title)
nextTick(() => {
// 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">
<GeneralIcon icon="server1" class="!text-green-700 !h-4 !w-4" />
</div>
<div class="flex-1">
<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-1 text-base font-weight-700">Add Data Source</div>
<div class="flex items-center gap-3">
<div class="w-[15px] h-[15px] cursor-pointer" @dblclick="onEasterEgg"></div>
@ -471,7 +461,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
<NcButton
size="small"
type="primary"
:disabled="!testSuccess"
:disabled="!testSuccess || !selectedIntegration"
:loading="creatingSource"
class="nc-extdb-btn-submit"
@click="createSource"
@ -483,7 +473,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
</NcButton>
</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="create-source bg-white relative flex flex-col gap-2 w-full max-w-[768px]">
<a-form
@ -496,12 +486,11 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
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-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" @input="populateName(formState.title)" />
<a-form-item label="Data Source Name" v-bind="validateInfos.title">
<a-input v-model:value="formState.title" />
</a-form-item>
</a-col>
</a-row>
@ -560,162 +549,156 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
</div>
</div>
<div class="nc-form-section">
<div class="flex items-center justify-between">
<div class="nc-form-section-title">Connection details</div>
</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-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>
<template v-if="selectedIntegration">
<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 class="nc-form-section">
<div class="nc-form-section-title">Permissions</div>
<div class="nc-form-section-body">
<DashboardSettingsDataSourcesSourceRestrictions
v-model:allowMetaWrite="allowMetaWrite"
v-model:allowDataWrite="allowDataWrite"
/>
<div class="nc-form-section">
<div class="nc-form-section-title">Permissions</div>
<div class="nc-form-section-body">
<DashboardSettingsDataSourcesSourceRestrictions
v-model:allowMetaWrite="allowMetaWrite"
v-model:allowDataWrite="allowDataWrite"
/>
</div>
</div>
</div>
<template
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
v-if="![ClientType.SQLITE, ClientType.SNOWFLAKE, ClientType.DATABRICKS].includes(formState.dataSource.client)"
>
<template #expandIcon="{ isActive }">
<NcButton
type="text"
size="small"
class="!-ml-1.5"
@click="handleUpdateAdvancedOptionsExpansionPanel(!advancedOptionsExpansionPanel.length)"
>
<div class="nc-form-section-title">Advanced options</div>
<GeneralIcon
icon="chevronDown"
class="ml-2 flex-none cursor-pointer transform transition-transform duration-500"
:class="{ '!rotate-180': isActive }"
/>
</NcButton>
</template>
<a-collapse-panel key="1" collapsible="disabled">
<template #header>
<span></span>
<a-collapse v-model:active-key="advancedOptionsExpansionPanel" ghost class="nc-source-advanced-options !mt-4">
<template #expandIcon="{ isActive }">
<NcButton
type="text"
size="small"
class="!-ml-1.5"
@click="handleUpdateAdvancedOptionsExpansionPanel(!advancedOptionsExpansionPanel.length)"
>
<div class="nc-form-section-title">Advanced options</div>
<GeneralIcon
icon="chevronDown"
class="ml-2 flex-none cursor-pointer transform transition-transform duration-500"
:class="{ '!rotate-180': isActive }"
/>
</NcButton>
</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">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item :label="$t('labels.inflection.tableName')">
<NcSelect
v-model:value="formState.inflection.inflectionTable"
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-form-item>
</a-col>
<a-col :span="12">
<a-form-item :label="$t('labels.inflection.columnName')">
<NcSelect
v-model:value="formState.inflection.inflectionColumn"
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-form-item>
</a-col>
</a-row>
<div class="flex flex-col gap-4">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item :label="$t('labels.inflection.tableName')">
<NcSelect
v-model:value="formState.inflection.inflectionTable"
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-form-item>
</a-col>
<a-col :span="12">
<a-form-item :label="$t('labels.inflection.columnName')">
<NcSelect
v-model:value="formState.inflection.inflectionColumn"
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-form-item>
</a-col>
</a-row>
</div>
</div>
</div>
</a-collapse-panel>
</a-collapse>
</a-collapse-panel>
</a-collapse>
</template>
</template>
<div>
<!-- For spacing -->
</div>
@ -726,7 +709,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
</div>
</div>
<div class="nc-add-source-right-panel">
<DashboardSettingsDataSourcesSupportedDocs/>
<DashboardSettingsDataSourcesSupportedDocs />
<NcDivider />
</div>
</div>
@ -739,7 +722,7 @@ const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [Integrati
@apply p-6 flex-1 flex justify-center;
}
.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) {
@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 advancedOptionsExpansionPanel = ref<string[]>([])
const onEasterEgg = () => {
easterEggCount.value += 1
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
const handleAutoScroll = (scroll: boolean, className: string) => {
function handleAutoScroll(scroll: boolean, className: string) {
if (scroll) {
if (timer) {
clearTimeout(timer)
@ -357,221 +368,224 @@ const handleAutoScroll = (scroll: boolean, className: string) => {
<template>
<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-w-[992px] p-6 mx-auto">
<a-form
ref="form"
:model="formState"
hide-required-mark
name="external-base-create-form"
layout="vertical"
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-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">
<div class="h-full max-h-[calc(100%_-_65px)] flex">
<div class="nc-edit-source-left-panel nc-scrollbar-thin">
<div class="h-full max-w-[768px] mx-auto">
<a-form
ref="form"
:model="formState"
hide-required-mark
name="external-base-create-form"
layout="vertical"
no-style
class="flex flex-col gap-5.5"
>
<div class="nc-form-section">
<div class="nc-form-section-body">
<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 label="Data 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>
</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 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>
</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 class="nc-form-section">
<div class="nc-form-section-title">Permissions</div>
<div class="nc-form-section-body">
<DashboardSettingsDataSourcesSourceRestrictions
v-model:allowMetaWrite="allowMetaWrite"
v-model:allowDataWrite="allowDataWrite"
/>
<div class="nc-form-section">
<div class="nc-form-section-title">Permissions</div>
<div class="nc-form-section-body">
<DashboardSettingsDataSourcesSourceRestrictions
v-model:allowMetaWrite="allowMetaWrite"
v-model:allowDataWrite="allowDataWrite"
/>
</div>
</div>
</div>
<template
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
v-if="![ClientType.SQLITE, ClientType.SNOWFLAKE, ClientType.DATABRICKS].includes(formState.dataSource.client)"
>
<template #expandIcon="{ isActive }">
<NcButton type="text" size="xsmall">
<GeneralIcon
icon="chevronDown"
class="flex-none cursor-pointer transform transition-transform duration-500"
:class="{ '!rotate-180': isActive }"
/>
</NcButton>
</template>
<a-collapse-panel key="1">
<template #header>
<div class="flex">
<a-collapse v-model:active-key="advancedOptionsExpansionPanel" ghost class="nc-source-advanced-options !mt-4">
<template #expandIcon="{ isActive }">
<NcButton
type="text"
size="small"
class="!-ml-1.5"
@click="handleUpdateAdvancedOptionsExpansionPanel(!advancedOptionsExpansionPanel.length)"
>
<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>
<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">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item :label="$t('labels.inflection.tableName')">
<NcSelect
v-model:value="formState.inflection.inflectionTable"
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-form-item>
</a-col>
<a-col :span="12">
<a-form-item :label="$t('labels.inflection.columnName')">
<NcSelect
v-model:value="formState.inflection.inflectionColumn"
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-form-item>
</a-col>
</a-row>
<div class="flex flex-col gap-4">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item :label="$t('labels.inflection.tableName')">
<NcSelect
v-model:value="formState.inflection.inflectionTable"
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-form-item>
</a-col>
<a-col :span="12">
<a-form-item :label="$t('labels.inflection.columnName')">
<NcSelect
v-model:value="formState.inflection.inflectionColumn"
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-form-item>
</a-col>
</a-row>
</div>
</div>
</div>
</a-collapse-panel>
</a-collapse>
</template>
<div>
<!-- For spacing -->
</div>
</a-form>
</a-collapse-panel>
</a-collapse>
</template>
<div>
<!-- For spacing -->
</div>
</a-form>
</div>
</div>
<div class="nc-edit-source-right-panel">
<DashboardSettingsDataSourcesSupportedDocs />
<NcDivider />
</div>
</div>
<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>
<style lang="scss" scoped>
.nc-add-source-left-panel {
.nc-edit-source-left-panel {
@apply p-6 flex-1 flex justify-center;
}
.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;
.nc-edit-source-right-panel {
@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) {
@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) {
@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>
<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">
<NcTooltip :disabled="!metaWrite" placement="topLeft" class="flex">
<template #title>
@ -30,7 +30,7 @@ const metaWrite = useVModel(props, 'allowMetaWrite', emits)
</div>
</a-form-item>
<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">
<a-switch
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"
@click="openTableCreateDialog()"
>
<div class="flex items-center gap-3">
<GeneralIcon icon="addOutlineBox" class="!text-brand-500 !h-5 !w-5" />
<GeneralIcon icon="addOutlineBox" class="!h-8 !w-8 !text-brand-500" />
<div class="flex flex-col gap-1">
<div class="label">{{ $t('general.create') }} {{ $t('general.new') }} {{ $t('objects.table') }}</div>
<div class="subtext">Start from scratch.</div>
</div>
<div class="subtext">Start from scratch by creating a new table.</div>
</div>
<div
@ -141,13 +140,19 @@ const onCreateBaseClick = () => {
data-testid="proj-view-btn__import-data"
@click="isImportModalOpen = true"
>
<div class="flex items-center gap-3">
<GeneralIcon icon="download" class="!text-orange-700 !h-5 !w-5" />
<GeneralIcon icon="download" class="!h-7.5 !w-7.5 !text-orange-700" />
<div class="flex flex-col gap-1">
<div class="label">{{ $t('activity.import') }} {{ $t('general.data') }}</div>
<div class="subtext">From files & external sources</div>
</div>
<div class="subtext">Quickly bring in existing data from various files & external sources.</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>
{{ $t('tooltip.reachedSourceLimit') }}
</template>
@ -161,28 +166,13 @@ const onCreateBaseClick = () => {
}"
@click="onCreateBaseClick"
>
<div class="flex items-center gap-3">
<GeneralIcon icon="server1" class="!text-green-700 !h-5 !w-5" />
<GeneralIcon icon="server1" class="!h-7 !w-7 !text-green-700" />
<div class="flex flex-col gap-1">
<div class="label">{{ $t('labels.connectDataSource') }}</div>
<div class="subtext">In realtime to external databases.</div>
</div>
<div class="subtext">Connect directly in realtime to external databases.</div>
</div>
</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
v-if="base?.isLoading"
@ -277,13 +267,13 @@ const onCreateBaseClick = () => {
<style lang="scss" scoped>
.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 {
box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.08);
}
.nc-icon {
@apply h-6 w-6;
@apply h-10 w-10;
}
.label {

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

@ -22,7 +22,7 @@ const upvotesData = computed(() => {
const handleUpvote = (syncDataType: SyncDataType) => {
if (upvotesData.value.has(syncDataType)) return
$e(`a:sync-request:${syncDataType}`)
$e(`a:integration-request:${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="text-sm font-normal text-gray-600">
<div>
Connections simplify managing stored configurations for different integrations.
Manage connections for your integrations.
<a target="_blank" rel="noopener noreferrer"> Learn more </a>
</div>
</div>

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

@ -83,10 +83,7 @@ const handleAddIntegration = (type: typeof integrationType) => {
'max-w-[740px]': !isModal,
}"
>
<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>Connect integrations with NocoDB. <a target="_blank" rel="noopener noreferrer"> Learn more </a></div>
</div>
<div class="integration-type-wrapper">

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

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

Loading…
Cancel
Save