Skip to content

Commit

Permalink
aded an event bus for admin-caused report changes. updated the dashbo…
Browse files Browse the repository at this point in the history
…ard widgets to listen for those changes, and to refresh accordingly.
  • Loading branch information
banders committed Sep 27, 2024
1 parent 952e9c1 commit 8088101
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ import {
import ReportsWidget from './ReportsWidget.vue';
import ApiService from '../../services/apiService';
import { formatIsoDateTimeAsLocalDate } from '../../utils/date';
import { ref } from 'vue';
import { ref, onMounted, onUnmounted } from 'vue';
import {
ReportChangeService,
ReportChangedEventPayload,
} from '../../services/reportChangeService';
const pageSize = 5;
const reportsWidget = ref<typeof ReportsWidget>();
Expand Down Expand Up @@ -56,6 +60,19 @@ const headers = [
},
];
onMounted(() => {
ReportChangeService.listen(onAnyReportChanged);
});
onUnmounted(() => {
ReportChangeService.unlisten(onAnyReportChanged);
});
function onAnyReportChanged(payload: ReportChangedEventPayload) {
console.log(`recentlySubmittedReports - onAnyReportChanged`);
refresh();
}
async function getRecentlySubmittedReports(): Promise<Report[]> {
const filter: ReportFilterType = [];
const sort: IReportSearchSort = [{ update_date: 'desc' }];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ import {
import ReportsWidget from './ReportsWidget.vue';
import ApiService from '../../services/apiService';
import { formatIsoDateTimeAsLocalDate } from '../../utils/date';
import { ref } from 'vue';
import { ref, onMounted, onUnmounted } from 'vue';
import {
ReportChangeService,
ReportChangedEventPayload,
} from '../../services/reportChangeService';
const pageSize = 5;
const reportsWidget = ref<typeof ReportsWidget>();
Expand All @@ -52,6 +56,19 @@ const headers = [
},
];
onMounted(() => {
ReportChangeService.listen(onAnyReportChanged);
});
onUnmounted(() => {
ReportChangeService.unlisten(onAnyReportChanged);
});
function onAnyReportChanged(payload: ReportChangedEventPayload) {
console.log(`recentlyViewedReports - onAnyReportChanged`);
refresh();
}
async function refresh() {
await reportsWidget.value?.refresh();
}
Expand Down
31 changes: 25 additions & 6 deletions admin-frontend/src/components/reports/ReportActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<v-menu activator="parent">
<v-card class="">
<v-card-text>
<div class="history-panel">
<div class="history-panel h-100">
<ReportAdminActionHistoryView
v-if="!isLoadingAdminActionHistory && reportAdminActionHistory"
:report-admin-action-history="reportAdminActionHistory"
Expand Down Expand Up @@ -58,15 +58,18 @@ export default {
import ConfirmationDialog from '../util/ConfirmationDialog.vue';
import ApiService from '../../services/apiService';
import { Report } from '../../types/reports';
import { ref, onMounted } from 'vue';
import { ref, onMounted, onUnmounted } from 'vue';
import { NotificationService } from '../../services/notificationService';
import ReportAdminActionHistoryView from './ReportAdminActionHistoryPanel.vue';
import { ReportAdminActionHistory } from '../../types/reports';
import {
ReportChangeService,
ReportChangedEventPayload,
} from '../../services/reportChangeService';
const props = defineProps<{
report: Report;
}>();
const emits = defineEmits(['onLockStatusChanged']);
const isLoadingPdf = ref<boolean>(false);
const isLoadingAdminActionHistory = ref<boolean>(false);
Expand All @@ -77,9 +80,20 @@ const reportAdminActionHistory = ref<ReportAdminActionHistory | undefined>(
const confirmDialog = ref<typeof ConfirmationDialog>();
onMounted(() => {
reset();
ReportChangeService.listen(onAnyReportChanged);
});
onUnmounted(() => {
ReportChangeService.unlisten(onAnyReportChanged);
});
function onAnyReportChanged(payload: ReportChangedEventPayload) {
if (payload.reportId == props.report?.report_id) {
console.log(`reportActions (${payload.reportId}) - onAnyReportChanged`);
reset();
}
}
async function lockUnlockReport(reportId: string, makeUnlocked: boolean) {
const lockText = makeUnlocked ? 'unlock' : 'lock';
const isConfirmed = await confirmDialog.value?.open(
Expand All @@ -92,7 +106,9 @@ async function lockUnlockReport(reportId: string, makeUnlocked: boolean) {
);
if (isConfirmed) {
await ApiService.lockUnlockReport(reportId, makeUnlocked);
emits('onLockStatusChanged');
//report_unlock_date and admin_last_access_date will have changed
ReportChangeService.reportChanged(reportId);
}
}
Expand All @@ -104,6 +120,9 @@ async function viewReportInNewTab(reportId: string) {
isLoadingPdf.value = true;
try {
const pdfAsBlob = await ApiService.getPdfReportAsBlob(reportId);
//admin_last_access_date will have changed
ReportChangeService.reportChanged(reportId);
const objectUrl = URL.createObjectURL(pdfAsBlob);
window.open(objectUrl);
} catch (e) {
Expand All @@ -123,6 +142,7 @@ async function openAdminActionHistory(reportId: string) {
}
async function fetchAdminActionHistory(reportId: string) {
console.log('fetchingAdminActionHistory');
isLoadingAdminActionHistory.value = true;
hadErrorLoadingAdminActionHistory.value = false;
try {
Expand All @@ -144,7 +164,6 @@ function reset() {
<style>
.history-panel {
min-width: 280px;
min-height: 50px;
max-height: 210px;
overflow-y: auto;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<template>
<div v-if="!reportAdminActionHistory?.length">No admin events to show</div>
<div
v-if="!reportAdminActionHistory?.length"
class="d-flex flex-column flex-grow-1 flex-shrink-0 justify-center align-center"
>
No admin events to show
</div>
<div v-if="reportAdminActionHistory?.length" class="d-flex flex-column">
<div
v-for="item in reportAdminActionHistory"
Expand Down
46 changes: 46 additions & 0 deletions admin-frontend/src/services/reportChangeService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { TinyEmitter } from 'tiny-emitter';
import { AdminPortalEvent } from '../types/events';

const reportChangedEvents = new TinyEmitter();

export type ReportChangedEventCallback = (
payload: ReportChangedEventPayload,
) => void;

export type ReportChangedEventPayload = { reportId: string };

/**
* This service is an event bus for events related to data changes made by
* admin users to Reports. It is intented to be used by
* components which trigger admin-related report changes (e.g. lock/unlock)
* to alert other components about those changes.
*/
export const ReportChangeService = {
/**
* Pushes a report change event onto the event bus for the given reportId
* @param reportId
*/
reportChanged(reportId: string) {
const payload: ReportChangedEventPayload = { reportId: reportId };
reportChangedEvents.emit(AdminPortalEvent.REPORT_CHANGED, payload);
},

/**
* Register a callback function which will called whenever
* a report change event occurs
* @param eventType the type of event that occurred
* @param callback a function that will be called
*/
listen(callback: ReportChangedEventCallback): void {
reportChangedEvents.on(AdminPortalEvent.REPORT_CHANGED, callback);
},

/**
* Un-register a callback function so that it will no longer be called
* when report change events occur
* @param callback a function that will be de-registered
*/
unlisten(callback: ReportChangedEventCallback): void {
reportChangedEvents.off(AdminPortalEvent.REPORT_CHANGED, callback);
},
};
3 changes: 3 additions & 0 deletions admin-frontend/src/types/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum AdminPortalEvent {
REPORT_CHANGED = 'report_changed',
}
34 changes: 26 additions & 8 deletions backend/src/v1/services/admin-report-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,19 @@ const adminReportService = {
* @returns
*/
async getReportAdminActionHistory(reportId: string) {
const select = {
is_unlocked: true,
admin_modified_date: true,
admin_user: {
select: {
admin_user_id: true,
display_name: true,
},
},
};
const existingReport = await prisma.pay_transparency_report.findUnique({
where: { report_id: reportId },
select: select,
});
if (!existingReport) {
throw new UserInputError('Not found');
Expand All @@ -203,19 +214,26 @@ const adminReportService = {
},
select: {
report_history_id: true,
is_unlocked: true,
admin_modified_date: true,
admin_user: {
select: {
admin_user_id: true,
display_name: true,
},
},
...select,
},
orderBy: {
admin_modified_date: 'desc',
},
});

//the current state of the report is not in the history table (it's in the
//pay_transparency_report table). if the current state was created as a
//result of an admin event, add the current state to the head of the
//adminActionHistory list. the current state doesn't have a report_history_id
//column, so explicitly add it and set it to null.
if (existingReport.admin_modified_date) {
const currentState = {
report_history_id: null,
...existingReport,
};
adminActionHistory.unshift(currentState);
}

return adminActionHistory;
},

Expand Down

0 comments on commit 8088101

Please sign in to comment.