Browse Source

fix(nc-gui): show only available audit types

pull/8836/head
Ramesh Mane 2 weeks ago
parent
commit
af7407d98f
  1. 106
      packages/nc-gui/components/workspace/AuditLogs.vue
  2. 47
      packages/nocodb-sdk/src/lib/globals.ts

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

@ -1,12 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import { Empty } from 'ant-design-vue' import { Empty } from 'ant-design-vue'
import type { AuditType, WorkspaceUserType } from 'nocodb-sdk' import type { AuditType, WorkspaceUserType } from 'nocodb-sdk'
import { timeAgo, AuditOperationTypes, AuditOperationSubTypes } from 'nocodb-sdk' import {
timeAgo,
AuditOperationTypes,
AuditOperationSubTypes,
auditOperationTypeLabels,
auditOperationSubTypeLabels,
} from 'nocodb-sdk'
interface Props { interface Props {
workspaceId?: string workspaceId?: string
} }
const allowedAuditOperationTypes = [AuditOperationTypes.DATA, AuditOperationTypes.TABLE, AuditOperationTypes.TABLE_COLUMN]
const allowedAuditOperationSubTypes = [
AuditOperationSubTypes.CREATE,
AuditOperationSubTypes.UPDATE,
AuditOperationSubTypes.DELETE,
AuditOperationSubTypes.INSERT,
AuditOperationSubTypes.LINK_RECORD,
AuditOperationSubTypes.UNLINK_RECORD,
]
const props = defineProps<Props>() const props = defineProps<Props>()
const workspaceStore = useWorkspace() const workspaceStore = useWorkspace()
@ -52,6 +68,43 @@ const auditDropdowns = ref({
user: false, user: false,
}) })
const auditTypeOptions = computed(() => {
return Object.values(AuditOperationTypes)
.filter((type) => allowedAuditOperationTypes.includes(type as AuditOperationTypes))
.map((type) => ({
label: auditOperationTypeLabels[type],
value: type,
}))
})
const auditSubTypeOptions = computed(() => {
return Object.values(AuditOperationSubTypes)
.filter((subType) => {
if (
auditLogsQuery.value.type === AuditOperationTypes.TABLE ||
auditLogsQuery.value.type === AuditOperationTypes.TABLE_COLUMN
) {
return [AuditOperationSubTypes.CREATE, AuditOperationSubTypes.UPDATE, AuditOperationSubTypes.DELETE].includes(subType)
}
if (auditLogsQuery.value.type === AuditOperationTypes.DATA) {
return [
AuditOperationSubTypes.UPDATE,
AuditOperationSubTypes.DELETE,
AuditOperationSubTypes.INSERT,
AuditOperationSubTypes.LINK_RECORD,
AuditOperationSubTypes.UNLINK_RECORD,
].includes(subType)
}
return allowedAuditOperationSubTypes.includes(subType)
})
.map((subType) => ({
label: auditOperationSubTypeLabels[subType],
value: subType,
}))
})
async function loadAudits(page = currentPage.value, limit = currentLimit.value) { async function loadAudits(page = currentPage.value, limit = currentLimit.value) {
try { try {
if (!props.workspaceId) return if (!props.workspaceId) return
@ -124,11 +177,13 @@ onMounted(async () => {
</template> </template>
</a-input> </a-input>
</form> </form>
<div class="flex items-stretch border-1 border-gray-200 rounded-lg overflow-hidden"> <div class="flex items-stretch border-1 border-gray-200 rounded-lg overflow-hidden h-8">
<NcDropdown v-model:visible="auditDropdowns.type"> <NcDropdown v-model:visible="auditDropdowns.type">
<NcButton type="secondary" size="small" class="!border-none !rounded-none"> <NcButton type="secondary" size="small" class="!border-none !rounded-none">
<div class="!w-[106px] flex items-center justify-between gap-2"> <div class="!w-[106px] flex items-center justify-between gap-2">
<div class="max-w-[120px] truncate text-sm !leading-5">Type: {{ auditLogsQuery.type || 'All' }}</div> <div class="max-w-[120px] truncate text-sm !leading-5">
Type: {{ auditOperationTypeLabels[auditLogsQuery.type] || 'All' }}
</div>
<GeneralIcon icon="arrowDown" class="flex-none h-4 w-4" /> <GeneralIcon icon="arrowDown" class="flex-none h-4 w-4" />
</div> </div>
</NcButton> </NcButton>
@ -139,6 +194,7 @@ onMounted(async () => {
@click=" @click="
() => { () => {
auditDropdowns.type = false auditDropdowns.type = false
loadAudits() loadAudits()
} }
" "
@ -151,17 +207,22 @@ onMounted(async () => {
</NcMenuItem> </NcMenuItem>
<NcDivider /> <NcDivider />
<NcMenuItem <NcMenuItem
v-for="type in AuditOperationTypes" v-for="type in auditTypeOptions"
:key="type" :key="type.value"
class="!children:w-full" class="!children:w-full"
@click="auditLogsQuery.type = type" @click="
() => {
auditLogsQuery.type = type.value
auditLogsQuery.subType = undefined
}
"
> >
<div class="w-full flex items-center justify-between gap-3"> <div class="w-full flex items-center justify-between gap-3">
<div class="flex-1 flex items-center gap-2 max-w-[calc(100%_-_28px)]"> <div class="flex-1 flex items-center gap-2 max-w-[calc(100%_-_28px)]">
{{ type }} {{ type.label }}
</div> </div>
<GeneralIcon v-if="auditLogsQuery.type === type" icon="check" class="flex-none text-primary w-4 h-4" /> <GeneralIcon v-if="auditLogsQuery.type === type.value" icon="check" class="flex-none text-primary w-4 h-4" />
</div> </div>
</NcMenuItem> </NcMenuItem>
</NcMenu> </NcMenu>
@ -170,7 +231,10 @@ onMounted(async () => {
<NcDropdown v-model:visible="auditDropdowns.subType" placement="bottomRight"> <NcDropdown v-model:visible="auditDropdowns.subType" placement="bottomRight">
<NcButton type="secondary" size="small" class="!border-none !rounded-none"> <NcButton type="secondary" size="small" class="!border-none !rounded-none">
<div class="!w-[146px] flex items-center justify-between gap-2"> <div class="!w-[146px] flex items-center justify-between gap-2">
<div class="truncate text-sm !leading-5">Sub-Type: {{ auditLogsQuery.subType || 'All' }}</div> <div class="truncate text-sm !leading-5">
Sub-Type:
{{ auditLogsQuery.subType ? auditOperationSubTypeLabels[auditLogsQuery.subType] : 'All' }}
</div>
<GeneralIcon icon="arrowDown" class="flex-none h-4 w-4" /> <GeneralIcon icon="arrowDown" class="flex-none h-4 w-4" />
</div> </div>
</NcButton> </NcButton>
@ -193,17 +257,21 @@ onMounted(async () => {
</NcMenuItem> </NcMenuItem>
<NcDivider /> <NcDivider />
<NcMenuItem <NcMenuItem
v-for="subType in AuditOperationSubTypes" v-for="subType in auditSubTypeOptions"
:key="subType" :key="subType.value"
class="!children:w-full" class="!children:w-full"
@click="auditLogsQuery.subType = subType" @click="auditLogsQuery.subType = subType.value"
> >
<div class="w-full flex items-center justify-between gap-3"> <div class="w-full flex items-center justify-between gap-3">
<div class="flex-1 flex items-center gap-2 max-w-[calc(100%_-_28px)]"> <div class="flex-1 flex items-center gap-2 max-w-[calc(100%_-_28px)]">
{{ subType }} {{ subType.label }}
</div> </div>
<GeneralIcon v-if="auditLogsQuery.subType === subType" icon="check" class="flex-none text-primary w-4 h-4" /> <GeneralIcon
v-if="auditLogsQuery.subType === subType.value"
icon="check"
class="flex-none text-primary w-4 h-4"
/>
</div> </div>
</NcMenuItem> </NcMenuItem>
</NcMenu> </NcMenu>
@ -415,20 +483,20 @@ onMounted(async () => {
</template> </template>
</div> </div>
<div class="td cell-type"> <div class="td cell-type">
<div class="truncate"> <div class="truncate bg-gray-200 px-3 py-1 rounded-lg">
<NcTooltip class="truncate" placement="bottom" show-on-truncate-only> <NcTooltip class="truncate" placement="bottom" show-on-truncate-only>
<template #title> {{ audit.op_type }}</template> <template #title> {{ auditOperationTypeLabels[audit.op_type] }}</template>
<span class="truncate"> {{ audit.op_type }} </span> <span class="truncate"> {{ auditOperationTypeLabels[audit.op_type] }} </span>
</NcTooltip> </NcTooltip>
</div> </div>
</div> </div>
<div class="td cell-sub-type"> <div class="td cell-sub-type">
<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> {{ audit.op_sub_type }}</template> <template #title> {{ auditOperationSubTypeLabels[audit.op_sub_type] }}</template>
<span class="truncate"> {{ audit.op_sub_type }} </span> <span class="truncate"> {{ auditOperationSubTypeLabels[audit.op_sub_type] }} </span>
</NcTooltip> </NcTooltip>
</div> </div>
</div> </div>

47
packages/nocodb-sdk/src/lib/globals.ts

@ -44,16 +44,32 @@ export enum AuditOperationTypes {
ORG_USER = 'ORG_USER', ORG_USER = 'ORG_USER',
} }
export const auditOperationTypeLabels = {
[AuditOperationTypes.COMMENT]: 'Comment',
[AuditOperationTypes.DATA]: 'Data',
[AuditOperationTypes.PROJECT]: 'Project',
[AuditOperationTypes.VIRTUAL_RELATION]: 'Virtual Relation',
[AuditOperationTypes.RELATION]: 'Relation',
[AuditOperationTypes.TABLE_VIEW]: 'Table View',
[AuditOperationTypes.TABLE]: 'Table',
[AuditOperationTypes.VIEW]: 'View',
[AuditOperationTypes.META]: 'Meta',
[AuditOperationTypes.WEBHOOKS]: 'Webhooks',
[AuditOperationTypes.AUTHENTICATION]: 'Authentication',
[AuditOperationTypes.TABLE_COLUMN]: 'Table Column',
[AuditOperationTypes.ORG_USER]: 'Org User',
};
export enum AuditOperationSubTypes { export enum AuditOperationSubTypes {
UPDATE = 'UPDATE',
INSERT = 'INSERT', INSERT = 'INSERT',
CREATE = 'CREATE',
UPDATE = 'UPDATE',
DELETE = 'DELETE',
BULK_INSERT = 'BULK_INSERT', BULK_INSERT = 'BULK_INSERT',
BULK_UPDATE = 'BULK_UPDATE', BULK_UPDATE = 'BULK_UPDATE',
BULK_DELETE = 'BULK_DELETE', BULK_DELETE = 'BULK_DELETE',
LINK_RECORD = 'LINK_RECORD', LINK_RECORD = 'LINK_RECORD',
UNLINK_RECORD = 'UNLINK_RECORD', UNLINK_RECORD = 'UNLINK_RECORD',
DELETE = 'DELETE',
CREATE = 'CREATE',
RENAME = 'RENAME', RENAME = 'RENAME',
IMPORT_FROM_ZIP = 'IMPORT_FROM_ZIP', IMPORT_FROM_ZIP = 'IMPORT_FROM_ZIP',
EXPORT_TO_FS = 'EXPORT_TO_FS', EXPORT_TO_FS = 'EXPORT_TO_FS',
@ -69,6 +85,31 @@ export enum AuditOperationSubTypes {
RESEND_INVITE = 'RESEND_INVITE', RESEND_INVITE = 'RESEND_INVITE',
} }
export const auditOperationSubTypeLabels = {
[AuditOperationSubTypes.UPDATE]: 'Update',
[AuditOperationSubTypes.INSERT]: 'Insert',
[AuditOperationSubTypes.DELETE]: 'Delete',
[AuditOperationSubTypes.BULK_INSERT]: 'Bulk Insert',
[AuditOperationSubTypes.BULK_UPDATE]: 'Bulk Update',
[AuditOperationSubTypes.BULK_DELETE]: 'Bulk Delete',
[AuditOperationSubTypes.LINK_RECORD]: 'Link Record',
[AuditOperationSubTypes.UNLINK_RECORD]: 'Unlink Record',
[AuditOperationSubTypes.CREATE]: 'Create',
[AuditOperationSubTypes.RENAME]: 'Rename',
[AuditOperationSubTypes.IMPORT_FROM_ZIP]: 'Import From Zip',
[AuditOperationSubTypes.EXPORT_TO_FS]: 'Export To FS',
[AuditOperationSubTypes.EXPORT_TO_ZIP]: 'Export To Zip',
[AuditOperationSubTypes.SIGNIN]: 'Signin',
[AuditOperationSubTypes.SIGNUP]: 'Signup',
[AuditOperationSubTypes.PASSWORD_RESET]: 'Password Reset',
[AuditOperationSubTypes.PASSWORD_FORGOT]: 'Password Forgot',
[AuditOperationSubTypes.PASSWORD_CHANGE]: 'Password Change',
[AuditOperationSubTypes.EMAIL_VERIFICATION]: 'Email Verification',
[AuditOperationSubTypes.ROLES_MANAGEMENT]: 'Roles Management',
[AuditOperationSubTypes.INVITE]: 'Invite',
[AuditOperationSubTypes.RESEND_INVITE]: 'Resend Invite',
};
export enum PluginCategory { export enum PluginCategory {
STORAGE = 'Storage', STORAGE = 'Storage',
EMAIL = 'Email', EMAIL = 'Email',

Loading…
Cancel
Save