Browse Source

fix(nc-gui): show page does not exist if shared url is invalid

Ramesh Mane 4 days ago
parent
commit
ec46068554
  1. 8
      packages/nc-gui/assets/style.scss
  2. 2
      packages/nc-gui/components/general/PageDoesNotExist.vue
  3. 13
      packages/nc-gui/composables/useSharedView.ts
  4. 109
      packages/nc-gui/layouts/shared-view.vue
  5. 4
      packages/nc-gui/pages/index/[typeOrId]/calendar/[viewId]/index.vue
  6. 7
      packages/nc-gui/pages/index/[typeOrId]/form/[viewId].vue
  7. 4
      packages/nc-gui/pages/index/[typeOrId]/gallery/[viewId]/index.vue
  8. 4
      packages/nc-gui/pages/index/[typeOrId]/kanban/[viewId]/index.vue
  9. 4
      packages/nc-gui/pages/index/[typeOrId]/map/[viewId]/index.vue
  10. 4
      packages/nc-gui/pages/index/[typeOrId]/view/[viewId].vue

8
packages/nc-gui/assets/style.scss

@ -14,6 +14,14 @@
scrollbar-width: none; /* Firefox */ scrollbar-width: none; /* Firefox */
} }
} }
.nc-h-screen {
height: 100vh;
@supports (height: 100dvh) {
height: 100dvh;
}
}
} }
* { * {

2
packages/nc-gui/components/general/PageDoesNotExist.vue

@ -1,5 +1,5 @@
<template> <template>
<div class="h-full grid place-items-center text-center"> <div class="nc-h-screen grid place-items-center text-center">
<div class="flex flex-col items-center gap-6"> <div class="flex flex-col items-center gap-6">
<slot name="icon"> <slot name="icon">
<img width="48" alt="NocoDB" src="~/assets/img/icons/256x256.png" /> <img width="48" alt="NocoDB" src="~/assets/img/icons/256x256.png" />

13
packages/nc-gui/composables/useSharedView.ts

@ -13,6 +13,8 @@ import type {
import { UITypes, ViewTypes } from 'nocodb-sdk' import { UITypes, ViewTypes } from 'nocodb-sdk'
export function useSharedView() { export function useSharedView() {
const router = useRouter()
const nestedFilters = ref<(FilterType & { status?: 'update' | 'delete' | 'create'; parentId?: string })[]>([]) const nestedFilters = ref<(FilterType & { status?: 'update' | 'delete' | 'create'; parentId?: string })[]>([])
const { appInfo } = useGlobal() const { appInfo } = useGlobal()
@ -70,6 +72,7 @@ export function useSharedView() {
'xc-password': localPassword ?? password.value, 'xc-password': localPassword ?? password.value,
}, },
}) })
try { try {
allowCSVDownload.value = parseProp(viewMeta.meta)?.allowCSVDownload allowCSVDownload.value = parseProp(viewMeta.meta)?.allowCSVDownload
} catch { } catch {
@ -421,6 +424,15 @@ export function useSharedView() {
} as RequestParams) } as RequestParams)
} }
const triggerNotFound = () => {
const currentQuery = { ...router.currentRoute.value.query, ncNotFound: 'true' }
router.push({
path: router.currentRoute.value.path,
query: currentQuery,
})
}
return { return {
sharedView, sharedView,
loadSharedView, loadSharedView,
@ -441,5 +453,6 @@ export function useSharedView() {
formColumns, formColumns,
allowCSVDownload, allowCSVDownload,
fetchCount, fetchCount,
triggerNotFound,
} }
} }

109
packages/nc-gui/layouts/shared-view.vue

