Files
nocodb/packages/nc-gui/components/dlg/share-and-collaborate/ShareBase.vue
2026-03-13 13:31:07 +00:00

186 lines
5.0 KiB
Vue

<script setup lang="ts">
import type { StringOrNullType } from 'nocodb-sdk'
interface ShareBase {
uuid?: string
url?: string
role?: string
fk_custom_url_id?: StringOrNullType
}
enum ShareBaseRole {
Editor = 'editor',
Viewer = 'viewer',
}
const { dashboardUrl } = useDashboard()
const { $api, $e } = useNuxtApp()
const { showEEFeatures } = useEeConfig()
const { copy } = useCopy()
const sharedBase = ref<null | ShareBase>(null)
const { base, isPrivateBase } = storeToRefs(useBase())
const { appInfo } = useGlobal()
const url = computed(() => {
if (!sharedBase.value || !sharedBase.value.uuid) return ''
return encodeURI(`${dashboardUrl.value}/base/${sharedBase.value.uuid}`)
})
const loadBase = async () => {
try {
if (!base.value.id) return
const res = await $api.base.sharedBaseGet(base.value.id)
sharedBase.value = {
uuid: res.uuid,
url: res.url,
role: res.roles,
fk_custom_url_id: res?.fk_custom_url_id || null,
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
const createShareBase = async (role = ShareBaseRole.Viewer, custUrl = undefined) => {
try {
if (!base.value.id) return
const res = await $api.base.sharedBaseUpdate(base.value.id, {
roles: role,
original_url: url.value,
...(custUrl !== undefined ? { custom_url_path: custUrl ?? null } : {}),
})
sharedBase.value = res ?? {}
sharedBase.value!.role = role
base.value.uuid = res.uuid
if (custUrl !== undefined) {
sharedBase.value!.fk_custom_url_id = res.fk_custom_url_id
base.value.fk_custom_url_id = res.fk_custom_url_id
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
$e('a:shared-base:enable', { role })
}
const disableSharedBase = async () => {
try {
if (!base.value.id) return
await $api.base.sharedBaseDisable(base.value.id)
sharedBase.value = null
base.value.uuid = undefined
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
$e('a:shared-base:disable')
}
onMounted(() => {
if (!sharedBase.value) {
loadBase()
}
})
const isSharedBaseEnabled = computed(() => {
// If base is private, then we have to restrict sharing
if (isPrivateBase.value) return false
return !!sharedBase.value?.uuid
})
const isToggleBaseLoading = ref(false)
const isRoleToggleLoading = ref(false)
const toggleSharedBase = async () => {
if (isToggleBaseLoading.value) return
isToggleBaseLoading.value = true
try {
if (isSharedBaseEnabled.value) {
await disableSharedBase()
} else {
await createShareBase()
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
} finally {
isToggleBaseLoading.value = false
}
}
const onRoleToggle = async () => {
if (!sharedBase.value) return
if (isRoleToggleLoading.value) return
isRoleToggleLoading.value = true
try {
await createShareBase(ShareBaseRole.Viewer)
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
} finally {
isRoleToggleLoading.value = false
}
}
const copyCustomUrl = async (custUrl = '') => {
return await copy(`${appInfo.value.ncSiteUrl}/p/${encodeURIComponent(custUrl)}`)
}
</script>
<template>
<div class="flex flex-col py-2 px-3 gap-2 w-full" data-testid="nc-share-base-sub-modal">
<div class="flex flex-col w-full p-3 border-1 border-nc-border-gray-light rounded-md">
<div class="flex flex-row w-full justify-between">
<div class="text-nc-content-gray-emphasis font-medium">{{ $t('activity.enablePublicAccess') }}</div>
<a-switch
v-if="!isPrivateBase"
v-e="['c:share:base:enable:toggle']"
:checked="isSharedBaseEnabled"
:loading="isToggleBaseLoading"
class="ml-2"
@click="toggleSharedBase"
/>
<div v-else class="text-nc-content-gray-muted">{{ $t('labels.sharingRestricted') }}</div>
</div>
<div v-if="isSharedBaseEnabled" class="flex flex-col gap-3 w-full mt-3 border-t-1 pt-3 border-nc-border-gray-light">
<GeneralCopyUrl v-model:url="url" />
<DlgShareAndCollaborateCustomUrl
v-if="sharedBase?.uuid && showEEFeatures"
:id="sharedBase.fk_custom_url_id"
:backend-url="appInfo.ncSiteUrl"
:copy-custom-url="copyCustomUrl"
:disabled="isPrivateBase"
@update-custom-url="createShareBase(undefined, $event)"
/>
<div
v-if="!appInfo.ee && sharedBase?.role === ShareBaseRole.Editor"
class="flex flex-row justify-between bg-nc-bg-gray-extralight px-3 py-2 rounded-md"
>
<div class="text-nc-content-gray-extreme">{{ $t('activity.editingAccess') }}</div>
<a-switch
v-e="['c:share:base:role:toggle']"
:loading="isRoleToggleLoading"
:checked="sharedBase?.role === ShareBaseRole.Editor"
class="ml-2"
@click="onRoleToggle"
/>
</div>
</div>
</div>
</div>
</template>