Bugzilla – Attachment 178667 Details for
Bug 10190
Overdue notice triggers based on item type
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 10190: Modal form improvements
Bug-10190-Modal-form-improvements.patch (text/plain), 36.79 KB, created by
Martin Renvoize (ashimema)
on 2025-02-25 11:58:29 UTC
(
hide
)
Description:
Bug 10190: Modal form improvements
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2025-02-25 11:58:29 UTC
Size:
36.79 KB
patch
obsolete
>From 3b51af679d6c982d914e71862181d8b142eb9ef9 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@ptfs-europe.com> >Date: Fri, 6 Sep 2024 14:20:21 +0100 >Subject: [PATCH] Bug 10190: Modal form improvements > >We now fetch all rules on modal open and the effective rule on context >selection. > >This allows us to compare the specific values of the rule we're >adding/editing to the fallback values present in the all rules set. > >We use the fallback rule values as placeholders in the input boxes to >highlight to the end user what value will be used should they choose to >wipe the input. We also allow wiping inputs and pass 'null' to the API >appropriately. > >Finally, we set a minimum value for delay when adding a new rule to >highlight to the user that the new trigger will be added after existing >triggers. > >Sponsored-by: Glasgow Colleges Library Group <https://library.cityofglasgowcollege.ac.uk> >Signed-off-by: George Harkins <George.Harkins@cityofglasgowcollege.ac.uk> >--- > .../CirculationTriggersFormAdd.vue | 437 ++++++++++++------ > .../CirculationTriggers/TriggersTable.vue | 121 +++-- > 2 files changed, 387 insertions(+), 171 deletions(-) > >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue >index f4a6c4d1482..ff46803dc4a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue >@@ -12,13 +12,19 @@ > <div class="page-section bg-info" v-if="circRules.length"> > <h2>{{ $__("Trigger context") }}</h2> > <TriggerContext :ruleInfo="ruleInfo" /> >- <h2>{{ $__("Existing rules") }}</h2> >- <p>{{ $__("Notice") }} {{ " " + newTriggerNumber - 1 }}</p> >+ <h2 v-if="ruleInfo.numberOfTriggers > 0"> >+ {{ $__("Existing rules") }} >+ </h2> >+ <p v-if="ruleInfo.numberOfTriggers > 0"> >+ {{ $__("Notice") }} {{ " " + newTriggerNumber - 1 }} >+ </p> > <TriggersTable >+ v-if="ruleInfo.numberOfTriggers > 0" > :circRules="circRules" > :triggerNumber="newTriggerNumber - 1" > :modal="true" > :ruleBeingEdited="ruleBeingEdited" >+ :triggerBeingEdited="triggerBeingEdited" > :letters="letters" > /> > </div> >@@ -30,7 +36,7 @@ > > > <v-select > id="library_id" >- v-model="circRuleTrigger.library_id" >+ v-model="newRule.library_id" > label="name" > :reduce="lib => lib.library_id" > :options="libraries" >@@ -39,7 +45,7 @@ > > > <template #search="{ attributes, events }"> > <input >- :required="!circRuleTrigger.library_id" >+ :required="!newRule.library_id" > class="vs__search" > v-bind="attributes" > v-on="events" >@@ -54,7 +60,7 @@ > > > <v-select > id="patron_category_id" >- v-model="circRuleTrigger.patron_category_id" >+ v-model="newRule.patron_category_id" > label="name" > :reduce="cat => cat.patron_category_id" > :options="categories" >@@ -63,9 +69,7 @@ > > > <template #search="{ attributes, events }"> > <input >- :required=" >- !circRuleTrigger.patron_category_id >- " >+ :required="!newRule.patron_category_id" > class="vs__search" > v-bind="attributes" > v-on="events" >@@ -80,7 +84,7 @@ > > > <v-select > id="item_type_id" >- v-model="circRuleTrigger.item_type_id" >+ v-model="newRule.item_type_id" > label="description" > :reduce="type => type.item_type_id" > :options="itemTypes" >@@ -89,9 +93,7 @@ > > > <template #search="{ attributes, events }"> > <input >- :required=" >- !circRuleTrigger.item_type_id >- " >+ :required="!newRule.item_type_id" > class="vs__search" > v-bind="attributes" > v-on="events" >@@ -106,8 +108,10 @@ > </label> > <input > id="overdue_delay" >- v-model="circRuleTrigger.delay" >+ v-model="newRule.delay" > type="number" >+ :placeholder="fallbackRule.delay" >+ :min="minDelay" > /> > </li> > <li> >@@ -116,7 +120,7 @@ > > > <v-select > id="letter_code" >- v-model="circRuleTrigger.notice" >+ v-model="newRule.notice" > label="name" > :reduce="type => type.code" > :options="letters" >@@ -126,17 +130,31 @@ > class="vs__search" > v-bind="attributes" > v-on="events" >+ :placeholder=" >+ letters.find( >+ letter => >+ letter.code === >+ fallbackRule.notice >+ )?.name || fallbackRule.notice >+ " > /> > </template> > </v-select> > </li> >- <li> >+ <li >+ v-if=" >+ newRule.notice !== '' || >+ ((newRule.notice === null || >+ newRule.notice === undefined) && >+ fallbackRule.notice !== '') >+ " >+ > > <label for="mtt" > >{{ $__("Transport type(s)") }}:</label > > > <v-select > id="mtt" >- v-model="circRuleTrigger.mtt" >+ v-model="newRule.mtt" > label="name" > :reduce="type => type.code" > :options="mtts" >@@ -147,6 +165,13 @@ > class="vs__search" > v-bind="attributes" > v-on="events" >+ :placeholder=" >+ newRule.mtt === null || >+ newRule.mtt === undefined || >+ newRule.mtt.length === 0 >+ ? fallbackRule.mtt >+ : '' >+ " > /> > </template> > </v-select> >@@ -155,14 +180,38 @@ > <label for="restricts" > >{{ $__("Restricts checkouts") }}:</label > > >- <input >- type="checkbox" >- id="restricts" >- :checked="false" >- true-value="1" >- false-value="0" >- v-model="circRuleTrigger.restrict" >- /> >+ <div> >+ <input >+ type="radio" >+ id="restricts-yes" >+ v-model="newRule.restrict" >+ :value="1" >+ /> >+ {{ $__("Yes") }} >+ >+ <input >+ type="radio" >+ id="restricts-no" >+ v-model="newRule.restrict" >+ :value="0" >+ /> >+ {{ $__("No") }} >+ >+ <input >+ type="radio" >+ id="restricts-fallback" >+ v-model="newRule.restrict" >+ :value="null" >+ /> >+ {{ $__("Fallback to default") }} >+ <span v-if="fallbackRule.restricts !== null"> >+ ({{ >+ fallbackRule.restricts === 1 >+ ? $__("Yes") >+ : $__("No") >+ }}) >+ </span> >+ </div> > </li> > </ol> > </fieldset> >@@ -209,23 +258,23 @@ export default { > categories: null, > itemTypes: null, > circRules: [], >- circRuleTrigger: { >+ newRule: { > item_type_id: "*", > library_id: "*", > patron_category_id: "*", > delay: null, > notice: null, > mtt: null, >- restrict: "0", >+ restrict: null, > }, >- effectiveRule: { >+ fallbackRule: { > item_type_id: "*", > library_id: "*", > patron_category_id: "*", > delay: null, > notice: null, > mtt: null, >- restrict: "0", >+ restrict: null, > }, > newTriggerNumber: 1, > mtts: [ >@@ -239,68 +288,62 @@ export default { > fine: null, > chargeperiod: null, > lengthunit: null, >+ numberOfTriggers: null, > }, > editMode: false, > ruleBeingEdited: null, >+ triggerBeingEdited: null, > }; > }, > beforeRouteEnter(to, from, next) { > next(vm => { > vm.getLibraries().then(() => > vm.getCategories().then(() => >- vm.getItemTypes().then(() => { >- const { query } = to; >- vm.checkForExistingRules(query).then( >- () => (vm.initialized = true) >- ); >- }) >+ vm.getItemTypes().then(() => >+ vm.getCircRules().then(() => { >+ const { query } = to; >+ vm.checkForExistingRules(query).then( >+ () => (vm.initialized = true) >+ ); >+ }) >+ ) > ) > ); > }); > }, >+ computed: { >+ minDelay() { >+ const lastRule = this.circRules[this.newTriggerNumber - 2]; >+ return lastRule >+ ? parseInt( >+ lastRule[`overdue_${this.newTriggerNumber - 1}_delay`] >+ ) + 1 >+ : 0; >+ }, >+ }, > methods: { > async addCircRule(e) { > e.preventDefault(); > > const context = { >- library_id: this.circRuleTrigger.library_id || "*", >- item_type_id: this.circRuleTrigger.item_type_id || "*", >- patron_category_id: >- this.circRuleTrigger.patron_category_id || "*", >+ library_id: this.newRule.library_id || "*", >+ item_type_id: this.newRule.item_type_id || "*", >+ patron_category_id: this.newRule.patron_category_id || "*", > }; > >- const delay = >- this.circRuleTrigger.delay === this.effectiveRule.delay >- ? null >- : this.circRuleTrigger.delay; >- const notice = >- this.circRuleTrigger.notice === this.effectiveRule.notice >- ? null >- : this.circRuleTrigger.notice; >- const restrict = >- this.circRuleTrigger.restrict === this.effectiveRule.restrict >- ? null >- : this.circRuleTrigger.restrict; >- const mtt = >- this.circRuleTrigger.mtt.join(",") === >- this.effectiveRule.mtt.join(",") >- ? null >- : this.circRuleTrigger.mtt.join(","); >- > const circRule = { > context, > }; >- circRule[`overdue_${this.newTriggerNumber}_delay`] = delay; >- circRule[`overdue_${this.newTriggerNumber}_notice`] = notice; >- circRule[`overdue_${this.newTriggerNumber}_restrict`] = restrict; >- circRule[`overdue_${this.newTriggerNumber}_mtt`] = mtt; >- >- if (this.editMode) { >- Object.keys(circRule).forEach(key => { >- if (key === "context") return; >- if (!circRule[key]) delete circRule[key]; >- }); >- } >+ circRule[`overdue_${this.newTriggerNumber}_delay`] = >+ this.newRule.delay; >+ circRule[`overdue_${this.newTriggerNumber}_notice`] = >+ this.newRule.notice; >+ circRule[`overdue_${this.newTriggerNumber}_restrict`] = >+ this.newRule.restrict; >+ circRule[`overdue_${this.newTriggerNumber}_mtt`] = >+ this.newRule.mtt && this.newRule.mtt.length >+ ? this.newRule.mtt.join(",") >+ : null; > > const client = APIClient.circRule; > await client.circRules.update(circRule).then( >@@ -354,6 +397,19 @@ export default { > error => {} > ); > }, >+ async getCircRules() { >+ const client = APIClient.circRule; >+ await client.circRules.getAll({}, { effective: false }).then( >+ rules => { >+ const { rulesPerTrigger } = >+ this.splitCircRulesByTriggerNumber(rules); >+ this.circRules = rulesPerTrigger.length >+ ? rulesPerTrigger >+ : rules; >+ }, >+ error => {} >+ ); >+ }, > async handleContextChange() { > await this.checkForExistingRules(); > }, >@@ -362,95 +418,165 @@ export default { > const editMode = routeParams && routeParams.triggerNumber; > if (editMode) { > this.editMode = editMode; >- this.ruleBeingEdited = routeParams.triggerNumber; >+ this.triggerBeingEdited = routeParams.triggerNumber; > } > const library_id = > routeParams && routeParams.library_id > ? routeParams.library_id >- : this.circRuleTrigger.library_id || "*"; >+ : this.newRule.library_id || "*"; > const item_type_id = > routeParams && routeParams.item_type_id > ? routeParams.item_type_id >- : this.circRuleTrigger.item_type_id || "*"; >+ : this.newRule.item_type_id || "*"; > const patron_category_id = > routeParams && routeParams.patron_category_id > ? routeParams.patron_category_id >- : this.circRuleTrigger.patron_category_id || "*"; >+ : this.newRule.patron_category_id || "*"; > const params = { > library_id, > item_type_id, > patron_category_id, > }; > >+ // Fetch effective ruleset for context > const client = APIClient.circRule; > await client.circRules.getAll({}, params).then( > rules => { >- if (rules.length === 0) { >- this.newTriggerNumber = 1; >- } else { >- const { rulesPerTrigger } = >- this.splitCircRulesByTriggerNumber(rules); >- this.circRules = rulesPerTrigger; >- this.ruleInfo = { >- issuelength: rules[0].issuelength, >- decreaseloanholds: rules[0].decreaseloanholds, >- fine: rules[0].fine, >- chargeperiod: rules[0].chargeperiod, >- lengthunit: rules[0].lengthunit, >- }; >- } >+ this.ruleBeingEdited = rules[0]; >+ this.ruleBeingEdited.context = params; >+ const regex = /overdue_(\d+)_delay/g; >+ const numberOfTriggers = Object.keys(rules[0]).filter( >+ key => regex.test(key) && rules[0][key] !== null >+ ).length; >+ const splitRules = this.filterCircRulesByContext( >+ this.ruleBeingEdited >+ ); >+ this.newTriggerNumber = editMode >+ ? routeParams.triggerNumber >+ : numberOfTriggers + 1; >+ this.assignTriggerValues( >+ splitRules, >+ this.newTriggerNumber, >+ params >+ ); >+ >+ this.ruleInfo = { >+ issuelength: rules[0].issuelength, >+ decreaseloanholds: rules[0].decreaseloanholds, >+ fine: rules[0].fine, >+ chargeperiod: rules[0].chargeperiod, >+ lengthunit: rules[0].lengthunit, >+ numberOfTriggers: numberOfTriggers, >+ }; > }, > error => {} > ); >+ }, >+ filterCircRulesByContext(effectiveRule) { >+ const context = effectiveRule.context; > >- params.effective = false; >- await client.circRules.getAll({}, params).then( >- rules => { >- if (rules.length === 0) { >- this.newTriggerNumber = 1; >+ // Filter rules that match the context >+ let contextRules = this.circRules.filter(rule => { >+ return Object.keys(context).every(key => { >+ return context[key] === rule.context[key]; >+ }); >+ }); > >- this.assignTriggerValues( >- "circRuleTrigger", >- this.circRules, >- this.newTriggerNumber, >- params >- ); >- this.assignTriggerValues( >- "effectiveRule", >- this.circRules, >- this.newTriggerNumber, >- params >- ); >- } else { >- const regex = /overdue_(\d+)_delay/g; >- const numberOfTriggers = Object.keys(rules[0]).filter( >- key => regex.test(key) && rules[0][key] !== null >- ).length; >- this.newTriggerNumber = editMode >- ? routeParams.triggerNumber >- : numberOfTriggers + 1; >- const { rulesPerTrigger } = >- this.splitCircRulesByTriggerNumber(rules); >- const triggerToDisplay = editMode >- ? routeParams.triggerNumber >- : numberOfTriggers; >- this.assignTriggerValues( >- "circRuleTrigger", >- rulesPerTrigger, >- triggerToDisplay >- ); >- this.assignTriggerValues( >- "effectiveRule", >- rulesPerTrigger, >- triggerToDisplay >- ); >- } >- }, >- error => {} >- ); >+ // Calculate the number of 'overdue_X_' triggers in the effectiveRule >+ const regex = /overdue_(\d+)_delay/g; >+ const numberOfTriggers = Object.keys(effectiveRule).filter( >+ key => regex.test(key) && effectiveRule[key] !== null >+ ).length; >+ >+ // Ensure there is one contextRule per 'X' from 1 to numberOfTriggers >+ for (let i = 1; i <= numberOfTriggers; i++) { >+ // Check if there's already a rule for overdue_X_ in contextRules >+ const matchingRule = contextRules.find( >+ rule => rule[`overdue_${i}_delay`] !== undefined >+ ); >+ >+ if (!matchingRule) { >+ // Create a new rule with the same context and null overdue_X_* keys >+ const placeholderRule = { >+ context: { ...context }, // Clone the context >+ [`overdue_${i}_delay`]: null, >+ [`overdue_${i}_notice`]: null, >+ [`overdue_${i}_mtt`]: null, >+ [`overdue_${i}_restrict`]: null, >+ }; >+ >+ // Add the new rule to contextRules >+ contextRules.push(placeholderRule); >+ } >+ } >+ >+ // Sort contextRules by the 'X' value in 'overdue_X_delay' >+ contextRules.sort((a, b) => { >+ const getX = rule => { >+ const match = Object.keys(rule).find(key => >+ regex.test(key) >+ ); >+ return match ? parseInt(match.match(/\d+/)[0], 10) : 0; >+ }; >+ >+ return getX(a) - getX(b); >+ }); >+ >+ return contextRules; > }, >- assignTriggerValues(prop, rules, triggerNumber, context = null) { >- this[prop] = { >+ findFallbackRule(currentContext, key) { >+ // Filter rules to only those with non-null values for the specified key and not the current context >+ const relevantRules = this.circRules.filter(rule => { >+ return ( >+ Object.keys(currentContext).some( >+ key => currentContext[key] !== rule.context[key] >+ ) && >+ rule[key] !== null && >+ rule[key] !== undefined >+ ); >+ }); >+ >+ // Function to calculate specificity score >+ const getSpecificityScore = ruleContext => { >+ let score = 0; >+ if ( >+ ruleContext.library_id !== "*" && >+ ruleContext.library_id === currentContext.library_id >+ ) >+ score += 4; >+ if ( >+ ruleContext.patron_category_id !== "*" && >+ ruleContext.patron_category_id === >+ currentContext.patron_category_id >+ ) >+ score += 2; >+ if ( >+ ruleContext.item_type_id !== "*" && >+ ruleContext.item_type_id === currentContext.item_type_id >+ ) >+ score += 1; >+ return score; >+ }; >+ >+ // Sort the rules based on specificity score, descending >+ const sortedRules = relevantRules.sort((a, b) => { >+ return ( >+ getSpecificityScore(b.context) - >+ getSpecificityScore(a.context) >+ ); >+ }); >+ >+ // If no rule found, return null >+ if (sortedRules.length === 0) { >+ return null; >+ } >+ >+ // Get the value from the most specific rule >+ const bestRule = sortedRules[0]; >+ return bestRule[key]; >+ }, >+ assignTriggerValues(rules, triggerNumber, context = null) { >+ this.newRule = { > item_type_id: context > ? context.item_type_id > : rules[triggerNumber - 1].context.item_type_id || "*", >@@ -461,21 +587,44 @@ export default { > ? context.patron_category_id > : rules[triggerNumber - 1].context.patron_category_id || > "*", >- delay: rules[triggerNumber - 1][ >+ delay: rules[triggerNumber - 1] >+ ? rules[triggerNumber - 1][`overdue_${triggerNumber}_delay`] >+ : null, >+ notice: rules[triggerNumber - 1] >+ ? rules[triggerNumber - 1][ >+ `overdue_${triggerNumber}_notice` >+ ] >+ : null, >+ mtt: rules[triggerNumber - 1] >+ ? rules[triggerNumber - 1][`overdue_${triggerNumber}_mtt`] >+ ? rules[triggerNumber - 1][ >+ `overdue_${triggerNumber}_mtt` >+ ].split(",") >+ : [] >+ : null, >+ restrict: rules[triggerNumber - 1] >+ ? rules[triggerNumber - 1][ >+ `overdue_${triggerNumber}_restrict` >+ ] >+ : null, >+ }; >+ this.fallbackRule = { >+ delay: this.findFallbackRule( >+ context, > `overdue_${triggerNumber}_delay` >- ], >- notice: rules[triggerNumber - 1][ >+ ), >+ notice: this.findFallbackRule( >+ context, > `overdue_${triggerNumber}_notice` >- ], >- mtt: rules[triggerNumber - 1][`overdue_${triggerNumber}_mtt`] >- ? rules[triggerNumber - 1][ >- `overdue_${triggerNumber}_mtt` >- ].split(",") >- : [], >- restrict: >- rules[triggerNumber - 1][ >- `overdue_${triggerNumber}_restrict` >- ], >+ ), >+ mtt: this.findFallbackRule( >+ context, >+ `overdue_${triggerNumber}_mtt` >+ ), >+ restrict: this.findFallbackRule( >+ context, >+ `overdue_${triggerNumber}_restrict` >+ ), > }; > }, > }, >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue >index 47ba8675c00..02b8a16cc55 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue >@@ -42,13 +42,13 @@ > </thead> > <tbody> > <tr >- v-for="(rule, i) in filterCircRulesByTabNumber( >- triggerNumber >- )" >+ v-for="(rule, i) in modal >+ ? filterCircRulesByContext(ruleBeingEdited) >+ : filterCircRulesByTabNumber(triggerNumber)" > v-bind:key="'rule' + i" > :class="{ > selected_rule: >- modal && i + 1 === parseInt(ruleBeingEdited), >+ modal && i + 1 === parseInt(triggerBeingEdited), > }" > > > <td v-if="!modal"> >@@ -125,13 +125,18 @@ > }" > > > {{ >- handleTransport( >- findEffectiveRule( >- rule, >- `overdue_${modal ? i + 1 : triggerNumber}_mtt` >- ).value, >- "email" >- ) >+ findEffectiveRule( >+ rule, >+ `overdue_${modal ? i + 1 : triggerNumber}_notice` >+ ).value !== "" >+ ? handleTransport( >+ findEffectiveRule( >+ rule, >+ `overdue_${modal ? i + 1 : triggerNumber}_mtt` >+ ).value, >+ "email" >+ ) >+ : "" > }} > </span> > </td> >@@ -147,13 +152,18 @@ > }" > > > {{ >- handleTransport( >- findEffectiveRule( >- rule, >- `overdue_${modal ? i + 1 : triggerNumber}_mtt` >- ).value, >- "print" >- ) >+ findEffectiveRule( >+ rule, >+ `overdue_${modal ? i + 1 : triggerNumber}_notice` >+ ).value !== "" >+ ? handleTransport( >+ findEffectiveRule( >+ rule, >+ `overdue_${modal ? i + 1 : triggerNumber}_mtt` >+ ).value, >+ "print" >+ ) >+ : "" > }} > </span> > </td> >@@ -169,13 +179,18 @@ > }" > > > {{ >- handleTransport( >- findEffectiveRule( >- rule, >- `overdue_${modal ? i + 1 : triggerNumber}_mtt` >- ).value, >- "sms" >- ) >+ findEffectiveRule( >+ rule, >+ `overdue_${modal ? i + 1 : triggerNumber}_notice` >+ ).value !== "" >+ ? handleTransport( >+ findEffectiveRule( >+ rule, >+ `overdue_${modal ? i + 1 : triggerNumber}_mtt` >+ ).value, >+ "sms" >+ ) >+ : "" > }} > </span> > </td> >@@ -233,6 +248,7 @@ export default { > "triggerNumber", > "modal", > "ruleBeingEdited", >+ "triggerBeingEdited", > "categories", > "itemTypes", > "letters", >@@ -252,8 +268,59 @@ export default { > handleRestrictions(value) { > return value === "1" ? this.$__("Yes") : this.$__("No"); > }, >+ filterCircRulesByContext(effectiveRule) { >+ const context = effectiveRule.context; >+ >+ // Filter rules that match the context >+ let contextRules = this.circRules.filter(rule => { >+ return Object.keys(context).every(key => { >+ return context[key] === rule.context[key]; >+ }); >+ }); >+ >+ // Calculate the number of 'overdue_X_' triggers in the effectiveRule >+ const regex = /overdue_(\d+)_delay/g; >+ const numberOfTriggers = Object.keys(effectiveRule).filter( >+ key => regex.test(key) && effectiveRule[key] !== null >+ ).length; >+ >+ // Ensure there is one contextRule per 'X' from 1 to numberOfTriggers >+ for (let i = 1; i <= numberOfTriggers; i++) { >+ // Check if there's already a rule for overdue_X_ in contextRules >+ const matchingRule = contextRules.find( >+ rule => rule[`overdue_${i}_delay`] !== undefined >+ ); >+ >+ if (!matchingRule) { >+ // Create a new rule with the same context and null overdue_X_* keys >+ const newRule = { >+ context: { ...context }, // Clone the context >+ [`overdue_${i}_delay`]: null, >+ [`overdue_${i}_notice`]: null, >+ [`overdue_${i}_mtt`]: null, >+ [`overdue_${i}_restrict`]: null, >+ }; >+ >+ // Add the new rule to contextRules >+ contextRules.push(newRule); >+ } >+ } >+ >+ // Sort contextRules by the 'X' value in 'overdue_X_delay' >+ contextRules.sort((a, b) => { >+ const getX = rule => { >+ const match = Object.keys(rule).find(key => >+ regex.test(key) >+ ); >+ return match ? parseInt(match.match(/\d+/)[0], 10) : 0; >+ }; >+ >+ return getX(a) - getX(b); >+ }); >+ >+ return contextRules; >+ }, > filterCircRulesByTabNumber(number) { >- if (this.modal) return this.circRules; > return this.circRules.filter( > rule => > rule.triggerNumber === number && >@@ -272,7 +339,7 @@ export default { > if (ruleSet[key] === null) { > // Filter rules to only those with non-null values for the specified key > const relevantRules = this.circRules.filter( >- rule => rule[key] !== null >+ rule => rule[key] !== null && rule[key] !== undefined > ); > > // Function to calculate specificity score >-- >2.48.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 10190
:
170357
|
170358
|
170359
|
170360
|
170361
|
170362
|
170363
|
170364
|
170365
|
170366
|
170367
|
170368
|
170369
|
170370
|
170371
|
170372
|
170373
|
170374
|
170375
|
170376
|
170380
|
170449
|
171727
|
171728
|
171729
|
171730
|
171731
|
171732
|
171733
|
171734
|
171735
|
171736
|
171737
|
171738
|
171739
|
171740
|
171741
|
171742
|
171743
|
171744
|
171745
|
171746
|
171747
|
171748
|
171749
|
171750
|
171751
|
171752
|
171753
|
171754
|
171755
|
172588
|
172589
|
172590
|
172591
|
172592
|
172593
|
172594
|
172595
|
172596
|
172597
|
172598
|
172599
|
172600
|
172601
|
172602
|
172603
|
172604
|
172605
|
172606
|
172607
|
172608
|
172609
|
172612
|
172614
|
172617
|
172619
|
172621
|
172622
|
172623
|
172624
|
172625
|
172626
|
172630
|
172631
|
172632
|
172633
|
172634
|
172635
|
172636
|
172637
|
172638
|
172639
|
172640
|
172641
|
172642
|
172643
|
172644
|
172645
|
172646
|
172647
|
172648
|
172649
|
172650
|
172651
|
172652
|
172653
|
172654
|
172655
|
172656
|
172657
|
172658
|
172659
|
172660
|
172661
|
172662
|
172663
|
178643
|
178644
|
178645
|
178646
|
178647
|
178648
|
178649
|
178650
|
178651
|
178652
|
178653
|
178654
|
178655
|
178656
|
178657
|
178658
|
178659
|
178660
|
178661
|
178662
|
178663
|
178664
|
178665
|
178666
| 178667 |
178668
|
178669
|
178670
|
178671
|
178672
|
178673
|
178674
|
178675