Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions webapp/cypress/component/CollectionTableTest.cy.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe("CollectionTable Component Tests", () => {
"ID",
"Title",
"Creators",
"", //clear filters
];

cy.get(".p-datatable-column-header-content").should("have.length", headers.length);
Expand Down
1 change: 1 addition & 0 deletions webapp/cypress/component/EquipmentTableTest.cy.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ describe("EquipmentTable Component Tests", () => {
"Date",
"Location",
"Maintainers",
"", // clear filters
];

cy.get(".p-datatable-column-header-content").should("have.length", headers.length);
Expand Down
1 change: 1 addition & 0 deletions webapp/cypress/component/SampleTableTest.cy.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ describe("SampleTable Component Tests", () => {
"", // nblocks
"", // nfiles
"", // last_modified
"", // clear filters
];

cy.get(".p-datatable-column-header-content").should("have.length", headers.length);
Expand Down
1 change: 1 addition & 0 deletions webapp/cypress/component/StartingMaterialTableTest.cy.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ describe("StartingMaterialTable Component Tests", () => {
"", // nblocks
"", //nfiles
"", // last_modified
"", // clear filters
];

cy.get(".p-datatable-column-header-content").should("have.length", headers.length);
Expand Down
99 changes: 80 additions & 19 deletions webapp/src/components/DynamicDataTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,25 @@
/>
</template>
</Column>

<Column
class="clear-filters-column"
:class="{ 'filter-active': hasActiveFilters }"
:style="{ minWidth: '3ch', maxWidth: '3ch' }"
>
<template #header>
<button
data-testid="clear-filters-button"
class="clear-filters-icon-button"
type="button"
:disabled="!hasActiveFilters"
:title="hasActiveFilters ? 'Clear all filters' : 'No active filters'"
@click="handleClearFilters"
>
<i class="pi pi-filter-slash"></i>
</button>
</template>
</Column>
</DataTable>
</div>
<CreateItemModal
Expand Down Expand Up @@ -277,6 +296,17 @@ export default {
availableColumns() {
return this.columns.map((col) => ({ ...col }));
},
hasActiveFilters() {
return Object.entries(this.filters).some(([field, filter]) => {
if (field === "global" || !filter?.constraints) return false;
return filter.constraints.some((constraint) => {
const value = constraint.value;
if (value === null || value === undefined || value === "") return false;
if (Array.isArray(value) && value.length === 0) return false;
return true;
});
});
},
},
created() {
this.$store.commit("setPage", { type: this.dataType, page: 0 });
Expand Down Expand Up @@ -310,30 +340,36 @@ export default {
return itemDate >= startDate && itemDate <= endDate;
});

const filters = { global: { value: null } };
for (const col of this.columns) {
if (!col.filter) continue;

let matchModeName;
if (typeof col.filter.match === "function") {
matchModeName = `${this.dataType}_${col.field}`;
const matchFn = col.filter.match;
FilterService.register(matchModeName, (value, filterValue) => {
const operator = this.filters[col.field]?.operator;
return matchFn(value, filterValue, operator);
});
} else {
matchModeName = col.filter.matchMode || FilterMatchMode.CONTAINS;
}
if (!col.filter || typeof col.filter.match !== "function") continue;

filters[col.field] = {
operator: col.filter.operator || FilterOperator.AND,
constraints: [{ value: null, matchMode: matchModeName }],
};
const matchModeName = `${this.dataType}_${col.field}`;
const matchFn = col.filter.match;
FilterService.register(matchModeName, (value, filterValue) => {
const operator = this.filters[col.field]?.operator;
return matchFn(value, filterValue, operator);
});
}
this.filters = filters;
this.filters = this.getDefaultFilters();
},
methods: {
getDefaultFilters() {
const filters = { global: { value: null } };
for (const col of this.columns) {
if (!col.filter) continue;

const matchModeName =
typeof col.filter.match === "function"
? `${this.dataType}_${col.field}`
: col.filter.matchMode || FilterMatchMode.CONTAINS;

filters[col.field] = {
operator: col.filter.operator || FilterOperator.AND,
constraints: [{ value: null, matchMode: matchModeName }],
};
}
return filters;
},
resolveBodyEvents(column) {
if (!column.body?.events?.length) return {};
return Object.fromEntries(
Expand Down Expand Up @@ -594,6 +630,9 @@ export default {
updateFilters(newFilters) {
this.filters = { ...newFilters };
},
handleClearFilters() {
this.filters = { ...this.getDefaultFilters(), global: this.filters.global };
},
handleResetTable() {
localStorage.removeItem(`datatable-state-${this.dataType}`);

Expand All @@ -610,4 +649,26 @@ export default {
font-size: 0.85em;
font-style: italic;
}

.clear-filters-icon-button {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 0.25rem;
border: none;
background: transparent;
color: inherit;
cursor: pointer;
}

.clear-filters-icon-button:hover {
opacity: 0.7;
}

.clear-filters-icon-button:disabled {
color: #ced4da;
cursor: default;
opacity: 1;
}
</style>
Loading