Refactor DepartmentLane.vue to use reusable ModuleActionLogsTable component

- Replaced inline logs table in `DepartmentLane.vue` with reusable `ModuleActionLogsTable` for better modularity.
- Enhanced `ModuleActionLogs` to support pagination and dynamic filtering.
- Introduced new `ModuleActionLogsTable.vue` component to centralize log display logic.
This commit is contained in:
Jeppe Bundgaard
2026-01-06 11:29:30 +01:00
parent e9d72918a7
commit de25e9c5f0
3 changed files with 148 additions and 41 deletions
@@ -0,0 +1,143 @@
<script setup>
import {computed, onMounted, ref, watch} from 'vue';
import {SessionUser} from "@/components/session/token/SessionUser.vue";
import PaginationNavigation from "@/components/displays/pagination/PaginationNavigation.vue";
import PaginationDisplay from "@/components/displays/pagination/PaginationDisplay.vue";
const props = defineProps({
module: {
type: String,
default: null
},
title: {
type: String,
default: 'Handlingslogs'
}
});
const logs = ref([]);
const isLoading = ref(false);
// Pagination state
const currentPage = ref(1);
const itemsPerPage = ref(10);
const totalItems = ref(0);
const totalPages = computed(() => {
return Math.ceil(totalItems.value / itemsPerPage.value);
});
const loadLogs = async () => {
isLoading.value = true;
try {
const filters = {};
if (props.module) {
filters.module = props.module;
}
const response = await SessionUser.objects.module_action_logs.get.all(
filters,
{ page: currentPage.value, limit: itemsPerPage.value, order: 'id:DESC' }
);
// Based on the implementation in DepartmentLane.vue, we need to handle both raw array and paginated response
if (response && response.data) {
logs.value = response.data;
if (response.meta && response.meta.pagination) {
totalItems.value = response.meta.pagination.total;
} else {
totalItems.value = response.data.length;
}
} else {
logs.value = response || [];
totalItems.value = logs.value.length;
}
} catch (error) {
console.error("Failed to load logs:", error);
} finally {
isLoading.value = false;
}
};
const setPage = (page) => {
currentPage.value = page;
loadLogs();
};
const setItemsPerPage = (limit) => {
itemsPerPage.value = limit;
currentPage.value = 1;
loadLogs();
};
onMounted(() => {
loadLogs();
});
watch(() => props.module, () => {
currentPage.value = 1;
loadLogs();
});
</script>
<template>
<div class="box">
<h3 class="title is-4">{{ title }}</h3>
<PaginationDisplay
:metaItemsPerPage="itemsPerPage"
:loadFunction="loadLogs"
:isLoading="isLoading"
:setMetaItemsPerPage="setItemsPerPage"
/>
<div class="table-container">
<table class="table is-fullwidth is-striped is-hoverable" :class="{ 'is-skeleton': isLoading }">
<thead>
<tr>
<th>{{ SessionUser.objects.module_action_logs.columns.created_at.label }}</th>
<th v-if="!module">{{ SessionUser.objects.module_action_logs.columns.module.label }}</th>
<th>{{ SessionUser.objects.module_action_logs.columns.action.label }}</th>
<th>{{ SessionUser.objects.module_action_logs.columns.status_code.label }}</th>
<th>{{ SessionUser.objects.module_action_logs.columns.data.label }}</th>
</tr>
</thead>
<tbody>
<tr v-for="log in logs" :key="log.id">
<td>{{ new Date(log.created_at).toLocaleString() }}</td>
<td v-if="!module">{{ log.module }}</td>
<td>{{ log.action }}</td>
<td>
<span class="tag" :class="log.status_code >= 200 && log.status_code < 300 ? 'is-success' : 'is-danger'">
{{ log.status_code }}
</span>
</td>
<td>
<pre style="font-size: 0.75rem; max-height: 100px; overflow-y: auto;">{{ JSON.stringify(log.data, null, 2) }}</pre>
</td>
</tr>
<tr v-if="logs.length === 0 && !isLoading">
<td :colspan="module ? 4 : 5" class="has-text-centered">Ingen logs fundet</td>
</tr>
</tbody>
</table>
</div>
<PaginationNavigation
:currentPage="currentPage"
:totalPages="totalPages"
:setPage="setPage"
:loadFunction="loadLogs"
:isLoading="isLoading"
/>
</div>
</template>
<style scoped>
pre {
background-color: transparent;
padding: 0;
margin: 0;
color: inherit;
}
</style>
@@ -48,14 +48,10 @@ export const ModuleActionLogs = {
}
},
get: {
all: async (filters = {}) => {
all: async (filters = {}, pagination = { page: 1, limit: 10, order: 'id:DESC' }) => {
return ObjectsGlobal.get.list(ModuleActionLogs.meta.endpoint, {
filters: filters,
pagination: {
page: 1,
limit: 100,
order: 'id:DESC'
}
pagination: pagination
});
},
single: async (id) => {
@@ -1,17 +1,17 @@
<script setup>
import {onMounted, ref} from 'vue';
import {computed, onMounted, ref} from 'vue';
import {useRouter} from 'vue-router';
import {SessionUser} from "@/components/session/token/SessionUser.vue";
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import SuperUserDashboardNavigation from "@/views/dashboards/superUserDashboard/SuperUserDashboardNavigation.vue";
import PageTitle from "@/components/global/PageTitle.vue";
import ModuleActionLogsTable from "@/components/displays/superuser/tables/ModuleActionLogsTable.vue";
const router = useRouter();
const laneId = router.currentRoute.value.params.id;
const lane = ref(null);
const isLoading = ref(true);
const departmentName = ref('');
const logs = ref([]);
const loadLane = async () => {
isLoading.value = true;
@@ -20,7 +20,6 @@ const loadLane = async () => {
SessionUser.objects.department_lanes.functions.getDepartmentName(lane.value.department).then(name => {
departmentName.value = name;
});
logs.value = await SessionUser.objects.module_action_logs.get.all({module: 'selfserve'});
} catch (error) {
console.error("Failed to load lane:", error);
} finally {
@@ -128,38 +127,7 @@ onMounted(() => {
<div class="columns">
<div class="column is-12">
<div class="box">
<h3 class="title is-4">Handlingslogs (selfserve)</h3>
<div class="table-container">
<table class="table is-fullwidth is-striped is-hoverable">
<thead>
<tr>
<th>{{ SessionUser.objects.module_action_logs.columns.created_at.label }}</th>
<th>{{ SessionUser.objects.module_action_logs.columns.action.label }}</th>
<th>{{ SessionUser.objects.module_action_logs.columns.status_code.label }}</th>
<th>{{ SessionUser.objects.module_action_logs.columns.data.label }}</th>
</tr>
</thead>
<tbody>
<tr v-for="log in logs" :key="log.id">
<td>{{ new Date(log.created_at).toLocaleString() }}</td>
<td>{{ log.action }}</td>
<td>
<span class="tag" :class="log.status_code >= 200 && log.status_code < 300 ? 'is-success' : 'is-danger'">
{{ log.status_code }}
</span>
</td>
<td>
<pre style="font-size: 0.75rem; max-height: 100px; overflow-y: auto;">{{ JSON.stringify(log.data, null, 2) }}</pre>
</td>
</tr>
<tr v-if="logs.length === 0">
<td colspan="4" class="has-text-centered">Ingen logs fundet</td>
</tr>
</tbody>
</table>
</div>
</div>
<ModuleActionLogsTable module="selfserve" title="Handlingslogs (selfserve)" />
</div>
</div>
</div>