Browse Source

Merge pull request #3197 from nocodb/fix/followup-on-shared-view

Follow up on shared view
pull/3213/head
Muhammed Mustafa 2 years ago committed by GitHub
parent
commit
db83c66de1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      packages/nc-gui-v2/app.vue
  2. 12
      packages/nc-gui-v2/components/cell/Checkbox.vue
  3. 10
      packages/nc-gui-v2/components/shared-view/Grid.vue
  4. 9
      packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue
  5. 17
      packages/nc-gui-v2/components/smartsheet-toolbar/ShareView.vue
  6. 33
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  7. 16
      packages/nc-gui-v2/composables/useSharedView.ts
  8. 52
      packages/nc-gui-v2/composables/useViewColumns.ts
  9. 17
      packages/nc-gui-v2/layouts/shared-view.vue
  10. 8
      packages/nc-gui-v2/lib/types.ts
  11. 2
      packages/nc-gui-v2/middleware/auth.global.ts
  12. 9
      packages/nc-gui-v2/pages/[projectType]/view/[viewId].vue

8
packages/nc-gui-v2/app.vue

@ -1,5 +1,11 @@
<script setup lang="ts">
const route = useRoute()
const disableBaseLayout = $computed(() => route.path.startsWith('/nc/view') || route.path.startsWith('/nc/form'))
</script>
<template> <template>
<NuxtLayout name="base"> <NuxtLayout :name="disableBaseLayout ? false : 'base'">
<NuxtPage /> <NuxtPage />
</NuxtLayout> </NuxtLayout>
</template> </template>

