Allow selecting several comptes/types at once in the filters
Compte and Type were single-value <select> elements. Converted both to <select multiple> -- Vue binds those to an array natively, so ctrl/cmd+click and shift+click just work with no custom JS. Matching semantics are OR within a filter (any of the selected comptes/types) and AND across filters, same as the existing client/year/écarts filters. The URL hash (compte=Maud,Bachir&type=versement,achat) now carries comma-separated lists instead of a single value, so the shareable/ reloadable filtered view still works with multiple selections.
This commit is contained in:
@@ -58,6 +58,15 @@ html.gin--dark-mode #figli-home-app {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Compte/Type filters: <select multiple> so ctrl/shift+click can select
|
||||
several values, rendered as a short scrollable list (size="4") rather
|
||||
than the single-line native default -- needs an explicit width, since
|
||||
a multi-row select sizes to its widest option's natural width
|
||||
otherwise, unlike a single-line select's fixed line box. */
|
||||
#figli-home-app .figli-toolbar select[multiple] {
|
||||
width: 9rem;
|
||||
}
|
||||
|
||||
#figli-home-app .figli-client-input {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
|
||||
@@ -205,9 +205,11 @@
|
||||
return res.json();
|
||||
}
|
||||
|
||||
// URL hash (#compte=Maud&type=versement&annee=2023&ecarts=1&aller=2024)
|
||||
// URL hash (#compte=Maud,Bachir&type=versement,achat&annee=2023&ecarts=1&aller=2024)
|
||||
// makes the filters and "Aller à" shareable/reloadable -- reload the
|
||||
// page or send the link and you land back in the same filtered view.
|
||||
// compte/type can each hold several values (comma-separated) since
|
||||
// both filters are now <select multiple>.
|
||||
// "aller" isn't an ongoing filter (jumpYearValue itself always resets
|
||||
// to '' right after firing) but its target year is worth remembering
|
||||
// for this purpose, so it's tracked separately (lastJumpYear) purely
|
||||
@@ -216,9 +218,9 @@
|
||||
function readHashState() {
|
||||
const params = new URLSearchParams(location.hash.replace(/^#/, ''));
|
||||
return {
|
||||
filterCompte: params.get('compte') || '',
|
||||
filterCompte: params.get('compte') ? params.get('compte').split(',') : [],
|
||||
filterClient: params.get('client') || '',
|
||||
filterType: params.get('type') || '',
|
||||
filterType: params.get('type') ? params.get('type').split(',') : [],
|
||||
filterYear: params.get('annee') || '',
|
||||
onlyErrors: params.get('ecarts') === '1',
|
||||
aller: params.get('aller') || '',
|
||||
@@ -227,9 +229,9 @@
|
||||
|
||||
function buildHashString(state) {
|
||||
const params = new URLSearchParams();
|
||||
if (state.filterCompte) params.set('compte', state.filterCompte);
|
||||
if (state.filterCompte.length) params.set('compte', state.filterCompte.join(','));
|
||||
if (state.filterClient) params.set('client', state.filterClient);
|
||||
if (state.filterType) params.set('type', state.filterType);
|
||||
if (state.filterType.length) params.set('type', state.filterType.join(','));
|
||||
if (state.filterYear) params.set('annee', state.filterYear);
|
||||
if (state.onlyErrors) params.set('ecarts', '1');
|
||||
// Redundant/ambiguous alongside an active "Année" filter -- that
|
||||
@@ -302,9 +304,13 @@
|
||||
allClientsList: [],
|
||||
allYearsList: [],
|
||||
ouvertureEcarts: {},
|
||||
filterCompte: '',
|
||||
// Arrays -- both are native <select multiple>, so ctrl/cmd+click
|
||||
// and shift+click just work (Vue's v-model binds a <select
|
||||
// multiple> to an array natively, no custom handling needed). An
|
||||
// empty array means "tous", same as the single-value '' used to.
|
||||
filterCompte: [],
|
||||
filterClient: '',
|
||||
filterType: '',
|
||||
filterType: [],
|
||||
filterYear: '',
|
||||
jumpYearValue: '',
|
||||
// Not a filter itself (jumpYearValue always resets to '' right
|
||||
@@ -482,9 +488,12 @@
|
||||
},
|
||||
filteredRows() {
|
||||
return this.rows.filter((r) => {
|
||||
if (this.filterCompte && r.parCompte[this.filterCompte] === undefined) return false;
|
||||
// Several selected comptes/types match with OR semantics ("any
|
||||
// of these") -- a line either touches one of the selected
|
||||
// comptes or it doesn't, same idea for type.
|
||||
if (this.filterCompte.length && !this.filterCompte.some((c) => r.parCompte[c] !== undefined)) return false;
|
||||
if (this.filterClient && r.client !== this.filterClient) return false;
|
||||
if (this.filterType && r.type !== this.filterType) return false;
|
||||
if (this.filterType.length && !this.filterType.includes(r.type)) return false;
|
||||
if (this.filterYear && (r.date || '').slice(0, 4) !== this.filterYear) return false;
|
||||
if (this.onlyErrors && !r.hasError) return false;
|
||||
return true;
|
||||
@@ -960,7 +969,7 @@
|
||||
// filter with only a few matches a year could search almost forever
|
||||
// without surfacing more of them.
|
||||
isFiltering() {
|
||||
return !!(this.filterCompte || this.filterClient || this.filterType || this.onlyErrors);
|
||||
return !!(this.filterCompte.length || this.filterClient || this.filterType.length || this.onlyErrors);
|
||||
},
|
||||
// Keeps extending the window (both directions) as long as a filter
|
||||
// leaves too few matching rows to fill the viewport -- otherwise
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
{% verbatim %}
|
||||
|
||||
<label>Compte
|
||||
<select v-model="filterCompte">
|
||||
<option value="">Tous</option>
|
||||
<select v-model="filterCompte" multiple size="4" title="Ctrl/Cmd+clic ou Maj+clic pour plusieurs comptes">
|
||||
<option v-for="c in allComptes" :key="c" :value="c">{{ c }}</option>
|
||||
</select>
|
||||
</label>
|
||||
@@ -34,8 +33,7 @@
|
||||
</label>
|
||||
|
||||
<label>Type
|
||||
<select v-model="filterType">
|
||||
<option value="">Tous</option>
|
||||
<select v-model="filterType" multiple size="4" title="Ctrl/Cmd+clic ou Maj+clic pour plusieurs types">
|
||||
<option v-for="t in allTypes" :key="t.value" :value="t.value">{{ t.label }}</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
Reference in New Issue
Block a user