feat: update activity log permissions and enhance column creation for changes display

This commit is contained in:
Yoga Pangestu 2026-07-25 23:31:24 +07:00
parent 4956f4aeb2
commit 562a2cf38f
5 changed files with 51 additions and 43 deletions

View File

@ -50,8 +50,6 @@ public function permissions(): array
Permission::ROLES_CREATE,
Permission::ROLES_UPDATE,
Permission::ROLES_DELETE,
Permission::ACTIVITY_LOGS_VIEW,
], true)
)),
@ -106,6 +104,8 @@ public function permissions(): array
Permission::EXPENSES_VIEW,
Permission::ACTIVITY_LOGS_VIEW,
Permission::EMPLOYEE_ADVANCES_VIEW,
Permission::EMPLOYEE_ADVANCES_CREATE,
Permission::EMPLOYEE_ADVANCES_UPDATE,
@ -188,6 +188,8 @@ public function permissions(): array
Permission::EXPENSES_UPDATE,
Permission::EXPENSES_DELETE,
Permission::ACTIVITY_LOGS_VIEW,
Permission::EMPLOYEE_ADVANCES_VIEW,
Permission::EMPLOYEE_ADVANCES_CREATE,
Permission::EMPLOYEE_ADVANCES_UPDATE,
@ -317,6 +319,8 @@ public function permissions(): array
Permission::EMPLOYEE_ADVANCES_DELETE,
Permission::EMPLOYEE_ADVANCES_PAY,
Permission::ACTIVITY_LOGS_VIEW,
Permission::PAYROLL_VIEW,
],

View File

@ -6,9 +6,8 @@ import { Card, CardContent } from '@/components/ui/card';
import { useDataTableQuery, useDataTableQuerySync } from '@/composables/useDataTableQuery';
import AdminLayout from '@/layouts/AdminLayout.vue';
import { index } from '@/routes/admin/system/activity_logs';
import type { ActivityLogListItem, PaginatedActivityLogs, SelectOption } from '@/types/activity-log';
import type { DataTableSort } from '@/types/data-table';
import ActivityLogDetailModal from './table/ActivityLogDetailModal.vue';
import type { PaginatedActivityLogs } from '@/types/activity-log';
import type { DataTableFilterOption, DataTableSort } from '@/types/data-table';
import { createColumns } from './table/columns';
const props = defineProps<{
@ -20,13 +19,11 @@ const props = defineProps<{
event?: string;
subject_type?: string;
};
eventOptions: SelectOption[];
subjectOptions: SelectOption[];
eventOptions: DataTableFilterOption[];
subjectOptions: DataTableFilterOption[];
}>();
const search = ref(props.filters.search ?? '');
const detailModalOpen = ref(false);
const selectedActivityLog = ref<ActivityLogListItem | null>(null);
const { query, setSearch, setSort, setFilter, resetFilters, syncFromServer } = useDataTableQuery({
url: index.url(),
@ -36,7 +33,7 @@ const { query, setSearch, setSort, setFilter, resetFilters, syncFromServer } = u
useDataTableQuerySync(() => props.filters, syncFromServer);
const columns = computed(() => createColumns(openDetailModal));
const columns = computed(() => createColumns());
const filterDefs = computed(() => [
{
@ -76,11 +73,6 @@ const pagination = computed(() => ({
total: props.activityLogs.total,
}));
function openDetailModal(activityLog: ActivityLogListItem) {
selectedActivityLog.value = activityLog;
detailModalOpen.value = true;
}
watch(search, (value) => {
setSearch(value);
});
@ -112,7 +104,5 @@ watch(
@filter-change="setFilter" @filters-reset="resetFilters" />
</CardContent>
</Card>
<ActivityLogDetailModal v-model:open="detailModalOpen" :activity-log="selectedActivityLog" />
</AdminLayout>
</template>

View File

@ -2,9 +2,24 @@ import type { ColumnDef } from '@tanstack/vue-table';
import { h } from 'vue';
import { DataTableColumnHeader } from '@/components/data-table';
import type { ActivityLogListItem } from '@/types/activity-log';
import DataTableActions from './data-table-actions.vue';
export function createColumns(onView: (activityLog: ActivityLogListItem) => void): ColumnDef<ActivityLogListItem>[] {
function formatValue(value: unknown): string {
if (value === null || value === undefined || value === '') {
return '-';
}
if (typeof value === 'boolean') {
return value ? 'Ya' : 'Tidak';
}
if (typeof value === 'object') {
return JSON.stringify(value);
}
return String(value);
}
export function createColumns(): ColumnDef<ActivityLogListItem>[] {
return [
{
accessorKey: 'created_at_formatted',
@ -33,13 +48,30 @@ export function createColumns(onView: (activityLog: ActivityLogListItem) => void
header: () => h(DataTableColumnHeader, { title: 'Deskripsi', column: 'description' }),
},
{
id: 'actions',
id: 'changes',
enableSorting: false,
enableHiding: false,
cell: ({ row }) => h(DataTableActions, {
activityLog: row.original,
onView: () => onView(row.original),
}),
header: 'Perubahan',
cell: ({ row }) => {
const changes = row.original.changes;
if (!changes.length) {
return h('span', { class: 'text-muted-foreground text-sm' }, '-');
}
const items = changes.map((change) =>
h('div', { class: 'text-xs space-y-0.5' }, [
h('div', { class: 'font-medium text-muted-foreground' }, change.field),
h('div', { class: 'flex items-center gap-1.5' }, [
h('span', { class: 'text-red-600' }, formatValue(change.old)),
h('span', { class: 'text-muted-foreground' }, '→'),
h('span', { class: 'text-green-600' }, formatValue(change.new)),
]),
]),
);
return h('div', { class: 'space-y-2 min-w-48' }, items);
},
},
];
}

View File

@ -1,16 +0,0 @@
<script setup lang="ts">
import { RowDetailAction } from '@/components/button';
import type { ActivityLogListItem } from '@/types/activity-log';
defineProps<{
activityLog: ActivityLogListItem;
}>();
const emit = defineEmits<{
view: [];
}>();
</script>
<template>
<RowDetailAction tooltip="Lihat" @click="emit('view')" />
</template>

View File

@ -1,6 +1,4 @@
import type { Paginated, SelectOption } from '@/types/common';
export type { SelectOption } from '@/types/common';
import type { Paginated } from '@/types/common';
export type ActivityLogChange = {
field: string;