Browse Source

fix(nc-gui): display audit logs in modal for user how have only base creator access

pull/8836/head
Ramesh Mane 6 months ago
parent
commit
2a0b44f12a
  1. 5
      packages/nc-gui/components/dlg/ProjectAudit.vue
  2. 110
      packages/nc-gui/components/workspace/AuditLogs.vue
  3. 2
      packages/nc-gui/components/workspace/View.vue
  4. 1
      packages/nc-gui/lib/acl.ts

5
packages/nc-gui/components/dlg/ProjectAudit.vue

@ -1,5 +1,6 @@
<script lang="ts" setup>
const props = defineProps<{
workspaceId?: string
baseId: string
sourceId: string
modelValue: boolean
@ -9,7 +10,7 @@ const emit = defineEmits(['update:modelValue'])
const isOpen = useVModel(props, 'modelValue', emit)
const activeSourceId = computed(() => props.sourceId)
const { workspaceId, sourceId } = toRefs(props)
const { openedProject: base } = storeToRefs(useBases())
@ -47,7 +48,7 @@ onMounted(async () => {
<template>
<GeneralModal v-model:visible="isOpen" size="xl" class="!w-[70rem] !top-[5vh]">
<div class="p-6 h-full">
<DashboardSettingsBaseAudit v-if="!isLoading" :source-id="activeSourceId" :base-id="baseId" :show-all-columns="false" />
<WorkspaceAuditLogs v-if="!isLoading" :workspace-id="workspaceId" :source-id="sourceId" :base-id="baseId" />
</div>
</GeneralModal>
</template>

110
packages/nc-gui/components/workspace/AuditLogs.vue

@ -8,12 +8,16 @@ import { AuditLogsDateRange } from '~/lib/enums'
interface Props {
workspaceId?: string
baseId?: string
sourceId?: string
}
const props = defineProps<Props>()
const allowedAuditOperationTypes = [AuditOperationTypes.DATA, AuditOperationTypes.TABLE, AuditOperationTypes.TABLE_COLUMN]
const { isUIAllowed } = useRoles()
const workspaceStore = useWorkspace()
const { loadAudits: _loadAudits } = workspaceStore
@ -30,7 +34,8 @@ const {
const basesStore = useBases()
const { getBaseUsers } = basesStore
const { bases, basesList, basesUser } = storeToRefs(basesStore)
const { bases, basesList } = storeToRefs(basesStore)
const baseCollaborators = ref<User[]>([])
@ -111,12 +116,18 @@ const dateRangeOptions = computed(() => {
]
})
async function loadAudits(page = currentPage.value, limit = currentLimit.value) {
async function loadAudits(page = currentPage.value, limit = currentLimit.value, updateCurrentPage = true) {
try {
if (!props.workspaceId) return
if ((isUIAllowed('workspaceAuditList') && !props.workspaceId) || (!isUIAllowed('workspaceAuditList') && !props.baseId)) {
return
}
if (updateCurrentPage) {
currentPage.value = 1
}
isLoading.value = true
await _loadAudits(props.workspaceId, page, limit)
await _loadAudits(props.workspaceId, updateCurrentPage ? 1 : page, limit)
} catch {
} finally {
isLoading.value = false
@ -272,31 +283,43 @@ watch(
)
onMounted(async () => {
if (audits.value === null) {
await loadAudits(currentPage.value, currentLimit.value)
if (props.baseId) {
auditLogsQuery.value.base = props.baseId
}
if (props.sourceId) {
auditLogsQuery.value.sourceId = props.sourceId
}
if (audits.value === null && appInfo.value.auditEnabled) {
await loadAudits(currentPage.value, currentLimit.value, false)
}
})
</script>
<template>
<div class="h-full flex flex-col gap-4 w-full h-[calc(100vh-120px)] pt-6">
<div class="h-full flex flex-col w-full" :class="{ 'pt-6 gap-6': !baseId, 'gap-4': baseId }">
<div v-if="!appInfo.auditEnabled" class="text-red-500">Audit logs are currently disabled by administrators.</div>
<div class="flex flex-col gap-y-6">
<div class="flex flex-col" :class="{ 'gap-6': !baseId, 'gap-4': baseId }">
<div class="flex flex-col gap-3">
<div class="flex flex-row items-center gap-3">
<h6 class="text-xl font-semibold text-gray-900 !my-0">Audit Logs</h6>
<NcButton class="!px-1" type="text" size="xs" :disabled="isLoading" @click="loadAudits()">
<h6 class="text-xl font-semibold text-gray-900 !my-0">
Audit Logs
<span v-if="baseId"> : {{ bases.get(baseId)?.title }} </span>
</h6>
<NcButton v-if="appInfo.auditEnabled" class="!px-1" type="text" size="xs" :disabled="isLoading" @click="loadAudits()">
<!-- Reload -->
<div class="flex items-center text-gray-600 font-light">
<component :is="iconMap.refresh" :class="{ 'animate-infinite animate-spin': isLoading }" />
</div>
</NcButton>
</div>
<div class="text-sm text-gray-600">Track and monitor any changes made to any base in your workspace.</div>
<div v-if="!baseId" class="text-sm text-gray-600">Track and monitor any changes made to any base in your workspace.</div>
</div>
<div class="px-1 flex items-center gap-3">
<div v-if="appInfo.auditEnabled" class="px-1 flex items-center gap-3">
<NcDropdown
v-if="collaborators?.length"
v-if="auditCollaborators?.length"
v-model:visible="auditDropdowns.user"
@update:visible="handleClearDropdownSearch($event, 'user')"
overlay-class-name="overflow-hidden"
@ -403,7 +426,7 @@ onMounted(async () => {
</NcDropdown>
<NcDropdown
v-if="basesList?.length"
v-if="!baseId && basesList?.length"
v-model:visible="auditDropdowns.base"
@update:visible="handleClearDropdownSearch($event, 'base')"
overlay-class-name="overflow-hidden"
@ -583,7 +606,7 @@ onMounted(async () => {
<div class="!w-[127px] flex items-center justify-between gap-2">
<div class="max-w-full truncate text-sm !leading-5">
Range:
<span :class="{ 'text-brand-500': auditLogsQuery.type }">
<span :class="{ 'text-brand-500': auditLogsQuery.dateRange }">
{{ auditLogsQuery.dateRange ? auditLogsQuery.dateRangeLabel : 'All Time' }}
</span>
</div>
@ -673,37 +696,43 @@ onMounted(async () => {
</NcDropdown>
</div>
</div>
<div class="h-[calc(100%_-_134px)] relative">
<div class="table-wrapper max-h-[calc(100%_-_40px)] overflow-auto nc-scrollbar-thin">
<template v-if="appInfo.auditEnabled">
<div
class="relative"
:class="{
'h-[calc(100%_-_92px)] ': baseId,
'h-[calc(100%_-_134px)]': !baseId,
}"
>
<div class="table-wrapper max-h-[calc(100%_-_40px)] overflow-auto nc-scrollbar-thin relative">
<div class="nc-audit-logs-table table h-full relative">
<div class="thead sticky top-0">
<div class="tr">
<div class="th cell-user !hover:bg-gray-100" @click="updateOrderBy('user')">
<div class="flex items-center gap-3">
<div class="flex-1">User</div>
<NcButton type="text" size="xs" class="!p-0">
<div>User</div>
<GeneralIcon
icon="chevronUpDown"
v-if="auditLogsQuery.orderBy?.user"
icon="chevronDown"
class="flex-none"
:class="{
'sort-asc': auditLogsQuery.orderBy?.user === 'asc',
'sort-desc': auditLogsQuery.orderBy?.user === 'desc',
'transform rotate-180': auditLogsQuery.orderBy?.user === 'asc',
}"
/>
</NcButton>
</div>
</div>
<div class="th cell-timestamp !hover:bg-gray-100" @click="updateOrderBy('created_at')">
<div class="flex items-center gap-3">
<div class="flex-1">Time stamp</div>
<NcButton type="text" size="xs" class="!p-0">
<div>Time stamp</div>
<GeneralIcon
icon="chevronUpDown"
v-if="auditLogsQuery.orderBy?.created_at"
icon="chevronDown"
class="flex-none"
:class="{
'sort-asc': auditLogsQuery.orderBy?.created_at === 'asc',
'sort-desc': auditLogsQuery.orderBy?.created_at === 'desc',
'transform rotate-180': auditLogsQuery.orderBy?.created_at === 'asc',
}"
/>
</NcButton>
</div>
</div>
<div class="th cell-base">Base</div>
@ -714,15 +743,6 @@ onMounted(async () => {
</div>
</div>
<div class="tbody">
<div
v-show="isLoading"
class="flex items-center justify-center absolute l-0 t-0 w-full h-full z-10 pb-10 pointer-events-none"
>
<div class="flex flex-col justify-center items-center gap-2">
<GeneralLoader size="xlarge" />
<span class="text-center">Loading...</span>
</div>
</div>
<template v-if="audits?.length">
<template v-for="(audit, i) of audits" :key="i">
<div
@ -808,6 +828,15 @@ onMounted(async () => {
</div>
</div>
</div>
<div
v-show="isLoading"
class="flex items-center justify-center absolute left-0 top-0 w-full h-full z-10 pb-10 pointer-events-none"
>
<div class="flex flex-col justify-center items-center gap-2">
<GeneralLoader size="xlarge" />
<span class="text-center">Loading...</span>
</div>
</div>
<div
v-if="totalRows"
class="flex flex-row justify-center items-center bg-gray-50 min-h-10"
@ -824,8 +853,8 @@ onMounted(async () => {
:total="+totalRows"
show-size-changer
:use-stored-page-size="false"
@update:current="loadAudits()"
@update:page-size="loadAudits(currentPage, $event)"
@update:current="loadAudits(undefined, undefined, false)"
@update:page-size="loadAudits(currentPage, $event, false)"
/>
</template>
<div class="text-gray-500 text-xs">{{ totalRows }} {{ totalRows === 1 ? 'record' : 'records' }}</div>
@ -921,6 +950,7 @@ onMounted(async () => {
</div>
</div>
</NcModal>
</template>
</div>
</template>

2
packages/nc-gui/components/workspace/View.vue

@ -128,7 +128,9 @@ onMounted(() => {
Audit Logs
</div>
</template>
<div class="h-[calc(100vh-120px)]">
<WorkspaceAuditLogs :workspace-id="currentWorkspace.id" />
</div>
</a-tab-pane>
</NcTabs>
</div>

1
packages/nc-gui/lib/acl.ts

@ -84,6 +84,7 @@ const rolePermissions = {
baseRename: true,
baseDuplicate: true,
sourceCreate: true,
baseAuditList: true,
},
},
[ProjectRoles.EDITOR]: {

Loading…
Cancel
Save