Skip to content

Commit 3462115

Browse files
dws4foster33
andauthored
Filter Button to Retrieve Prior 'X' Amount of Days (#3087)
This PR does the following: 1. Creates a filter icon near the search bar 2. Can filter 'X' days prior based on a full search _(by the search bar)_ by input and 'apply' button. 3. Can reset and show all rows by clicking the 'show all rows' button by showing all rows. 4. On loading, it will default to only 30 days prior. 5. _NEW 8/13/25:_ Fixed the Button Parse Bug (duplicate buttons appearing on same sections of data). _Note: ~~Right now this has not been integration tested~~. ~~Probably needs a rebase as well.~~_ --------- Co-authored-by: foster33 <[email protected]>
1 parent 324c493 commit 3462115

File tree

2 files changed

+116
-24
lines changed

2 files changed

+116
-24
lines changed

microservices/services/dictionary/service/src/main/frontend/src/functions/formatters.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ export function maxSubstring(str: any, colName: any): any {
8080
}
8181

8282
// Defines how the expandability is parsed on the table.
83-
export function buttonParse(col: any, row: any): boolean {
84-
return row.button == 1;
83+
export function buttonParse(row: any): boolean {
84+
return row.button && row.priorDays;
8585
}
8686

8787
// Toggles how the row collapses based on the DOM. Filters visible rows.
@@ -90,7 +90,7 @@ export function toggleVisibility(row: any) {
9090
}
9191

9292
// Set the Visibility in DOM, sorts and filters by lastUpdated, and the respective row to render button.
93-
export function setVisibility(rows: readonly any[]) {
93+
export function setVisibility(rows: readonly any[], priorDays?: any) {
9494
const fieldVisibility: Map<string, Ref<boolean>> = new Map<
9595
string,
9696
Ref<boolean>
@@ -103,7 +103,10 @@ export function setVisibility(rows: readonly any[]) {
103103
const currentRowInternalFieldName: any = row.internalFieldName;
104104
const currentRowDataType: any = row.dataType;
105105

106-
if (currentRowDataType) {
106+
const meetsDateFilter = priorDays === undefined || row.lastUpdated >= getDateCode(priorDays);
107+
row['priorDays'] = meetsDateFilter;
108+
109+
if (currentRowDataType && meetsDateFilter) {
107110
let currentValue = countValues.get(currentRowInternalFieldName) || 0;
108111
countValues.set(currentRowInternalFieldName, ++currentValue);
109112
}
@@ -120,13 +123,14 @@ export function setVisibility(rows: readonly any[]) {
120123
for (const row of rows) {
121124
// Checks to Render button
122125
if (
123-
buttonValues.has(row.internalFieldName) &&
124-
row.lastUpdated == buttonValues.get(row.internalFieldName)
126+
(buttonValues.has(row.internalFieldName) &&
127+
row.lastUpdated == buttonValues.get(row.internalFieldName)) && (countValues.get(row.internalFieldName)! > 1)
125128
) {
126129
row['duplicate'] = 1;
127130
row['button'] = true;
128-
129131
row['dataTypeCount'] = countValues.get(row.internalFieldName) + ' types';
132+
133+
buttonValues.set(row.internalFieldName, -1); // This ensures only one button per internalFieldName (no duplicate buttons)
130134
}
131135
// Checks to Render Collapsible Row - Refreshes on Search
132136
else if (
@@ -164,7 +168,20 @@ export function setVisibility(rows: readonly any[]) {
164168

165169
// Lets the DOM know what is visible and what is not based on setVisibility filters.
166170
export function isVisible(row: any) {
167-
return row.duplicate == 0 || row.isVisible.value;
171+
return (row.duplicate == 0 || row.isVisible.value) && row.priorDays;
172+
}
173+
174+
export function getDateCode(daysPrior = Infinity): number {
175+
if (!isFinite(daysPrior)) {
176+
return 0; // return earliest possible dateCode (match all)
177+
}
178+
179+
const date = new Date();
180+
date.setDate(date.getDate() - daysPrior);
181+
const y = date.getFullYear();
182+
const m = String(date.getMonth() + 1).padStart(2, '0');
183+
const d = String(date.getDate()).padStart(2, '0');
184+
return Number(`${y}${m}${d}000000`);
168185
}
169186

170187
// Filters the URL Search Bar to handle Edge Cases and only queries 1 item.

microservices/services/dictionary/service/src/main/frontend/src/pages/DataDictionary.vue

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
<q-input
7373
borderless
7474
dense
75-
debounce="300"
7675
v-model="changeFilter"
7776
placeholder="Search"
7877
@keydown.enter.prevent="queryTable"
@@ -83,28 +82,101 @@
8382
size="12px"
8483
color="cyan-8"
8584
icon="search"
86-
round
8785
dense
8886
@click="queryTable"
8987
/>
9088
</template>
9189
<template v-slot:header="props">
9290
<q-tr :props="props">
9391
<q-th />
94-
<q-th v-for="col in props.cols" :key="col.name" :props="props">
95-
<div class="tooltip-wrapper">
96-
{{ col.label }}
97-
<q-tooltip class="tooltip-text" anchor="bottom middle" self="top middle" :offset="[0, 5]">
98-
{{ Feature.toolTipGen(col.name) }}
99-
</q-tooltip>
92+
<q-th
93+
v-for="col in props.cols"
94+
:key="col.name"
95+
:props="props"
96+
>
97+
<div class="tooltip-wrapper row items-center no-wrap">
98+
<span class="q-mr-xs">
99+
<span class="cursor-pointer">
100+
{{ col.label }}
101+
<q-tooltip
102+
class="tooltip-text"
103+
anchor="bottom middle"
104+
self="top middle"
105+
:offset="[0, 5]"
106+
>
107+
{{ Feature.toolTipGen(col.name) }}
108+
</q-tooltip>
109+
</span>
110+
</span>
111+
<template v-if="col.name === 'lastUpdated'">
112+
<q-btn
113+
size="7px"
114+
color="cyan-8"
115+
icon="bi-funnel-fill"
116+
style="padding: 2.5px; margin-bottom: 1.5px;"
117+
dense
118+
ref="buttonRef"
119+
>
120+
<q-menu
121+
anchor="bottom right"
122+
self="top right"
123+
:offset="[0, 5]"
124+
>
125+
<q-card
126+
style="max-width: 205px; padding: 5px; box-shadow: 0 0 12px rgba(0, 188, 212, 0.6);"
127+
class="q-pa-sm"
128+
>
129+
<q-card-section class="text-center text-subtitle1" style="font-weight: 550;">
130+
FILTER DAYS
131+
</q-card-section>
132+
<q-separator />
133+
<q-card-section class="q-gutter-sm">
134+
<div class="row items-center q-col-gutter-sm">
135+
<q-input
136+
dense
137+
color="cyan-8"
138+
v-model="search"
139+
placeholder="30"
140+
@keyup.enter="queryTable(search)"
141+
style="width: 50px; margin-left: 15px;"
142+
input-class="text-center"
143+
/>
144+
<q-item-label style="font-weight: 450;"> DAY(S) PRIOR</q-item-label>
145+
</div>
146+
</q-card-section>
147+
<q-separator />
148+
<q-card-section class="q-pt-none">
149+
<div class="row items-center q-gutter-sm" style="margin-top: 15px;">
150+
<q-btn
151+
dense
152+
style="padding: 5px;"
153+
size="12px"
154+
label="Apply"
155+
color="cyan-8"
156+
@click="queryTable(search)"
157+
/>
158+
<q-btn
159+
dense
160+
style="padding: 5px;"
161+
size="12px"
162+
label="Clear Filter"
163+
color="cyan-8"
164+
@click="queryTable()"
165+
/>
166+
</div>
167+
</q-card-section>
168+
</q-card>
169+
</q-menu>
170+
</q-btn>
171+
</template>
100172
</div>
101173
</q-th>
102174
</q-tr>
103175
</template>
104176
<template v-slot:body="props">
105177
<q-tr
106178
:props="props"
107-
v-if="Formatters.buttonParse(props.cols, props.row)"
179+
v-if="Formatters.buttonParse(props.row)"
108180
>
109181
<q-td class="cell-spacing">
110182
<q-btn
@@ -206,6 +278,7 @@ const router = useRouter();
206278
const changeFilter = ref<string>('');
207279
const banner = ref<Banner>();
208280
const system = ref<System>();
281+
const search = ref('');
209282
let rows: QTableProps['rows'] = [];
210283
const paginationFront = ref({
211284
rowsPerPage: 200,
@@ -261,7 +334,10 @@ onMounted(() => {
261334
return b.lastUpdated - a.lastUpdated;
262335
}
263336
});
264-
rows = Formatters.setVisibility(rows);
337+
rows = changeFilter.value
338+
? Formatters.setVisibility(rows) // if searched through URL bar, it removes 30 day filter.
339+
: Formatters.setVisibility(rows, 30); // default at 30 days when loaded without '?search=<val>' query.
340+
265341
loading.value = false;
266342
})
267343
.catch((reason) => {
@@ -333,8 +409,7 @@ function exportTable(this: any) {
333409
}
334410
335411
// Query - Runs through a Search Process as it waits for the user.
336-
async function queryTable(this: any) {
337-
// Wait Until User Enters...
412+
async function queryTable(priorDays?: any) {
338413
await waitUp();
339414
340415
// Handles the URL change to reflect when the user searches.
@@ -353,14 +428,14 @@ async function queryTable(this: any) {
353428
const originalRows = rows;
354429
const triggerRefresh = paginationFront.value.rowsPerPage;
355430
356-
// 3 - Set the Current Rows to Filtered Value
357-
rows = Formatters.setVisibility(rowsToExport);
431+
// 3 - Set filtered rows with visibility flags updated
432+
rows = Formatters.setVisibility(rowsToExport, priorDays);
358433
359-
// 4 - Trigger the Refresh
434+
// 4 - Refresh pagination to trigger table update
360435
paginationFront.value.rowsPerPage = 100;
361436
paginationFront.value.rowsPerPage = triggerRefresh;
362437
363-
// 5 - Restore Original Rows for Next Query
438+
// 5 - Restore original rows for next queries
364439
rows = originalRows;
365440
}
366441

0 commit comments

Comments
 (0)