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.
230 lines
6.5 KiB
230 lines
6.5 KiB
2 years ago
|
<script setup lang="ts">
|
||
|
import { useToast } from 'vue-toastification'
|
||
2 years ago
|
import { useClipboard } from '@vueuse/core'
|
||
2 years ago
|
import OpenInNewIcon from '~icons/mdi/open-in-new'
|
||
|
import { dashboardUrl } from '~/utils/urlUtils'
|
||
2 years ago
|
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
|
||
2 years ago
|
import MdiReload from '~icons/mdi/reload'
|
||
|
import DownIcon from '~icons/ic/round-keyboard-arrow-down'
|
||
|
import ContentCopyIcon from '~icons/mdi/content-copy'
|
||
|
import MdiXmlIcon from '~icons/mdi/xml'
|
||
|
const toast = useToast()
|
||
|
|
||
|
interface ShareBase {
|
||
|
uuid?: string
|
||
|
url?: string
|
||
|
role?: string
|
||
|
}
|
||
|
|
||
2 years ago
|
enum ShareBaseRole {
|
||
2 years ago
|
Editor = 'editor',
|
||
|
Viewer = 'viewer',
|
||
|
}
|
||
|
|
||
|
const { $api, $e } = useNuxtApp()
|
||
|
let base = $ref<null | ShareBase>(null)
|
||
|
const showEditBaseDropdown = $ref(false)
|
||
|
const { project } = useProject()
|
||
2 years ago
|
const { copy } = useClipboard()
|
||
2 years ago
|
|
||
|
const url = $computed(() => (base && base.uuid ? `${dashboardUrl()}#/nc/base/${base.uuid}` : null))
|
||
|
|
||
|
const loadBase = async () => {
|
||
|
try {
|
||
|
if (!project.value.id) return
|
||
|
|
||
|
const res = await $api.project.sharedBaseGet(project.value.id)
|
||
|
base = {
|
||
|
uuid: res.uuid,
|
||
|
url: res.url,
|
||
|
role: res.roles,
|
||
|
}
|
||
2 years ago
|
} catch (e: any) {
|
||
2 years ago
|
console.error(e)
|
||
2 years ago
|
toast.error(await extractSdkResponseErrorMsg(e))
|
||
2 years ago
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
const createShareBase = async (role = ShareBaseRole.Viewer) => {
|
||
2 years ago
|
try {
|
||
|
if (!project.value.id) return
|
||
|
|
||
|
const res = await $api.project.sharedBaseUpdate(project.value.id, {
|
||
|
roles: role,
|
||
|
})
|
||
|
|
||
|
base = res || {}
|
||
|
base.role = role
|
||
2 years ago
|
} catch (e: any) {
|
||
2 years ago
|
console.error(e)
|
||
2 years ago
|
toast.error(await extractSdkResponseErrorMsg(e))
|
||
2 years ago
|
}
|
||
|
$e('a:shared-base:enable', { role })
|
||
|
}
|
||
|
|
||
|
const disableSharedBase = async () => {
|
||
|
try {
|
||
|
if (!project.value.id) return
|
||
|
|
||
|
await $api.project.sharedBaseDisable(project.value.id)
|
||
2 years ago
|
base = null
|
||
2 years ago
|
} catch (e: any) {
|
||
|
console.error(e)
|
||
|
toast.error(await extractSdkResponseErrorMsg(e))
|
||
2 years ago
|
}
|
||
|
|
||
|
$e('a:shared-base:disable')
|
||
|
}
|
||
|
|
||
|
const recreate = async () => {
|
||
|
try {
|
||
|
if (!project.value.id) return
|
||
|
|
||
|
const sharedBase = await $api.project.sharedBaseCreate(project.value.id, {
|
||
2 years ago
|
roles: base?.role || ShareBaseRole.Viewer,
|
||
2 years ago
|
})
|
||
|
const newBase = sharedBase || {}
|
||
|
base = { ...newBase, role: base?.role }
|
||
2 years ago
|
} catch (e: any) {
|
||
|
console.error(e)
|
||
|
toast.error(await extractSdkResponseErrorMsg(e))
|
||
2 years ago
|
}
|
||
|
|
||
|
$e('a:shared-base:recreate')
|
||
|
}
|
||
|
|
||
|
const copyUrl = async () => {
|
||
|
if (!url) return
|
||
|
|
||
2 years ago
|
copy(url)
|
||
2 years ago
|
toast.success('Copied shareable base url to clipboard!')
|
||
|
|
||
|
$e('c:shared-base:copy-url')
|
||
|
}
|
||
|
|
||
|
const navigateToSharedBase = () => {
|
||
|
if (!url) return
|
||
|
|
||
|
window.open(url, '_blank')
|
||
|
|
||
|
$e('c:shared-base:open-url')
|
||
|
}
|
||
|
|
||
|
const generateEmbeddableIframe = () => {
|
||
|
if (!url) return
|
||
|
|
||
2 years ago
|
copy(`<iframe
|
||
2 years ago
|
class="nc-embed"
|
||
|
src="${url}?embed"
|
||
|
frameborder="0"
|
||
|
width="100%"
|
||
|
height="700"
|
||
|
style="background: transparent; border: 1px solid #ddd"></iframe>`)
|
||
|
toast.success('Copied embeddable html code!')
|
||
|
|
||
|
$e('c:shared-base:copy-embed-frame')
|
||
|
}
|
||
|
|
||
|
onMounted(() => {
|
||
|
if (!base) {
|
||
|
loadBase()
|
||
|
}
|
||
|
})
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
2 years ago
|
<div class="flex flex-col w-full">
|
||
2 years ago
|
<div class="flex flex-row items-center space-x-0.5 pl-2 h-[0.8rem]">
|
||
|
<OpenInNewIcon />
|
||
2 years ago
|
<div class="text-xs">Shared Base Link</div>
|
||
2 years ago
|
</div>
|
||
2 years ago
|
<div v-if="base?.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">{{ url }}</span>
|
||
|
<div class="flex border-l-1 pt-1 pl-1">
|
||
|
<a-tooltip placement="bottom">
|
||
|
<template #title>
|
||
|
<span>Reload</span>
|
||
|
</template>
|
||
2 years ago
|
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="recreate">
|
||
2 years ago
|
<template #icon>
|
||
2 years ago
|
<MdiReload class="flex mx-auto text-gray-600" />
|
||
2 years ago
|
</template>
|
||
|
</a-button>
|
||
|
</a-tooltip>
|
||
|
<a-tooltip placement="bottom">
|
||
|
<template #title>
|
||
|
<span>Copy URL</span>
|
||
|
</template>
|
||
2 years ago
|
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="copyUrl">
|
||
2 years ago
|
<template #icon>
|
||
2 years ago
|
<ContentCopyIcon class="flex mx-auto text-gray-600" />
|
||
2 years ago
|
</template>
|
||
|
</a-button>
|
||
|
</a-tooltip>
|
||
|
<a-tooltip placement="bottom">
|
||
|
<template #title>
|
||
|
<span>Open new tab</span>
|
||
|
</template>
|
||
2 years ago
|
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="navigateToSharedBase">
|
||
2 years ago
|
<template #icon>
|
||
2 years ago
|
<OpenInNewIcon class="flex mx-auto text-gray-600" />
|
||
2 years ago
|
</template>
|
||
|
</a-button>
|
||
|
</a-tooltip>
|
||
|
<a-tooltip placement="bottom">
|
||
|
<template #title>
|
||
|
<span>Copy embeddable HTML code</span>
|
||
|
</template>
|
||
2 years ago
|
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="generateEmbeddableIframe">
|
||
2 years ago
|
<template #icon>
|
||
2 years ago
|
<MdiXmlIcon class="flex mx-auto text-gray-600" />
|
||
2 years ago
|
</template>
|
||
|
</a-button>
|
||
|
</a-tooltip>
|
||
|
</div>
|
||
2 years ago
|
</div>
|
||
2 years ago
|
<div class="flex text-xs text-gray-500 mt-2 justify-start ml-2">Generate publicly shareable readonly base</div>
|
||
2 years ago
|
<div class="mt-4 flex flex-row justify-between mx-1">
|
||
|
<a-dropdown v-model="showEditBaseDropdown" class="flex">
|
||
|
<a-button>
|
||
|
<div class="flex flex-row items-center space-x-2">
|
||
|
<div v-if="base?.uuid">Anyone with the link</div>
|
||
|
<div v-else>Disable shared base</div>
|
||
2 years ago
|
<DownIcon class="h-[1rem]" />
|
||
2 years ago
|
</div>
|
||
|
</a-button>
|
||
|
|
||
|
<template #overlay>
|
||
|
<a-menu>
|
||
|
<a-menu-item>
|
||
|
<div v-if="base?.uuid" @click="disableSharedBase">Disable shared base</div>
|
||
2 years ago
|
<div v-else @click="createShareBase(ShareBaseRole.Viewer)">Anyone with the link</div>
|
||
2 years ago
|
</a-menu-item>
|
||
|
</a-menu>
|
||
|
</template>
|
||
|
</a-dropdown>
|
||
|
|
||
|
<a-select v-if="base?.uuid" v-model:value="base.role" class="flex">
|
||
2 years ago
|
<template #suffixIcon>
|
||
|
<div class="flex flex-row">
|
||
|
<DownIcon class="text-black -mt-0.5 h-[1rem]" />
|
||
|
</div>
|
||
|
</template>
|
||
2 years ago
|
<a-select-option
|
||
2 years ago
|
v-for="(role, index) in [ShareBaseRole.Editor, ShareBaseRole.Viewer]"
|
||
2 years ago
|
: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>
|
||
|
</template>
|
||
|
|
||
|
<style scoped></style>
|