|
|
@ -2,69 +2,90 @@ |
|
|
|
import { Empty } from 'ant-design-vue' |
|
|
|
import { Empty } from 'ant-design-vue' |
|
|
|
import type { BaseType } from 'nocodb-sdk' |
|
|
|
import type { BaseType } from 'nocodb-sdk' |
|
|
|
import CreateBase from './data-sources/CreateBase.vue' |
|
|
|
import CreateBase from './data-sources/CreateBase.vue' |
|
|
|
|
|
|
|
import Metadata from './Metadata.vue' |
|
|
|
|
|
|
|
import UIAcl from './UIAcl.vue' |
|
|
|
|
|
|
|
import Erd from './Erd.vue' |
|
|
|
|
|
|
|
import { DataSourcesSubTab } from '~/lib' |
|
|
|
import { useNuxtApp, useProject } from '#imports' |
|
|
|
import { useNuxtApp, useProject } from '#imports' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
interface Props { |
|
|
|
|
|
|
|
state: string |
|
|
|
|
|
|
|
reload: boolean |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const props = defineProps<Props>() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const emits = defineEmits(['update:state', 'update:reload']) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const vModel = useVModel(props, 'state', emits) |
|
|
|
|
|
|
|
const vReload = useVModel(props, 'reload', emits) |
|
|
|
|
|
|
|
|
|
|
|
const { $api } = useNuxtApp() |
|
|
|
const { $api } = useNuxtApp() |
|
|
|
const { project } = useProject() |
|
|
|
const { project } = useProject() |
|
|
|
|
|
|
|
|
|
|
|
let isLoading = $ref(false) |
|
|
|
|
|
|
|
let sources = $ref<BaseType[]>([]) |
|
|
|
let sources = $ref<BaseType[]>([]) |
|
|
|
const newSourceTab = $ref(false) |
|
|
|
let activeBaseId = $ref('') |
|
|
|
|
|
|
|
let metadiffbases = $ref<string[]>([]) |
|
|
|
|
|
|
|
|
|
|
|
async function loadBases() { |
|
|
|
async function loadBases() { |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (!project.value?.id) return |
|
|
|
if (!project.value?.id) return |
|
|
|
|
|
|
|
|
|
|
|
isLoading = true |
|
|
|
vReload.value = true |
|
|
|
const baseList = await $api.base.list(project.value?.id) |
|
|
|
const baseList = await $api.base.list(project.value?.id) |
|
|
|
if (baseList.bases.list && baseList.bases.list.length) { |
|
|
|
if (baseList.bases.list && baseList.bases.list.length) { |
|
|
|
sources = baseList.bases.list |
|
|
|
sources = baseList.bases.list |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
loadMetaDiff() |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.error(e) |
|
|
|
console.error(e) |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
isLoading = false |
|
|
|
vReload.value = false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function loadMetaDiff() { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (!project.value?.id) return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
metadiffbases = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const metadiff = await $api.project.metaDiffGet(project.value?.id) |
|
|
|
|
|
|
|
for (const model of metadiff) { |
|
|
|
|
|
|
|
if (model.detectedChanges?.length > 0) { |
|
|
|
|
|
|
|
metadiffbases.push(model.base_id) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
console.error(e) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const baseAction = (baseId: string, action: string) => { |
|
|
|
|
|
|
|
activeBaseId = baseId |
|
|
|
|
|
|
|
vModel.value = action |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
|
onMounted(async () => { |
|
|
|
if (sources.length === 0) { |
|
|
|
if (sources.length === 0) { |
|
|
|
await loadBases() |
|
|
|
await loadBases() |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch( |
|
|
|
|
|
|
|
() => props.reload, |
|
|
|
|
|
|
|
async (reload) => { |
|
|
|
|
|
|
|
if (reload) { |
|
|
|
|
|
|
|
await loadBases() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
) |
|
|
|
</script> |
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
|
|
<template> |
|
|
|
<template> |
|
|
|
<div class="flex flex-row w-full"> |
|
|
|
<div class="flex flex-row w-full"> |
|
|
|
<div class="flex flex-col w-full"> |
|
|
|
<div class="flex flex-col w-full"> |
|
|
|
<div class="flex flex-row justify-end items-center w-full mb-4"> |
|
|
|
<div v-if="props.state === ''" class="max-h-600px overflow-y-auto"> |
|
|
|
<a-button class="self-start nc-btn-new-datasource" @click="newSourceTab = !newSourceTab"> |
|
|
|
|
|
|
|
<div v-if="newSourceTab" class="flex items-center gap-2 text-gray-600 font-light"> |
|
|
|
|
|
|
|
<MdiClose class="text-lg group-hover:text-accent" /> |
|
|
|
|
|
|
|
Cancel |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-else class="flex items-center gap-2 text-gray-600 font-light"> |
|
|
|
|
|
|
|
<MdiDatabaseOutline class="text-lg group-hover:text-accent" /> |
|
|
|
|
|
|
|
New |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</a-button> |
|
|
|
|
|
|
|
<!-- Reload --> |
|
|
|
|
|
|
|
<a-button |
|
|
|
|
|
|
|
v-if="!newSourceTab" |
|
|
|
|
|
|
|
v-e="['a:proj-meta:meta-data:reload']" |
|
|
|
|
|
|
|
class="self-start nc-btn-metasync-reload" |
|
|
|
|
|
|
|
@click="loadBases" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<div class="flex items-center gap-2 text-gray-600 font-light"> |
|
|
|
|
|
|
|
<MdiReload :class="{ 'animate-infinite animate-spin !text-success': isLoading }" /> |
|
|
|
|
|
|
|
{{ $t('general.reload') }} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</a-button> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-if="newSourceTab" class="max-h-600px overflow-y-auto"> |
|
|
|
|
|
|
|
<CreateBase /> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-else class="max-h-600px overflow-y-auto"> |
|
|
|
|
|
|
|
<a-table |
|
|
|
<a-table |
|
|
|
class="w-full" |
|
|
|
class="w-full" |
|
|
|
size="small" |
|
|
|
size="small" |
|
|
@ -75,27 +96,68 @@ onMounted(async () => { |
|
|
|
" |
|
|
|
" |
|
|
|
:data-source="sources ?? []" |
|
|
|
:data-source="sources ?? []" |
|
|
|
:pagination="false" |
|
|
|
:pagination="false" |
|
|
|
:loading="isLoading" |
|
|
|
:loading="vReload" |
|
|
|
bordered |
|
|
|
bordered |
|
|
|
> |
|
|
|
> |
|
|
|
<template #emptyText> <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" :description="$t('labels.noData')" /> </template> |
|
|
|
<template #emptyText> <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" :description="$t('labels.noData')" /> </template> |
|
|
|
<a-table-column key="type" title="Type" data-index="type" :width="180"> |
|
|
|
|
|
|
|
<template #default="{ text }">{{ text }}</template> |
|
|
|
|
|
|
|
</a-table-column> |
|
|
|
|
|
|
|
<a-table-column key="alias" title="Name" data-index="alias"> |
|
|
|
<a-table-column key="alias" title="Name" data-index="alias"> |
|
|
|
<template #default="{ text, record }">{{ record.is_meta ? 'BASE' : text }}</template> |
|
|
|
<template #default="{ text, record }"> |
|
|
|
|
|
|
|
{{ record.is_meta ? 'BASE' : text }} <span class="text-gray-400 text-xs">({{ record.type }})</span> |
|
|
|
|
|
|
|
</template> |
|
|
|
</a-table-column> |
|
|
|
</a-table-column> |
|
|
|
<a-table-column key="action" :title="$t('labels.actions')" :width="180"> |
|
|
|
<a-table-column key="action" :title="$t('labels.actions')" :width="180"> |
|
|
|
<template #default="{ record }"> |
|
|
|
<template #default="{ record }"> |
|
|
|
<div class="flex items-center gap-2"> |
|
|
|
<div class="flex items-center gap-2"> |
|
|
|
<MdiEditOutline v-e="['c:base:edit:rename']" class="nc-action-btn" /> |
|
|
|
<a-tooltip> |
|
|
|
|
|
|
|
<template #title>Sync Metadata {{ metadiffbases.includes(record.id) ? '(Out of sync)' : '' }}</template> |
|
|
|
<MdiDeleteOutline class="nc-action-btn" /> |
|
|
|
<MdiDatabaseSync |
|
|
|
|
|
|
|
class="nc-action-btn cursor-pointer outline-0" |
|
|
|
|
|
|
|
:class="metadiffbases.includes(record.id) ? 'text-primary' : ''" |
|
|
|
|
|
|
|
@click="baseAction(record.id, DataSourcesSubTab.Metadata)" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</a-tooltip> |
|
|
|
|
|
|
|
<a-tooltip> |
|
|
|
|
|
|
|
<template #title>UI ACL</template> |
|
|
|
|
|
|
|
<MdiDatabaseLockOutline |
|
|
|
|
|
|
|
class="nc-action-btn cursor-pointer outline-0" |
|
|
|
|
|
|
|
@click="baseAction(record.id, DataSourcesSubTab.UIAcl)" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</a-tooltip> |
|
|
|
|
|
|
|
<a-tooltip> |
|
|
|
|
|
|
|
<template #title>ERD</template> |
|
|
|
|
|
|
|
<MdiGraphOutline |
|
|
|
|
|
|
|
class="nc-action-btn cursor-pointer outline-0" |
|
|
|
|
|
|
|
@click="baseAction(record.id, DataSourcesSubTab.ERD)" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</a-tooltip> |
|
|
|
|
|
|
|
<a-tooltip> |
|
|
|
|
|
|
|
<template #title>Edit</template> |
|
|
|
|
|
|
|
<MdiEditOutline |
|
|
|
|
|
|
|
class="nc-action-btn cursor-pointer outline-0" |
|
|
|
|
|
|
|
@click="baseAction(record.id, DataSourcesSubTab.Edit)" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</a-tooltip> |
|
|
|
|
|
|
|
<a-tooltip> |
|
|
|
|
|
|
|
<template #title>Delete</template> |
|
|
|
|
|
|
|
<MdiDeleteOutline class="nc-action-btn cursor-pointer outline-0" /> |
|
|
|
|
|
|
|
</a-tooltip> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</a-table-column> |
|
|
|
</a-table-column> |
|
|
|
</a-table> |
|
|
|
</a-table> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-else-if="props.state === DataSourcesSubTab.New" class="max-h-600px overflow-y-auto"> |
|
|
|
|
|
|
|
<CreateBase /> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-else-if="props.state === DataSourcesSubTab.Metadata" class="max-h-600px overflow-y-auto"> |
|
|
|
|
|
|
|
<Metadata :base-id="activeBaseId" /> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-else-if="props.state === DataSourcesSubTab.UIAcl" class="max-h-600px overflow-y-auto"> |
|
|
|
|
|
|
|
<UIAcl :base-id="activeBaseId" /> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-else-if="props.state === DataSourcesSubTab.ERD" class="max-h-600px overflow-y-auto"> |
|
|
|
|
|
|
|
<Erd :base-id="activeBaseId" /> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|