多维表格
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.
 
 
 
 
 
 

229 lines
6.5 KiB

<script setup lang="ts">
import { useToast } from 'vue-toastification'
import { useClipboard } from '@vueuse/core'
import OpenInNewIcon from '~icons/mdi/open-in-new'
import { dashboardUrl } from '~/utils/urlUtils'
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
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
}
enum ShareBaseRole {
Editor = 'editor',
Viewer = 'viewer',
}
const { $api, $e } = useNuxtApp()
let base = $ref<null | ShareBase>(null)
const showEditBaseDropdown = $ref(false)
const { project } = useProject()
const { copy } = useClipboard()
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,
}
} catch (e: any) {
console.error(e)
toast.error(await extractSdkResponseErrorMsg(e))
}
}
const createShareBase = async (role = ShareBaseRole.Viewer) => {
try {
if (!project.value.id) return
const res = await $api.project.sharedBaseUpdate(project.value.id, {
roles: role,
})
base = res || {}
base.role = role
} catch (e: any) {
console.error(e)
toast.error(await extractSdkResponseErrorMsg(e))
}
$e('a:shared-base:enable', { role })
}
const disableSharedBase = async () => {
try {
if (!project.value.id) return
await $api.project.sharedBaseDisable(project.value.id)
base = null
} catch (e: any) {
console.error(e)
toast.error(await extractSdkResponseErrorMsg(e))
}
$e('a:shared-base:disable')
}
const recreate = async () => {
try {
if (!project.value.id) return
const sharedBase = await $api.project.sharedBaseCreate(project.value.id, {
roles: base?.role || ShareBaseRole.Viewer,
})
const newBase = sharedBase || {}
base = { ...newBase, role: base?.role }
} catch (e: any) {
console.error(e)
toast.error(await extractSdkResponseErrorMsg(e))
}
$e('a:shared-base:recreate')
}
const copyUrl = async () => {
if (!url) return
copy(url)
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
copy(`<iframe
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>
<div class="flex flex-col w-full">
<div class="flex flex-row items-center space-x-0.5 pl-2 h-[0.8rem]">
<OpenInNewIcon />
<div class="text-xs">Shared Base Link</div>
</div>
<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>
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="recreate">
<template #icon>
<MdiReload class="flex mx-auto text-gray-600" />
</template>
</a-button>
</a-tooltip>
<a-tooltip placement="bottom">
<template #title>
<span>Copy URL</span>
</template>
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="copyUrl">
<template #icon>
<ContentCopyIcon class="flex mx-auto text-gray-600" />
</template>
</a-button>
</a-tooltip>
<a-tooltip placement="bottom">
<template #title>
<span>Open new tab</span>
</template>
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="navigateToSharedBase">
<template #icon>
<OpenInNewIcon class="flex mx-auto text-gray-600" />
</template>
</a-button>
</a-tooltip>
<a-tooltip placement="bottom">
<template #title>
<span>Copy embeddable HTML code</span>
</template>
<a-button type="text" class="!rounded-md mr-1 -mt-1.5 h-[1rem]" @click="generateEmbeddableIframe">
<template #icon>
<MdiXmlIcon class="flex mx-auto text-gray-600" />
</template>
</a-button>
</a-tooltip>
</div>
</div>
<div class="flex text-xs text-gray-500 mt-2 justify-start ml-2">Generate publicly shareable readonly base</div>
<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>
<DownIcon class="h-[1rem]" />
</div>
</a-button>
<template #overlay>
<a-menu>
<a-menu-item>
<div v-if="base?.uuid" @click="disableSharedBase">Disable shared base</div>
<div v-else @click="createShareBase(ShareBaseRole.Viewer)">Anyone with the link</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<a-select v-if="base?.uuid" v-model:value="base.role" class="flex">
<template #suffixIcon>
<div class="flex flex-row">
<DownIcon 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>
</template>
<style scoped></style>