@ -11,6 +11,8 @@ const route = router.currentRoute
const disableTopbar = computed(() => route.value.query?.disableTopbar === 'true') const disableTopbar = computed(() => route.value.query?.disableTopbar === 'true')
const ncNotFound = computed(() => route.value.query?.ncNotFound === 'true')
onMounted(() => { onMounted(() => {
// check if we are inside an iframe // check if we are inside an iframe
// if we are, communicate to the parent page whenever we navigate to a new url, // if we are, communicate to the parent page whenever we navigate to a new url,
@ -53,63 +55,66 @@ export default {
<template> <template>
<a-layout id="nc-app"> <a-layout id="nc-app">
<a-layout class="!flex-col bg-white"> <a-layout class="!flex-col bg-white">
<a-layout-header <GeneralPageDoesNotExist v-if="ncNotFound" />
v-if="!disableTopbar" <template v-else>
class="nc-table-topbar flex items-center justify-between !bg-transparent !px-3 !py-2 border-b-1 border-gray-200 !h-[46px]" <a-layout-header
> v-if="!disableTopbar"
<div class="flex items-center gap-6 h-7 max-w-[calc(100%_-_280px)] xs:max-w-[calc(100%_-_90px)]"> class="nc-table-topbar flex items-center justify-between !bg-transparent !px-3 !py-2 border-b-1 border-gray-200 !h-[46px]"
<a >
class="transition-all duration-200 cursor-pointer transform hover:scale-105" <div class="flex items-center gap-6 h-7 max-w-[calc(100%_-_280px)] xs:max-w-[calc(100%_-_90px)]">
href="https://github.com/nocodb/nocodb" <a
target="_blank" class="transition-all duration-200 cursor-pointer transform hover:scale-105"
rel="noopener noreferrer" href="https://github.com/nocodb/nocodb"
> target="_blank"
<img width="96" alt="NocoDB" src="~/assets/img/brand/nocodb.png" class="flex-none min-w-[96px]" /> rel="noopener noreferrer"
</a> >
<img width="96" alt="NocoDB" src="~/assets/img/brand/nocodb.png" class="flex-none min-w-[96px]" />
<div class="flex items-center gap-2 text-gray-900 text-sm truncate"> </a>
<template v-if="isLoading">
<span data-testid="nc-loading">{{ $t('general.loading') }}</span> <div class="flex items-center gap-2 text-gray-900 text-sm truncate">
<template v-if="isLoading">
<component :is="iconMap.reload" :class="{ 'animate-infinite animate-spin ': isLoading }" /> <span data-testid="nc-loading">{{ $t('general.loading') }}</span>
</template>
<component :is="iconMap.reload" :class="{ 'animate-infinite animate-spin ': isLoading }" />
<div v-else class="text-sm font-semibold truncate nc-shared-view-title flex gap-2 items-center"> </template>
<GeneralViewIcon v-if="sharedView" class="h-4 w-4 ml-0.5" :meta="sharedView" />
<div v-else class="text-sm font-semibold truncate nc-shared-view-title flex gap-2 items-center">
<span class="truncate"> <GeneralViewIcon v-if="sharedView" class="h-4 w-4 ml-0.5" :meta="sharedView" />
{{ sharedView?.title }}
</span> <span class="truncate">
{{ sharedView?.title }}
<NcTooltip v-if="sharedView?.description?.length" placement="bottom"> </span>
<template #title>
{{ sharedView?.description }} <NcTooltip v-if="sharedView?.description?.length" placement="bottom">
</template> <template #title>
{{ sharedView?.description }}
<NcButton type="text" class="!hover:bg-transparent" size="xsmall"> </template>
<GeneralIcon icon="info" class="!w-3.5 !h-3.5 nc-info-icon text-gray-600" />
</NcButton> <NcButton type="text" class="!hover:bg-transparent" size="xsmall">
</NcTooltip> <GeneralIcon icon="info" class="!w-3.5 !h-3.5 nc-info-icon text-gray-600" />
</NcButton>
</NcTooltip>
</div>
</div> </div>
</div> </div>
</div>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<LazySmartsheetToolbarExport v-if="allowCSVDownload" /> <LazySmartsheetToolbarExport v-if="allowCSVDownload" />
<a href="https://app.nocodb.com/#/signin" target="_blank" class="!no-underline xs:hidden" rel="noopener"> <a href="https://app.nocodb.com/#/signin" target="_blank" class="!no-underline xs:hidden" rel="noopener">
<NcButton size="xs"> {{ $t('labels.signUpForFree') }} </NcButton> <NcButton size="xs"> {{ $t('labels.signUpForFree') }} </NcButton>
</a> </a>
</div>
</a-layout-header>
<div
class="nc-shared-view-container w-full overflow-hidden"
:class="{
'nc-shared-mobile-view': isMobileMode,
}"
>
<slot />
</div> </div>
</a-layout-header> </template>
<div
class="nc-shared-view-container w-full overflow-hidden"
:class="{
'nc-shared-mobile-view': isMobileMode,
}"
>
<slot />
</div>
</a-layout> </a-layout>
</a-layout> </a-layout>
</template> </template>

4
packages/nc-gui/pages/index/[typeOrId]/calendar/[viewId]/index.vue

@ -11,7 +11,7 @@ definePageMeta({
const route = useRoute() const route = useRoute()
const { loadSharedView } = useSharedView() const { loadSharedView, triggerNotFound } = useSharedView()
const showPassword = ref(false) const showPassword = ref(false)
@ -20,6 +20,8 @@ try {
} catch (e: any) { } catch (e: any) {
if (e?.response?.status === 403) { if (e?.response?.status === 403) {
showPassword.value = true showPassword.value = true
} else if (e?.response?.status === 404) {
triggerNotFound()
} else { } else {
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))
} }

7
packages/nc-gui/pages/index/[typeOrId]/form/[viewId].vue

@ -27,9 +27,6 @@ if (!notFound.value) {
useProvideSmartsheetStore(sharedView, meta, true) useProvideSmartsheetStore(sharedView, meta, true)
applyLanguageDirection(sharedViewMeta.value.rtl ? 'rtl' : 'ltr') applyLanguageDirection(sharedViewMeta.value.rtl ? 'rtl' : 'ltr')
} else {
navigateTo('/error/404')
throw createError({ statusCode: 404, statusMessage: t('msg.pageNotFound') })
} }
const form = reactive({ const form = reactive({
@ -51,7 +48,9 @@ const focus: VNodeRef = (el: typeof InputPassword) => {
<template> <template>
<div> <div>
<NuxtLayout> <NuxtLayout>
<NuxtPage v-if="!passwordDlg" /> <NuxtPage v-if="!passwordDlg && !notFound" />
<GeneralPageDoesNotExist v-if="notFound" />
<a-modal <a-modal
v-model:visible="passwordDlg" v-model:visible="passwordDlg"

4
packages/nc-gui/pages/index/[typeOrId]/gallery/[viewId]/index.vue

@ -10,7 +10,7 @@ definePageMeta({
const route = useRoute() const route = useRoute()
const { loadSharedView } = useSharedView() const { loadSharedView, triggerNotFound } = useSharedView()
const showPassword = ref(false) const showPassword = ref(false)
@ -19,6 +19,8 @@ try {
} catch (e: any) { } catch (e: any) {
if (e?.response?.status === 403) { if (e?.response?.status === 403) {
showPassword.value = true showPassword.value = true
} else if (e?.response?.status === 404) {
triggerNotFound()
} else { } else {
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))
} }

4
packages/nc-gui/pages/index/[typeOrId]/kanban/[viewId]/index.vue

@ -11,7 +11,7 @@ definePageMeta({
const route = useRoute() const route = useRoute()
const { loadSharedView } = useSharedView() const { loadSharedView, triggerNotFound } = useSharedView()
const showPassword = ref(false) const showPassword = ref(false)
@ -20,6 +20,8 @@ try {
} catch (e: any) { } catch (e: any) {
if (e?.response?.status === 403) { if (e?.response?.status === 403) {
showPassword.value = true showPassword.value = true
} else if (e?.response?.status === 404) {
triggerNotFound()
} else { } else {
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))
} }

4
packages/nc-gui/pages/index/[typeOrId]/map/[viewId]/index.vue

@ -10,7 +10,7 @@ definePageMeta({
const route = useRoute() const route = useRoute()
const { loadSharedView } = useSharedView() const { loadSharedView , triggerNotFound} = useSharedView()
const showPassword = ref(false) const showPassword = ref(false)
@ -19,6 +19,8 @@ try {
} catch (e: any) { } catch (e: any) {
if (e?.response?.status === 403) { if (e?.response?.status === 403) {
showPassword.value = true showPassword.value = true
} else if (e?.response?.status === 404) {
triggerNotFound()
} else { } else {
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))
} }

4
packages/nc-gui/pages/index/[typeOrId]/view/[viewId].vue

@ -10,7 +10,7 @@ definePageMeta({
const route = useRoute() const route = useRoute()
const { loadSharedView, meta } = useSharedView() const { loadSharedView, meta, triggerNotFound } = useSharedView()
const { isViewDataLoading } = storeToRefs(useViewsStore()) const { isViewDataLoading } = storeToRefs(useViewsStore())
provide(MetaInj, meta) provide(MetaInj, meta)
@ -24,6 +24,8 @@ onMounted(async () => {
} catch (e: any) { } catch (e: any) {
if (e?.response?.status === 403) { if (e?.response?.status === 403) {
showPassword.value = true showPassword.value = true
} else if (e?.response?.status === 404) {
triggerNotFound()
} else { } else {
console.error(e) console.error(e)
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))

Loading…
Cancel
Save