Browse Source

fix(nc-gui): make audit log table first column stick

pull/8836/head
Ramesh Mane 3 months ago
parent
commit
aa3c80bacb
  1. 174
      packages/nc-gui/components/workspace/AuditLogs.vue

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

@ -70,6 +70,8 @@ const isRowExpanded = ref(false)
const selectedAudit = ref<null | AuditType>(null) const selectedAudit = ref<null | AuditType>(null)
const tableWrapper = ref<HTMLDivElement>()
const auditDropdowns = ref({ const auditDropdowns = ref({
type: false, type: false,
subType: false, subType: false,
@ -324,6 +326,20 @@ onMounted(async () => {
await loadAudits(currentPage.value, currentLimit.value, false) await loadAudits(currentPage.value, currentLimit.value, false)
} }
}) })
useEventListener(tableWrapper, 'scroll', () => {
const stickyHeaderCell = tableWrapper.value?.querySelector('th.cell-user')
const nonStickyHeaderFirstCell = tableWrapper.value?.querySelector('th.cell-base')
if (!stickyHeaderCell?.getBoundingClientRect().right || !nonStickyHeaderFirstCell?.getBoundingClientRect().left) {
return
}
if (nonStickyHeaderFirstCell?.getBoundingClientRect().left < stickyHeaderCell?.getBoundingClientRect().right + 180) {
tableWrapper.value?.classList.add('sticky-shadow')
} else {
tableWrapper.value?.classList.remove('sticky-shadow')
}
})
</script> </script>
<template> <template>
@ -765,18 +781,21 @@ onMounted(async () => {
'bordered': bordered, 'bordered': bordered,
}" }"
> >
<div class="table-wrapper h-full max-h-[calc(100%_-_40px)] overflow-auto nc-scrollbar-thin relative"> <div
<div class="nc-audit-logs-table table h-full relative"> ref="tableWrapper"
<div class="thead sticky top-0"> class="nc-audit-logs-table h-full max-h-[calc(100%_-_40px)] nc-scrollbar-thin relative !overflow-auto"
<div class="tr"> >
<div <table class="!sticky top-0 z-10">
class="th cell-user !hover:bg-gray-100 select-none cursor-pointer" <thead>
<tr>
<th
class="cell-user !hover:bg-gray-100 select-none cursor-pointer"
:class="{ :class="{
'cursor-not-allowed': !audits?.length, 'cursor-not-allowed': !audits?.length,
}" }"
@click="updateOrderBy('user')" @click="updateOrderBy('user')"
> >
<div class="flex items-center gap-3 sticky left-0"> <div class="flex items-center gap-3">
<div>User</div> <div>User</div>
<GeneralIcon <GeneralIcon
v-if="auditLogsQuery.orderBy?.user" v-if="auditLogsQuery.orderBy?.user"
@ -788,9 +807,9 @@ onMounted(async () => {
/> />
<GeneralIcon v-else icon="chevronUpDown" class="flex-none" /> <GeneralIcon v-else icon="chevronUpDown" class="flex-none" />
</div> </div>
</div> </th>
<div <th
class="th cell-timestamp !hover:bg-gray-100 select-none cursor-pointer" class="cell-timestamp !hover:bg-gray-100 select-none cursor-pointer"
:class="{ :class="{
'cursor-not-allowed': !audits?.length, 'cursor-not-allowed': !audits?.length,
}" }"
@ -809,25 +828,38 @@ onMounted(async () => {
/> />
<GeneralIcon v-else icon="chevronUpDown" class="flex-none" /> <GeneralIcon v-else icon="chevronUpDown" class="flex-none" />
</div> </div>
</div> </th>
<div class="th cell-base">Base</div> <th class="cell-base">
<div class="th cell-type">Type</div> <div>Base</div>
<div class="th cell-sub-type">Sub-type</div> </th>
<div class="th cell-description">Description</div> <th class="cell-type">
<div class="th cell-ip">IP Address</div> <div>Type</div>
</div> </th>
</div> <th class="cell-sub-type">
<div class="tbody"> <div>Sub-type</div>
<template v-if="audits?.length"> </th>
<template v-for="(audit, i) of audits" :key="i"> <th class="cell-description">
<div <div>Description</div>
class="tr" </th>
:class="{ <th class="cell-ip">
selected: selectedAudit?.id === audit.id && isRowExpanded, <div>IP Address</div>
}" </th>
@click="handleRowClick(audit)" </tr>
> </thead>
<div class="td cell-user"> </table>
<template v-if="audits?.length">
<table>
<tbody>
<tr
v-for="(audit, i) of audits"
:key="i"
:class="{
selected: selectedAudit?.id === audit.id && isRowExpanded,
}"
@click="handleRowClick(audit)"
>
<td class="cell-user">
<div>
<div v-if="audit.user && collaboratorsMap.get(audit.user)?.email" class="w-full flex gap-3 items-center"> <div v-if="audit.user && collaboratorsMap.get(audit.user)?.email" class="w-full flex gap-3 items-center">
<GeneralUserIcon :email="collaboratorsMap.get(audit.user)?.email" size="base" class="flex-none" /> <GeneralUserIcon :email="collaboratorsMap.get(audit.user)?.email" size="base" class="flex-none" />
<div class="flex-1 flex flex-col max-w-[calc(100%_-_44px)]"> <div class="flex-1 flex flex-col max-w-[calc(100%_-_44px)]">
@ -863,14 +895,18 @@ onMounted(async () => {
</div> </div>
<template v-else>{{ audit.user }} </template> <template v-else>{{ audit.user }} </template>
</div> </div>
<div class="td cell-timestamp"> </td>
<td class="cell-timestamp">
<div>
<NcTooltip placement="bottom"> <NcTooltip placement="bottom">
<template #title> {{ parseStringDateTime(audit.created_at, 'D MMMM YYYY HH:mm') }}</template> <template #title> {{ parseStringDateTime(audit.created_at, 'D MMMM YYYY HH:mm') }}</template>
{{ timeAgo(audit.created_at) }} {{ timeAgo(audit.created_at) }}
</NcTooltip> </NcTooltip>
</div> </div>
<div class="td cell-base"> </td>
<td class="cell-base">
<div>
<div v-if="audit.base_id" class="w-full"> <div v-if="audit.base_id" class="w-full">
<NcTooltip <NcTooltip
class="truncate text-sm !leading-5 text-gray-800 font-semibold" class="truncate text-sm !leading-5 text-gray-800 font-semibold"
@ -889,7 +925,9 @@ onMounted(async () => {
{{ audit.base_id }} {{ audit.base_id }}
</template> </template>
</div> </div>
<div class="td cell-type"> </td>
<td class="cell-type">
<div>
<div class="truncate bg-gray-200 px-2 py-1 rounded-lg"> <div class="truncate bg-gray-200 px-2 py-1 rounded-lg">
<NcTooltip class="truncate" placement="bottom" show-on-truncate-only> <NcTooltip class="truncate" placement="bottom" show-on-truncate-only>
<template #title> {{ auditOperationTypeLabels[audit.op_type] }}</template> <template #title> {{ auditOperationTypeLabels[audit.op_type] }}</template>
@ -898,7 +936,9 @@ onMounted(async () => {
</NcTooltip> </NcTooltip>
</div> </div>
</div> </div>
<div class="td cell-sub-type"> </td>
<td class="cell-sub-type">
<div>
<div class="truncate"> <div class="truncate">
<NcTooltip class="truncate" placement="bottom" show-on-truncate-only> <NcTooltip class="truncate" placement="bottom" show-on-truncate-only>
<template #title> {{ auditOperationSubTypeLabels[audit.op_sub_type] }}</template> <template #title> {{ auditOperationSubTypeLabels[audit.op_sub_type] }}</template>
@ -907,21 +947,25 @@ onMounted(async () => {
</NcTooltip> </NcTooltip>
</div> </div>
</div> </div>
<div class="td cell-description"> </td>
<td class="cell-description">
<div>
<div class="truncate"> <div class="truncate">
{{ audit.description }} {{ audit.description }}
</div> </div>
</div> </div>
<div class="td cell-ip"> </td>
<td class="cell-ip">
<div>
<div class="truncate"> <div class="truncate">
{{ audit.ip }} {{ audit.ip }}
</div> </div>
</div> </div>
</div> </td>
</template> </tr>
</template> </tbody>
</div> </table>
</div> </template>
</div> </div>
<div <div
v-show="isLoading" v-show="isLoading"
@ -1074,39 +1118,61 @@ onMounted(async () => {
} }
.nc-audit-logs-table { .nc-audit-logs-table {
.thead { &.sticky-shadow {
.th { th,
td {
&.cell-user {
box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.08);
}
}
}
thead {
th {
@apply bg-gray-50 text-sm text-gray-600; @apply bg-gray-50 text-sm text-gray-600;
&.cell-user {
@apply sticky left-0 z-4 bg-gray-50;
}
} }
} }
.tbody { tbody {
.tr { tr {
@apply cursor-pointer; @apply cursor-pointer;
.td { .td {
@apply text-small leading-[18px] text-gray-600; @apply text-small leading-[18px] text-gray-600;
} }
td {
&.cell-user {
@apply sticky left-0 z-4 bg-white;
}
}
} }
} }
.tr { tr {
@apply h-[54px] flex overflow-hidden border-b-1 border-gray-200; @apply h-[54px] flex border-b-1 border-gray-200;
&:hover .td { &:hover td {
@apply bg-gray-50; @apply !bg-gray-50;
} }
&.selected .td { &.selected td {
@apply bg-gray-50; @apply !bg-gray-50;
} }
.th, th,
.td { td {
@apply px-6 h-full flex items-center; @apply h-full;
& > div {
@apply px-6 h-full flex items-center;
}
&.cell-user { &.cell-user {
@apply w-[220px]; @apply w-[220px] sticky left-0 z-5;
} }
&.cell-timestamp, &.cell-timestamp,

Loading…
Cancel
Save