12
packages/nc-gui-v2/components/cell/Checkbox.vue

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ColumnInj, IsFormInj, getMdiIcon, inject } from '#imports' import { ColumnInj, IsFormInj, ReadonlyInj, getMdiIcon, inject } from '#imports'
import { EditModeInj } from '~/context'
interface Props { interface Props {
modelValue?: boolean | undefined | number modelValue?: boolean | undefined | number
@ -20,7 +19,7 @@ const column = inject(ColumnInj)
const isForm = inject(IsFormInj) const isForm = inject(IsFormInj)
const editEnabled = inject(EditModeInj) const readOnly = inject(ReadonlyInj)
const checkboxMeta = $computed(() => { const checkboxMeta = $computed(() => {
return { return {
@ -34,14 +33,17 @@ const checkboxMeta = $computed(() => {
}) })
function onClick() { function onClick() {
if (editEnabled) { if (!readOnly) {
vModel = !vModel vModel = !vModel
} }
} }
</script> </script>
<template> <template>
<div class="flex" :class="{ 'justify-center': !isForm, 'nc-cell-hover-show': !vModel }"> <div
class="flex"
:class="{ 'justify-center': !isForm, 'nc-cell-hover-show': !vModel && !readOnly, 'opacity-0': readOnly && !vModel }"
>
<div class="px-1 pt-1 rounded-full items-center" :class="{ 'bg-gray-100': !vModel }" @click="onClick"> <div class="px-1 pt-1 rounded-full items-center" :class="{ 'bg-gray-100': !vModel }" @click="onClick">
<component <component
:is="getMdiIcon(vModel ? checkboxMeta.icon.checked : checkboxMeta.icon.unchecked)" :is="getMdiIcon(vModel ? checkboxMeta.icon.checked : checkboxMeta.icon.unchecked)"

10
packages/nc-gui-v2/components/shared-view/Grid.vue

@ -4,23 +4,23 @@ import type { TableType } from 'nocodb-sdk'
import { ActiveViewInj, FieldsInj, IsPublicInj, MetaInj, ReadonlyInj, ReloadViewDataHookInj } from '~/context' import { ActiveViewInj, FieldsInj, IsPublicInj, MetaInj, ReadonlyInj, ReloadViewDataHookInj } from '~/context'
const { sharedView, meta, columns } = useSharedView() const { sharedView, meta } = useSharedView()
const reloadEventHook = createEventHook<void>() const reloadEventHook = createEventHook<void>()
provide(ReloadViewDataHookInj, reloadEventHook) provide(ReloadViewDataHookInj, reloadEventHook)
provide(ReadonlyInj, ref(true)) provide(ReadonlyInj, true)
provide(MetaInj, meta) provide(MetaInj, meta)
provide(ActiveViewInj, sharedView) provide(ActiveViewInj, sharedView)
provide(FieldsInj, columns) provide(FieldsInj, ref(meta.value.columns as any[]))
provide(IsPublicInj, ref(true)) provide(IsPublicInj, ref(true))
useProvideSmartsheetStore(sharedView as Ref<TableType>, meta) useProvideSmartsheetStore(sharedView as Ref<TableType>, meta)
</script> </script>
<template> <template>
<div class="nc-container flex flex-col h-full mt-4 px-6"> <div class="nc-container flex flex-col h-full mt-1.5 px-12">
<SmartsheetToolbar /> <SmartsheetToolbar />
<SmartsheetGrid class="px-3" /> <SmartsheetGrid />
</div> </div>
</template> </template>

9
packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import { ActiveViewInj, FieldsInj, IsLockedInj, MetaInj, ReloadViewDataHookInj } from '~/context' import { ActiveViewInj, FieldsInj, IsLockedInj, IsPublicInj, MetaInj, ReloadViewDataHookInj } from '~/context'
import { computed, inject, useNuxtApp, useViewColumns, watch } from '#imports' import { computed, inject, useNuxtApp, useViewColumns, watch } from '#imports'
const meta = inject(MetaInj)! const meta = inject(MetaInj)!
@ -8,6 +8,7 @@ const activeView = inject(ActiveViewInj)!
const reloadDataHook = inject(ReloadViewDataHookInj)! const reloadDataHook = inject(ReloadViewDataHookInj)!
const rootFields = inject(FieldsInj) const rootFields = inject(FieldsInj)
const isLocked = inject(IsLockedInj) const isLocked = inject(IsLockedInj)
const isPublic = inject(IsPublicInj)
const { $e } = useNuxtApp() const { $e } = useNuxtApp()
@ -88,9 +89,9 @@ const onMove = (event: { moved: { newIndex: number } }) => {
</div> </div>
<div class="nc-fields-list py-1"> <div class="nc-fields-list py-1">
<Draggable :list="fields" item-key="id" @change="onMove($event)"> <Draggable :list="fields" item-key="id" @change="onMove($event)">
<template #item="{ element: field }"> <template #item="{ element: field, index: index }">
<div v-show="filteredFieldList.includes(field)" :key="field.id" class="px-2 py-1 flex" @click.stop> <div v-show="filteredFieldList.includes(field)" :key="field.id" class="px-2 py-1 flex" @click.stop>
<a-checkbox v-model:checked="field.show" class="flex-shrink" @change="saveOrUpdate(field, i)"> <a-checkbox v-model:checked="field.show" class="flex-shrink" @change="saveOrUpdate(field, index)">
<span class="">{{ field.title }}</span> <span class="">{{ field.title }}</span>
</a-checkbox> </a-checkbox>
<div class="flex-1" /> <div class="flex-1" />
@ -101,7 +102,7 @@ const onMove = (event: { moved: { newIndex: number } }) => {
</div> </div>
<v-divider class="my-2" /> <v-divider class="my-2" />
<div class="p-2 py-1 flex" @click.stop> <div v-if="!isPublic" class="p-2 py-1 flex" @click.stop>
<a-checkbox v-model:checked="showSystemFields"> <a-checkbox v-model:checked="showSystemFields">
<span class="text-xs"> {{ $t('activity.showSystemFields') }}</span> <span class="text-xs"> {{ $t('activity.showSystemFields') }}</span>
</a-checkbox> </a-checkbox>

17
packages/nc-gui-v2/components/smartsheet-toolbar/ShareView.vue

@ -21,7 +21,7 @@ const { isUIAllowed } = useUIPermission()
let showShareModel = $ref(false) let showShareModel = $ref(false)
const passwordProtected = $ref(false) let passwordProtected = $ref(false)
const shared = ref() const shared = ref()
@ -100,6 +100,20 @@ const copyLink = () => {
copy(sharedViewUrl?.value as string) copy(sharedViewUrl?.value as string)
message.success('Copied to clipboard') message.success('Copied to clipboard')
} }
watch(
() => passwordProtected,
(value) => {
if (!value) {
shared.value.password = ''
saveShareLinkPassword()
}
},
)
onMounted(() => {
if (shared.value?.password?.length) passwordProtected = true
})
</script> </script>
<template> <template>
@ -133,7 +147,6 @@ const copyLink = () => {
<a-collapse-panel key="1" header="More Options"> <a-collapse-panel key="1" header="More Options">
<div class="mb-2"> <div class="mb-2">
<a-checkbox v-model:checked="passwordProtected" class="!text-xs">{{ $t('msg.info.beforeEnablePwd') }} </a-checkbox> <a-checkbox v-model:checked="passwordProtected" class="!text-xs">{{ $t('msg.info.beforeEnablePwd') }} </a-checkbox>
<!-- todo: add password toggle -->
<div v-if="passwordProtected" class="flex gap-2 mt-2 mb-4"> <div v-if="passwordProtected" class="flex gap-2 mt-2 mb-4">
<a-input <a-input
v-model:value="shared.password" v-model:value="shared.password"

33
packages/nc-gui-v2/components/smartsheet/Grid.vue

@ -41,7 +41,7 @@ const isPublicView = inject(IsPublicInj, ref(false))
// keep a root fields variable and will get modified from // keep a root fields variable and will get modified from
// fields menu and get used in grid and gallery // fields menu and get used in grid and gallery
const fields = inject(FieldsInj, ref([])) const fields = inject(FieldsInj, ref([]))
const readonly = inject(ReadonlyInj, ref(false)) const readOnly = inject(ReadonlyInj, false)
const isLocked = inject(IsLockedInj, false) const isLocked = inject(IsLockedInj, false)
const reloadViewDataHook = inject(ReloadViewDataHookInj) const reloadViewDataHook = inject(ReloadViewDataHookInj)
@ -59,7 +59,15 @@ const { xWhere, isPkAvail, cellRefs } = useSmartsheetStoreOrThrow()
const addColumnDropdown = ref(false) const addColumnDropdown = ref(false)
const contextMenu = ref(false) const _contextMenu = ref(false)
const contextMenu = computed({
get: () => _contextMenu.value,
set: (val) => {
if (!readOnly) {
_contextMenu.value = val
}
},
})
const contextMenuTarget = ref(false) const contextMenuTarget = ref(false)
const expandedFormDlg = ref(false) const expandedFormDlg = ref(false)
@ -302,6 +310,7 @@ const expandForm = (row: Row, state: Record<string, any>) => {
<tr class="nc-grid-header border-1 bg-gray-100 sticky top[-1px]"> <tr class="nc-grid-header border-1 bg-gray-100 sticky top[-1px]">
<th> <th>
<div class="w-full h-full bg-gray-100 flex min-w-[70px] pl-5 pr-1 items-center"> <div class="w-full h-full bg-gray-100 flex min-w-[70px] pl-5 pr-1 items-center">
<template v-if="!readOnly">
<div class="nc-no-label text-gray-500" :class="{ hidden: selectedAllRecords }">#</div> <div class="nc-no-label text-gray-500" :class="{ hidden: selectedAllRecords }">#</div>
<div <div
:class="{ hidden: !selectedAllRecords, flex: selectedAllRecords }" :class="{ hidden: !selectedAllRecords, flex: selectedAllRecords }"
@ -311,6 +320,10 @@ const expandForm = (row: Row, state: Record<string, any>) => {
<span class="flex-1" /> <span class="flex-1" />
</div> </div>
</template>
<template v-else>
<div class="text-gray-500">#</div>
</template>
</div> </div>
</th> </th>
<th <th
@ -324,14 +337,13 @@ const expandForm = (row: Row, state: Record<string, any>) => {
@xcresized="resizingCol = null" @xcresized="resizingCol = null"
> >
<div class="w-full h-full bg-gray-100 flex items-center"> <div class="w-full h-full bg-gray-100 flex items-center">
<SmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" :hide-menu="readonly" /> <SmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" :hide-menu="readOnly" />
<SmartsheetHeaderCell v-else :column="col" :hide-menu="readonly" /> <SmartsheetHeaderCell v-else :column="col" :hide-menu="readOnly" />
</div> </div>
</th> </th>
<!-- v-if="!isLocked && !isVirtual && !isPublicView && _isUIAllowed('add-column')" -->
<th <th
v-if="!readonly && isUIAllowed('add-column')" v-if="!readOnly && isUIAllowed('add-column')"
v-t="['c:column:add']" v-t="['c:column:add']"
class="cursor-pointer" class="cursor-pointer"
@click.stop="addColumnDropdown = true" @click.stop="addColumnDropdown = true"
@ -360,18 +372,21 @@ const expandForm = (row: Row, state: Record<string, any>) => {
<tr class="nc-grid-row"> <tr class="nc-grid-row">
<td key="row-index" class="caption nc-grid-cell pl-5 pr-1"> <td key="row-index" class="caption nc-grid-cell pl-5 pr-1">
<div class="align-center flex gap-1 min-w-[55px]"> <div class="align-center flex gap-1 min-w-[55px]">
<div v-if="!readonly" class="nc-row-no text-xs text-gray-500" :class="{ hidden: row.rowMeta.selected }"> <div v-if="!readOnly" class="nc-row-no text-xs text-gray-500" :class="{ hidden: row.rowMeta.selected }">
{{ rowIndex + 1 }}
</div>
<div v-else class="text-xs text-gray-500">
{{ rowIndex + 1 }} {{ rowIndex + 1 }}
</div> </div>
<div <div
v-if="!readonly" v-if="!readOnly"
:class="{ hidden: !row.rowMeta.selected, flex: row.rowMeta.selected }" :class="{ hidden: !row.rowMeta.selected, flex: row.rowMeta.selected }"
class="nc-row-expand-and-checkbox" class="nc-row-expand-and-checkbox"
> >
<a-checkbox v-model:checked="row.rowMeta.selected" /> <a-checkbox v-model:checked="row.rowMeta.selected" />
</div> </div>
<span class="flex-1" /> <span class="flex-1" />
<div v-if="!readonly" class="nc-expand" :class="{ 'nc-comment': row.rowMeta?.commentCount }"> <div v-if="!readOnly" class="nc-expand" :class="{ 'nc-comment': row.rowMeta?.commentCount }">
<span <span
v-if="row.rowMeta?.commentCount" v-if="row.rowMeta?.commentCount"
class="py-1 px-3 rounded-full text-xs cursor-pointer select-none transform hover:(scale-110)" class="py-1 px-3 rounded-full text-xs cursor-pointer select-none transform hover:(scale-110)"

16
packages/nc-gui-v2/composables/useSharedView.ts

@ -13,11 +13,10 @@ export function useSharedView() {
const password = useState<string | undefined>('password') const password = useState<string | undefined>('password')
const allowCSVDownload = useState<boolean>('allowCSVDownload', () => false) const allowCSVDownload = useState<boolean>('allowCSVDownload', () => false)
const meta = ref<TableType>(sharedView.value?.model) const meta = useState<TableType>('meta')
const columns = ref<ColumnType[]>(sharedView.value?.model?.columns)
const formColumns = computed( const formColumns = computed(
() => () =>
columns.value meta.value.columns
.filter( .filter(
(f: Record<string, any>) => (f: Record<string, any>) =>
f.show && f.uidt !== UITypes.Rollup && f.uidt !== UITypes.Lookup && f.uidt !== UITypes.Formula, f.show && f.uidt !== UITypes.Rollup && f.uidt !== UITypes.Lookup && f.uidt !== UITypes.Formula,
@ -39,10 +38,14 @@ export function useSharedView() {
allowCSVDownload.value = JSON.parse(viewMeta.meta).allowCSVDownload allowCSVDownload.value = JSON.parse(viewMeta.meta).allowCSVDownload
if (localPassword) password.value = localPassword if (localPassword) password.value = localPassword
sharedView.value = viewMeta sharedView.value = { ...viewMeta }
meta.value = { ...viewMeta.model }
meta.value = viewMeta.model let order = 1
columns.value = viewMeta.model.columns meta.value.columns = [...viewMeta.model.columns]
.filter((c) => c.show)
.map((c) => ({ ...c, order: order++ }))
.sort((a, b) => a.order - b.order)
setMeta(viewMeta.model) setMeta(viewMeta.model)
@ -96,7 +99,6 @@ export function useSharedView() {
sharedView, sharedView,
loadSharedView, loadSharedView,
meta, meta,
columns,
nestedFilters, nestedFilters,
fetchSharedViewData, fetchSharedViewData,
paginationData, paginationData,

52
packages/nc-gui-v2/composables/useViewColumns.ts

@ -4,18 +4,11 @@ import { watch } from 'vue'
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import { useNuxtApp } from '#app' import { useNuxtApp } from '#app'
import { IsPublicInj } from '#imports' import { IsPublicInj } from '#imports'
import type { Field } from '~/lib'
export function useViewColumns(view: Ref<ViewType> | undefined, meta: ComputedRef<TableType>, reloadData?: () => void) { export function useViewColumns(view: Ref<ViewType> | undefined, meta: ComputedRef<TableType>, reloadData?: () => void) {
const isPublic = inject(IsPublicInj, ref(false)) const isPublic = inject(IsPublicInj, ref(false))
const fields = ref< const fields = ref<Field[]>()
{
order: number
show: number | boolean
title: string
fk_column_id?: string
system?: boolean
}[]
>()
const filterQuery = ref('') const filterQuery = ref('')
@ -39,7 +32,7 @@ export function useViewColumns(view: Ref<ViewType> | undefined, meta: ComputedRe
} }
}, {}) }, {})
fields.value = meta.value?.columns fields.value = meta.value?.columns
?.map((column) => { ?.map((column: ColumnType) => {
const currentColumnField = fieldById[column.id!] || {} const currentColumnField = fieldById[column.id!] || {}
return { return {
@ -50,13 +43,13 @@ export function useViewColumns(view: Ref<ViewType> | undefined, meta: ComputedRe
system: isSystemColumn(currentColumnField.type || false), system: isSystemColumn(currentColumnField.type || false),
} }
}) })
.sort((a, b) => a.order - b.order) .sort((a: Field, b: Field) => a.order - b.order)
} }
} }
const showAll = async (ignoreIds?: any) => { const showAll = async (ignoreIds?: any) => {
if (isPublic.value) { if (isPublic.value) {
fields.value = fields.value?.map((field) => ({ fields.value = fields.value?.map((field: Field) => ({
...field, ...field,
show: true, show: true,
})) }))
@ -79,7 +72,7 @@ export function useViewColumns(view: Ref<ViewType> | undefined, meta: ComputedRe
} }
const hideAll = async (ignoreIds?: any) => { const hideAll = async (ignoreIds?: any) => {
if (isPublic.value) { if (isPublic.value) {
fields.value = fields.value?.map((field) => ({ fields.value = fields.value?.map((field: Field) => ({
...field, ...field,
show: false, show: false,
})) }))
@ -101,9 +94,9 @@ export function useViewColumns(view: Ref<ViewType> | undefined, meta: ComputedRe
} }
const saveOrUpdate = async (field: any, index: number) => { const saveOrUpdate = async (field: any, index: number) => {
if (isPublic && fields.value) { if (isPublic.value && fields.value) {
fields.value[index] = field fields.value[index] = field
meta.value.columns = meta.value?.columns?.map((column) => { meta.value.columns = meta.value?.columns?.map((column: ColumnType) => {
if (column.id === field.fk_column_id) { if (column.id === field.fk_column_id) {
return { return {
...column, ...column,
@ -128,14 +121,15 @@ export function useViewColumns(view: Ref<ViewType> | undefined, meta: ComputedRe
reloadData?.() reloadData?.()
} }
const metaColumnById = computed(() => { const metaColumnById = computed<Record<string, ColumnType>>(() => {
return ( if (!meta.value?.columns) return {}
meta.value?.columns?.reduce<Record<string, ColumnType>>((acc, curr) => {
return { return meta.value?.columns?.reduce(
(acc: ColumnType, curr: ColumnType) => ({
...acc, ...acc,
[curr.id!]: curr, [curr.id!]: curr,
} }),
}, {}) || {} {} as any,
) )
}) })
@ -160,33 +154,33 @@ export function useViewColumns(view: Ref<ViewType> | undefined, meta: ComputedRe
const filteredFieldList = computed(() => { const filteredFieldList = computed(() => {
return ( return (
fields.value?.filter((field) => { fields.value?.filter((field: Field) => {
// hide system columns if not enabled // hide system columns if not enabled
if (!showSystemFields.value && isSystemColumn(metaColumnById?.value?.[field.fk_column_id!])) { if (!showSystemFields.value && isSystemColumn(metaColumnById?.value?.[field.fk_column_id!])) {
return false return false
} }
return !filterQuery?.value || field.title.toLowerCase().includes(filterQuery.value.toLowerCase()) return !filterQuery?.value || field.title.toLowerCase().includes(filterQuery.value.toLowerCase())
}) || {} }) || []
) )
}) })
const sortedAndFilteredFields = computed<ColumnType[]>(() => { const sortedAndFilteredFields = computed<ColumnType[]>(() => {
return (fields?.value return (fields?.value
?.filter((c) => { ?.filter((field: Field) => {
// hide system columns if not enabled // hide system columns if not enabled
if ( if (
!showSystemFields.value && !showSystemFields.value &&
metaColumnById.value && metaColumnById.value &&
metaColumnById?.value?.[c.fk_column_id!] && metaColumnById?.value?.[field.fk_column_id!] &&
isSystemColumn(metaColumnById.value?.[c.fk_column_id!]) isSystemColumn(metaColumnById.value?.[field.fk_column_id!])
) { ) {
return false return false
} }
return c.show && metaColumnById?.value?.[c.fk_column_id!] return field.show && metaColumnById?.value?.[field.fk_column_id!]
}) })
?.sort((a, b) => a.order - b.order) ?.sort((a: Field, b: Field) => a.order - b.order)
?.map((c) => metaColumnById?.value?.[c.fk_column_id!]) || []) as ColumnType[] ?.map((field: Field) => metaColumnById?.value?.[field.fk_column_id!]) || []) as ColumnType[]
}) })
// reload view columns when table meta changes // reload view columns when table meta changes

17
packages/nc-gui-v2/layouts/shared-view.vue

@ -1,5 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { navigateTo } from '#app' import { navigateTo } from '#app'
const { isLoading } = useGlobal()
const { sharedView } = useSharedView()
</script> </script>
<script lang="ts"> <script lang="ts">
@ -10,12 +12,25 @@ export default {
<template> <template>
<a-layout id="nc-app"> <a-layout id="nc-app">
<a-layout class="!flex-col"> <a-layout class="!flex-col bg-white">
<a-layout-header class="flex !bg-primary items-center text-white pl-3 pr-4 shadow-lg"> <a-layout-header class="flex !bg-primary items-center text-white pl-3 pr-4 shadow-lg">
<div class="transition-all duration-200 p-2 cursor-pointer transform hover:scale-105" @click="navigateTo('/')"> <div class="transition-all duration-200 p-2 cursor-pointer transform hover:scale-105" @click="navigateTo('/')">
<img width="35" alt="NocoDB" src="~/assets/img/icons/512x512-trans.png" /> <img width="35" alt="NocoDB" src="~/assets/img/icons/512x512-trans.png" />
</div> </div>
<div>
<div class="flex justify-center items-center">
<div class="flex items-center gap-2 ml-3">
<template v-if="isLoading">
{{ $t('general.loading') }}
<MdiReload :class="{ 'animate-infinite animate-spin': isLoading }" />
</template>
<div v-else class="text-xl font-semibold truncate">
{{ sharedView?.title }}
</div>
</div>
</div>
</div>
<div class="flex-1" /> <div class="flex-1" />
</a-layout-header> </a-layout-header>

8
packages/nc-gui-v2/lib/types.ts

@ -21,6 +21,14 @@ export interface ProjectMetaInfo {
PackageVersion?: string PackageVersion?: string
} }
export interface Field {
order: number
show: number | boolean
title: string
fk_column_id?: string
system?: boolean
}
export type Roles = Record<Role, boolean> export type Roles = Record<Role, boolean>
export type Filter = FilterType & { status?: 'update' | 'delete' | 'create'; parentId?: string; readOnly?: boolean } export type Filter = FilterType & { status?: 'update' | 'delete' | 'create'; parentId?: string; readOnly?: boolean }

2
packages/nc-gui-v2/middleware/auth.global.ts

@ -26,6 +26,8 @@ export default defineNuxtRouteMiddleware((to, from) => {
/** if shred base allow without validating */ /** if shred base allow without validating */
if (to.params?.projectType === 'base') return if (to.params?.projectType === 'base') return
if (to.meta.public) return
/** if auth is required or unspecified (same as required) and user is not signed in, redirect to signin page */ /** if auth is required or unspecified (same as required) and user is not signed in, redirect to signin page */
if ((to.meta.requiresAuth || typeof to.meta.requiresAuth === 'undefined') && !state.signedIn.value) { if ((to.meta.requiresAuth || typeof to.meta.requiresAuth === 'undefined') && !state.signedIn.value) {
return navigateTo('/signin') return navigateTo('/signin')

9
packages/nc-gui-v2/pages/[projectType]/view/[viewId].vue

@ -1,9 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { message } from 'ant-design-vue'
import { import {
ReadonlyInj, ReadonlyInj,
ReloadViewDataHookInj, ReloadViewDataHookInj,
createEventHook, createEventHook,
definePageMeta, definePageMeta,
extractSdkResponseErrorMsg,
provide, provide,
ref, ref,
useRoute, useRoute,
@ -27,8 +29,13 @@ const showPassword = ref(false)
try { try {
await loadSharedView(route.params.viewId as string) await loadSharedView(route.params.viewId as string)
} catch (e) { } catch (e: any) {
if (e?.response?.status === 403) {
showPassword.value = true showPassword.value = true
} else {
console.error(e)
message.error(await extractSdkResponseErrorMsg(e))
}
} }
</script> </script>

Loading…
Cancel
Save