mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
6.8 KiB
250 lines
6.8 KiB
<script setup lang="ts"> |
|
interface ShareBase { |
|
uuid?: string |
|
url?: string |
|
role?: string |
|
} |
|
|
|
enum ShareBaseRole { |
|
Editor = 'editor', |
|
Viewer = 'viewer', |
|
} |
|
|
|
const { t } = useI18n() |
|
|
|
const { dashboardUrl } = useDashboard() |
|
|
|
const { $api, $e } = useNuxtApp() |
|
|
|
const sharedBase = ref<null | ShareBase>(null) |
|
|
|
const showEditBaseDropdown = ref(false) |
|
|
|
const { base } = storeToRefs(useBase()) |
|
|
|
const { copy } = useCopy() |
|
|
|
const url = computed(() => |
|
sharedBase.value && sharedBase.value.uuid ? `${dashboardUrl.value}#/base/${sharedBase.value.uuid}` : null, |
|
) |
|
|
|
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, |
|
} |
|
} catch (e: any) { |
|
message.error(await extractSdkResponseErrorMsg(e)) |
|
} |
|
} |
|
|
|
const createShareBase = async (role = ShareBaseRole.Viewer) => { |
|
try { |
|
if (!base.value.id) return |
|
|
|
const res = await $api.base.sharedBaseUpdate(base.value.id, { |
|
roles: role, |
|
}) |
|
|
|
sharedBase.value = res ?? {} |
|
sharedBase.value!.role = role |
|
} 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 |
|
} catch (e: any) { |
|
message.error(await extractSdkResponseErrorMsg(e)) |
|
} |
|
|
|
$e('a:shared-base:disable') |
|
} |
|
|
|
const recreate = async () => { |
|
try { |
|
if (!base.value.id) return |
|
|
|
const createdShareBase = await $api.base.sharedBaseCreate(base.value.id, { |
|
roles: sharedBase.value?.role || ShareBaseRole.Viewer, |
|
}) |
|
|
|
const newBase = createdShareBase || {} |
|
|
|
sharedBase.value = { ...newBase, role: sharedBase.value?.role } |
|
} catch (e: any) { |
|
message.error(await extractSdkResponseErrorMsg(e)) |
|
} |
|
|
|
$e('a:shared-base:recreate') |
|
} |
|
|
|
const copyUrl = async () => { |
|
if (!url.value) return |
|
try { |
|
await copy(url.value) |
|
|
|
// Copied shareable base url to clipboard! |
|
message.success(t('msg.success.shareableURLCopied')) |
|
} catch (e: any) { |
|
message.error(e.message) |
|
} |
|
|
|
$e('c:shared-base:copy-url') |
|
} |
|
|
|
const navigateToSharedBase = () => { |
|
if (!url.value) return |
|
|
|
window.open(url.value, '_blank') |
|
|
|
$e('c:shared-base:open-url') |
|
} |
|
|
|
const generateEmbeddableIframe = async () => { |
|
if (!url.value) return |
|
try { |
|
await copy(`<iframe |
|
class="nc-embed" |
|
src="${url.value}?embed" |
|
frameborder="0" |
|
width="100%" |
|
height="700" |
|
style="background: transparent; border: 1px solid #ddd"></iframe>`) |
|
|
|
// Copied embeddable html code! |
|
message.success(t('msg.success.embeddableHTMLCodeCopied')) |
|
} catch (e: any) { |
|
message.error(e.message) |
|
} |
|
$e('c:shared-base:copy-embed-frame') |
|
} |
|
|
|
onMounted(() => { |
|
if (!sharedBase.value) { |
|
loadBase() |
|
} |
|
}) |
|
</script> |
|
|
|
<template> |
|
<div class="flex flex-col gap-2 w-full" data-testid="nc-share-base-sub-modal"> |
|
<!-- Generate publicly shareable readonly source --> |
|
<div class="flex text-xs text-gray-500 justify-start ml-1">{{ $t('msg.info.generatePublicShareableReadonlyBase') }}</div> |
|
|
|
<div class="flex flex-row justify-between mx-1"> |
|
<a-dropdown v-model="showEditBaseDropdown" class="flex" overlay-class-name="nc-dropdown-shared-base-toggle"> |
|
<a-button> |
|
<div class="flex flex-row rounded-md items-center space-x-2 nc-disable-shared-base"> |
|
<div v-if="sharedBase?.uuid">{{ $t('activity.shareBase.enable') }}</div> |
|
<div v-else>{{ $t('activity.shareBase.disable') }}</div> |
|
<IcRoundKeyboardArrowDown class="h-[1rem]" /> |
|
</div> |
|
</a-button> |
|
|
|
<template #overlay> |
|
<a-menu> |
|
<a-menu-item> |
|
<div v-if="sharedBase?.uuid" class="py-3" @click="disableSharedBase">{{ $t('activity.shareBase.disable') }}</div> |
|
<div v-else class="py-3" @click="createShareBase(ShareBaseRole.Viewer)">{{ $t('activity.shareBase.enable') }}</div> |
|
</a-menu-item> |
|
</a-menu> |
|
</template> |
|
</a-dropdown> |
|
|
|
<a-select |
|
v-if="sharedBase?.uuid" |
|
v-model:value="sharedBase.role" |
|
class="flex nc-shared-base-role" |
|
dropdown-class-name="nc-dropdown-share-base-role" |
|
> |
|
<template #suffixIcon> |
|
<div class="flex flex-row"> |
|
<IcRoundKeyboardArrowDown class="text-black -mt-0.5 h-[1rem]" /> |
|
</div> |
|
</template> |
|
|
|
<a-select-option |
|
v-for="(role, index) in [ShareBaseRole.Editor, ShareBaseRole.Viewer]" |
|
:key="index" |
|
:value="role" |
|
dropdown-class-name="capitalize" |
|
@click="createShareBase(role)" |
|
> |
|
<div class="w-full px-2 capitalize"> |
|
{{ role }} |
|
</div> |
|
</a-select-option> |
|
</a-select> |
|
</div> |
|
<div |
|
v-if="sharedBase?.uuid" |
|
class="flex flex-row mt-2 bg-red-50 py-4 mx-1 px-2 items-center rounded-sm w-full justify-between" |
|
> |
|
<span class="flex text-xs overflow-x-hidden overflow-ellipsis text-gray-700 pl-2 nc-url">{{ url }}</span> |
|
|
|
<div class="flex border-l-1 pt-1 pl-1"> |
|
<a-tooltip placement="bottom"> |
|
<template #title> |
|
<span>{{ $t('general.reload') }}</span> |
|
</template> |
|
|
|
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="recreate"> |
|
<template #icon> |
|
<component :is="iconMap.reload" class="flex mx-auto text-gray-600" /> |
|
</template> |
|
</a-button> |
|
</a-tooltip> |
|
|
|
<a-tooltip placement="bottom"> |
|
<template #title> |
|
<span>{{ $t('activity.copyUrl') }}</span> |
|
</template> |
|
|
|
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="copyUrl"> |
|
<template #icon> |
|
<component :is="iconMap.copy" class="flex mx-auto text-gray-600" /> |
|
</template> |
|
</a-button> |
|
</a-tooltip> |
|
|
|
<a-tooltip placement="bottom"> |
|
<template #title> |
|
<span>{{ $t('activity.openTab') }}</span> |
|
</template> |
|
|
|
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="navigateToSharedBase"> |
|
<template #icon> |
|
<component :is="iconMap.share" class="flex mx-auto text-gray-600" /> |
|
</template> |
|
</a-button> |
|
</a-tooltip> |
|
|
|
<a-tooltip placement="bottom"> |
|
<template #title> |
|
<span>{{ $t('activity.iFrame') }}</span> |
|
</template> |
|
|
|
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="generateEmbeddableIframe"> |
|
<template #icon> |
|
<component :is="iconMap.xml" class="flex mx-auto text-gray-600" /> |
|
</template> |
|
</a-button> |
|
</a-tooltip> |
|
</div> |
|
</div> |
|
</div> |
|
</template>
|
|
|