Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prevent commentor/viewer from enabling hidden columns #8268

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
83 changes: 76 additions & 7 deletions packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
<script lang="ts" setup>
import type { CalendarType, ColumnType, GalleryType, KanbanType } from 'nocodb-sdk'
import { UITypes, ViewTypes, isVirtualCol } from 'nocodb-sdk'
import { ProjectRoles, UITypes, ViewTypes, isVirtualCol } from 'nocodb-sdk'
import Draggable from 'vuedraggable'

import type { SelectProps } from 'ant-design-vue'

import {
ActiveViewInj,
FieldsInj,
IsLockedInj,
IsPublicInj,
computed,
iconMap,
inject,
ref,
resolveComponent,
useMenuCloseOnEsc,
useNuxtApp,
useRoles,
useSmartsheetStoreOrThrow,
useUndoRedo,
useViewColumnsOrThrow,
watch,
} from '#imports'

const activeView = inject(ActiveViewInj, ref())

const { baseRoles } = useRoles()

const reloadViewMetaHook = inject(ReloadViewMetaHookInj, undefined)!

const reloadViewDataHook = inject(ReloadViewDataHookInj, undefined)!
Expand All @@ -33,7 +54,20 @@ const {
toggleFieldVisibility,
} = useViewColumnsOrThrow()

const { eventBus, isDefaultView } = useSmartsheetStoreOrThrow()

const hiddenFields = ref<string[]>([])

const isLocalMode = computed(
() => isPublic.value || baseRoles?.value[ProjectRoles.COMMENTER] || baseRoles?.value[ProjectRoles.VIEWER],
)

const shouldShowField = (id: string) => {
if (isLocalMode.value && hiddenFields.value.includes(id)) return false
return true
}

const { eventBus } = useSmartsheetStoreOrThrow()


const { addUndo, defineViewScope } = useUndoRedo()

Expand All @@ -45,7 +79,26 @@ eventBus.on((event) => {
}
})

const numberOfHiddenFields = computed(() => filteredFieldList.value?.filter((field) => !field.show)?.length)

watch(
sortedAndFilteredFields,
(v) => {
if (rootFields) rootFields.value = v || []
},
{ immediate: true },
)

const numberOfHiddenFields = computed(() => {
if (isLocalMode.value) {
// slice is added to remove the first element, ie column with name title as default value,
// without slice the count will always be one more than the exact count
return filteredFieldList.value?.slice(1).filter((field) => !hiddenFields.value.includes(field.id) && field.show === false)
?.length
} else {
return filteredFieldList.value?.filter((field) => !field.show)?.length
}
})


const gridDisplayValueField = computed(() => {
if (activeView.value?.type !== ViewTypes.GRID && activeView.value?.type !== ViewTypes.CALENDAR) return null
Expand Down Expand Up @@ -194,7 +247,7 @@ const coverImageColumnId = computed({
},
})

const onShowAll = () => {
const onShowAll = (hiddenFields: Array<string> = []) => {
addUndo({
undo: {
fn: async () => {
Expand All @@ -210,7 +263,7 @@ const onShowAll = () => {
},
scope: defineViewScope({ view: activeView.value }),
})
showAll()
showAll(hiddenFields)
}

const onHideAll = () => {
Expand All @@ -232,13 +285,29 @@ const onHideAll = () => {
hideAll()
}

onMounted(() => {
if (isLocalMode.value) {
hiddenFields.value = filteredFieldList.value.filter((field) => !field.show).map((field) => field.id)
}
})

const showAllColumns = computed({
get: () => {
if (isLocalMode.value) {
if (filteredFieldList.value?.every((field) => !field.show)) return false
return filteredFieldList.value?.every((field) => {
if (hiddenFields.value.includes(field.id)) {
// Skip fields with IDs listed in hiddenFields
return true
}
return field?.show
})
}
return filteredFieldList.value?.every((field) => field.show)
},
set: async (val) => {
if (val) {
await onShowAll()
await onShowAll(hiddenFields.value)
} else {
await onHideAll()
}
Expand Down Expand Up @@ -393,7 +462,7 @@ useMenuCloseOnEsc(open)
v-if="
filteredFieldList
.filter((el) => (activeView.type !== ViewTypes.CALENDAR ? el !== gridDisplayValueField : true))
.includes(field)
.includes(field) && shouldShowField(field.id)
"
:key="field.id"
:data-testid="`nc-fields-menu-${field.title}`"
Expand Down
21 changes: 14 additions & 7 deletions packages/nc-gui/composables/useViewColumns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,19 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
}
}

const showAll = async (ignoreIds?: any) => {
// `ignoreIds` allows specifying field IDs that should not be altered by this function.
const showAll = async (ignoreIds: Array<string> = []) => {
if (isLocalMode.value) {
fields.value = fields.value?.map((field: Field) => ({
...field,
show: true,
}))
fields.value = fields.value?.map((field: Field) => {
if (ignoreIds.includes(field.id)) {
return field
} else {
return {
...field,
show: true,
}
}
})
reloadData?.()
return
}
Expand Down Expand Up @@ -160,7 +167,7 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
}

const saveOrUpdate = async (
field: any,
field: Field,
index: number,
disableDataReload: boolean = false,
updateDefaultViewColumnOrder: boolean = false,
Expand Down Expand Up @@ -266,7 +273,7 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
?.map((field: Field) => metaColumnById?.value?.[field.fk_column_id!]) || []) as ColumnType[]
})

const toggleFieldVisibility = (checked: boolean, field: any) => {
const toggleFieldVisibility = (checked: boolean, field: Field) => {
const fieldIndex = fields.value?.findIndex((f) => f.fk_column_id === field.fk_column_id)
if (!fieldIndex && fieldIndex !== 0) return
addUndo({
Expand Down
1 change: 1 addition & 0 deletions packages/nc-gui/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface ProjectMetaInfo {
}

interface Field {
id: string
order: number
show: number | boolean
bold: boolean | number
Expand Down