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_CREATE,
Permission::ROLES_UPDATE, Permission::ROLES_UPDATE,
Permission::ROLES_DELETE, Permission::ROLES_DELETE,
Permission::ACTIVITY_LOGS_VIEW,
], true) ], true)
)), )),
@ -106,6 +104,8 @@ public function permissions(): array
Permission::EXPENSES_VIEW, Permission::EXPENSES_VIEW,
Permission::ACTIVITY_LOGS_VIEW,
Permission::EMPLOYEE_ADVANCES_VIEW, Permission::EMPLOYEE_ADVANCES_VIEW,
Permission::EMPLOYEE_ADVANCES_CREATE, Permission::EMPLOYEE_ADVANCES_CREATE,
Permission::EMPLOYEE_ADVANCES_UPDATE, Permission::EMPLOYEE_ADVANCES_UPDATE,
@ -188,6 +188,8 @@ public function permissions(): array
Permission::EXPENSES_UPDATE, Permission::EXPENSES_UPDATE,
Permission::EXPENSES_DELETE, Permission::EXPENSES_DELETE,
Permission::ACTIVITY_LOGS_VIEW,
Permission::EMPLOYEE_ADVANCES_VIEW, Permission::EMPLOYEE_ADVANCES_VIEW,
Permission::EMPLOYEE_ADVANCES_CREATE, Permission::EMPLOYEE_ADVANCES_CREATE,
Permission::EMPLOYEE_ADVANCES_UPDATE, Permission::EMPLOYEE_ADVANCES_UPDATE,
@ -317,6 +319,8 @@ public function permissions(): array
Permission::EMPLOYEE_ADVANCES_DELETE, Permission::EMPLOYEE_ADVANCES_DELETE,
Permission::EMPLOYEE_ADVANCES_PAY, Permission::EMPLOYEE_ADVANCES_PAY,
Permission::ACTIVITY_LOGS_VIEW,
Permission::PAYROLL_VIEW, Permission::PAYROLL_VIEW,
], ],

View File

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

View File

@ -2,9 +2,24 @@ import type { ColumnDef } from '@tanstack/vue-table';
import { h } from 'vue'; import { h } from 'vue';
import { DataTableColumnHeader } from '@/components/data-table'; import { DataTableColumnHeader } from '@/components/data-table';
import type { ActivityLogListItem } from '@/types/activity-log'; 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 [ return [
{ {
accessorKey: 'created_at_formatted', accessorKey: 'created_at_formatted',
@ -33,13 +48,30 @@ export function createColumns(onView: (activityLog: ActivityLogListItem) => void
header: () => h(DataTableColumnHeader, { title: 'Deskripsi', column: 'description' }), header: () => h(DataTableColumnHeader, { title: 'Deskripsi', column: 'description' }),
}, },
{ {
id: 'actions', id: 'changes',
enableSorting: false, enableSorting: false,
enableHiding: false, enableHiding: false,
cell: ({ row }) => h(DataTableActions, { header: 'Perubahan',
activityLog: row.original, cell: ({ row }) => {
onView: () => onView(row.original), 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'; import type { Paginated } from '@/types/common';
export type { SelectOption } from '@/types/common';
export type ActivityLogChange = { export type ActivityLogChange = {
field: string; field: string;