View | Details | Raw Unified | Return to bug 10190
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue (-90 / +329 lines)
Lines 12-19 Link Here
12
                <div class="page-section bg-info" v-if="circRules.length">
12
                <div class="page-section bg-info" v-if="circRules.length">
13
                    <h2>{{ $__("Trigger context") }}</h2>
13
                    <h2>{{ $__("Trigger context") }}</h2>
14
                    <TriggerContext :ruleInfo="ruleInfo" />
14
                    <TriggerContext :ruleInfo="ruleInfo" />
15
                    <h2 v-if="ruleInfo.numberOfTriggers > 0">{{ $__("Existing rules") }}</h2>
15
                    <h2 v-if="ruleInfo.numberOfTriggers > 0">
16
                    <p v-if="ruleInfo.numberOfTriggers > 0">{{ $__("Notice") }} {{ " " + newTriggerNumber - 1 }}</p>
16
                        {{ $__("Existing rules") }}
17
                    </h2>
18
                    <p v-if="ruleInfo.numberOfTriggers > 0">
19
                        {{ $__("Notice") }} {{ " " + newTriggerNumber - 1 }}
20
                    </p>
17
                    <TriggersTable
21
                    <TriggersTable
18
                        v-if="ruleInfo.numberOfTriggers > 0"
22
                        v-if="ruleInfo.numberOfTriggers > 0"
19
                        :circRules="circRules"
23
                        :circRules="circRules"
Lines 65-73 Link Here
65
                            >
69
                            >
66
                                <template #search="{ attributes, events }">
70
                                <template #search="{ attributes, events }">
67
                                    <input
71
                                    <input
68
                                        :required="
72
                                        :required="!newRule.patron_category_id"
69
                                            !newRule.patron_category_id
70
                                        "
71
                                        class="vs__search"
73
                                        class="vs__search"
72
                                        v-bind="attributes"
74
                                        v-bind="attributes"
73
                                        v-on="events"
75
                                        v-on="events"
Lines 91-99 Link Here
91
                            >
93
                            >
92
                                <template #search="{ attributes, events }">
94
                                <template #search="{ attributes, events }">
93
                                    <input
95
                                    <input
94
                                        :required="
96
                                        :required="!newRule.item_type_id"
95
                                            !newRule.item_type_id
96
                                        "
97
                                        class="vs__search"
97
                                        class="vs__search"
98
                                        v-bind="attributes"
98
                                        v-bind="attributes"
99
                                        v-on="events"
99
                                        v-on="events"
Lines 106-118 Link Here
106
                            <label for="overdue_delay"
106
                            <label for="overdue_delay"
107
                                >{{ $__("Delay") }}:
107
                                >{{ $__("Delay") }}:
108
                            </label>
108
                            </label>
109
                            <input
109
                            <div class="numeric-input-wrapper">
110
                                id="overdue_delay"
110
                                <div class="input-with-clear">
111
                                v-model="newRule.delay"
111
                                    <input
112
                                type="number"
112
                                        id="overdue_delay"
113
                                :placeholder="fallbackRule.delay"
113
                                        v-model="newRule.delay"
114
                                :min="minDelay"
114
                                        type="number"
115
                            />
115
                                        :placeholder="fallbackRule.delay"
116
                                        :min="minDelay"
117
                                        :max="maxDelay"
118
                                        class="numeric-input"
119
                                    />
120
                                    <button
121
                                        v-if="
122
                                            newRule.delay !== null &&
123
                                            newRule.delay !== undefined
124
                                        "
125
                                        type="button"
126
                                        class="clear-btn"
127
                                        @click="newRule.delay = null"
128
                                    >
129
                                        <svg
130
                                            xmlns="http://www.w3.org/2000/svg"
131
                                            width="10"
132
                                            height="10"
133
                                        >
134
                                            <path
135
                                                d="M6.895455 5l2.842897-2.842898c.348864-.348863.348864-.914488 0-1.263636L9.106534.261648c-.348864-.348864-.914489-.348864-1.263636 0L5 3.104545 2.157102.261648c-.348863-.348864-.914488-.348864-1.263636 0L.261648.893466c-.348864.348864-.348864.914489 0 1.263636L3.104545 5 .261648 7.842898c-.348864.348863-.348864.914488 0 1.263636l.631818.631818c.348864.348864.914773.348864 1.263636 0L5 6.895455l2.842898 2.842897c.348863.348864.914772.348864 1.263636 0l.631818-.631818c.348864-.348864.348864-.914489 0-1.263636L6.895455 5z"
136
                                            ></path>
137
                                        </svg>
138
                                    </button>
139
                                    <div class="chevron-buttons">
140
                                        <button
141
                                            type="button"
142
                                            class="increment-btn"
143
                                            @click="incrementDelay"
144
                                        >
145
146
                                        </button>
147
                                        <button
148
                                            type="button"
149
                                            class="decrement-btn"
150
                                            @click="decrementDelay"
151
                                        >
152
153
                                        </button>
154
                                    </div>
155
                                </div>
156
                            </div>
116
                        </li>
157
                        </li>
117
                        <li>
158
                        <li>
118
                            <label for="letter_code"
159
                            <label for="letter_code"
Lines 130-141 Link Here
130
                                        class="vs__search"
171
                                        class="vs__search"
131
                                        v-bind="attributes"
172
                                        v-bind="attributes"
132
                                        v-on="events"
173
                                        v-on="events"
133
                                        :placeholder="letters.find(letter => letter.code === fallbackRule.notice)?.name || fallbackRule.notice"
174
                                        :placeholder="
175
                                            newRule.notice === null ||
176
                                            newRule.notice === undefined
177
                                                ? letters.find(
178
                                                      letter =>
179
                                                          letter.code ===
180
                                                          fallbackRule.notice
181
                                                  )?.name || fallbackRule.notice
182
                                                : ''
183
                                        "
134
                                    />
184
                                    />
135
                                </template>
185
                                </template>
136
                            </v-select>
186
                            </v-select>
137
                        </li>
187
                        </li>
138
                        <li v-if="newRule.notice !== '' || (( newRule.notice === null || newRule.notice === undefined ) && fallbackRule.notice !== '' )">
188
                        <li
189
                            v-if="
190
                                newRule.notice !== '' ||
191
                                ((newRule.notice === null ||
192
                                    newRule.notice === undefined) &&
193
                                    fallbackRule.notice !== '')
194
                            "
195
                        >
139
                            <label for="mtt"
196
                            <label for="mtt"
140
                                >{{ $__("Transport type(s)") }}:</label
197
                                >{{ $__("Transport type(s)") }}:</label
141
                            >
198
                            >
Lines 152-164 Link Here
152
                                        class="vs__search"
209
                                        class="vs__search"
153
                                        v-bind="attributes"
210
                                        v-bind="attributes"
154
                                        v-on="events"
211
                                        v-on="events"
155
                                        :placeholder="newRule.mtt === null || newRule.mtt === undefined || newRule.mtt.length === 0 ? fallbackRule.mtt : ''"
212
                                        :placeholder="
213
                                            newRule.mtt === null ||
214
                                            newRule.mtt === undefined ||
215
                                            newRule.mtt.length === 0
216
                                                ? fallbackRule.mtt
217
                                                : ''
218
                                        "
156
                                    />
219
                                    />
157
                                </template>
220
                                </template>
158
                            </v-select>
221
                            </v-select>
159
                        </li>
222
                        </li>
160
                        <li>
223
                        <li>
161
                            <label for="restricts">{{ $__("Restricts checkouts") }}:</label>
224
                            <label for="restricts"
225
                                >{{ $__("Restricts checkouts") }}:</label
226
                            >
162
                            <div>
227
                            <div>
163
                                <input
228
                                <input
164
                                    type="radio"
229
                                    type="radio"
Lines 167-173 Link Here
167
                                    :value="1"
232
                                    :value="1"
168
                                />
233
                                />
169
                                {{ $__("Yes") }}
234
                                {{ $__("Yes") }}
170
                    
235
171
                                <input
236
                                <input
172
                                    type="radio"
237
                                    type="radio"
173
                                    id="restricts-no"
238
                                    id="restricts-no"
Lines 175-181 Link Here
175
                                    :value="0"
240
                                    :value="0"
176
                                />
241
                                />
177
                                {{ $__("No") }}
242
                                {{ $__("No") }}
178
                    
243
179
                                <input
244
                                <input
180
                                    type="radio"
245
                                    type="radio"
181
                                    id="restricts-fallback"
246
                                    id="restricts-fallback"
Lines 184-190 Link Here
184
                                />
249
                                />
185
                                {{ $__("Fallback to default") }}
250
                                {{ $__("Fallback to default") }}
186
                                <span v-if="fallbackRule.restricts !== null">
251
                                <span v-if="fallbackRule.restricts !== null">
187
                                    ({{ fallbackRule.restricts === 1 ? $__("Yes") : $__("No") }})
252
                                    ({{
253
                                        fallbackRule.restricts === 1
254
                                            ? $__("Yes")
255
                                            : $__("No")
256
                                    }})
188
                                </span>
257
                                </span>
189
                            </div>
258
                            </div>
190
                        </li>
259
                        </li>
Lines 268-273 export default { Link Here
268
            editMode: false,
337
            editMode: false,
269
            ruleBeingEdited: null,
338
            ruleBeingEdited: null,
270
            triggerBeingEdited: null,
339
            triggerBeingEdited: null,
340
            minDelay: 0,
341
            maxDelay: Infinity,
271
        }
342
        }
272
    },
343
    },
273
    beforeRouteEnter(to, from, next) {
344
    beforeRouteEnter(to, from, next) {
Lines 286-297 export default { Link Here
286
            )
357
            )
287
        })
358
        })
288
    },
359
    },
289
    computed: {
290
        minDelay() {
291
            const lastRule = this.circRules[this.newTriggerNumber - 2];
292
            return lastRule ? parseInt(lastRule[`overdue_${this.newTriggerNumber - 1}_delay`]) + 1 : 0;
293
        }
294
    },
295
    methods: {
360
    methods: {
296
        async addCircRule(e) {
361
        async addCircRule(e) {
297
            e.preventDefault()
362
            e.preventDefault()
Lines 299-315 export default { Link Here
299
            const context = {
364
            const context = {
300
                library_id: this.newRule.library_id || "*",
365
                library_id: this.newRule.library_id || "*",
301
                item_type_id: this.newRule.item_type_id || "*",
366
                item_type_id: this.newRule.item_type_id || "*",
302
                patron_category_id:
367
                patron_category_id: this.newRule.patron_category_id || "*",
303
                    this.newRule.patron_category_id || "*",
304
            }
368
            }
305
369
306
            const circRule = {
370
            const circRule = {
307
                context,
371
                context,
308
            }
372
            }
309
            circRule[`overdue_${this.newTriggerNumber}_delay`] = this.newRule.delay
373
            circRule[`overdue_${this.newTriggerNumber}_delay`] =
310
            circRule[`overdue_${this.newTriggerNumber}_notice`] = this.newRule.notice
374
                this.newRule.delay
311
            circRule[`overdue_${this.newTriggerNumber}_restrict`] = this.newRule.restrict
375
            circRule[`overdue_${this.newTriggerNumber}_notice`] =
312
            circRule[`overdue_${this.newTriggerNumber}_mtt`] = this.newRule.mtt && this.newRule.mtt.length ? this.newRule.mtt.join(",") : null
376
                this.newRule.notice
377
            circRule[`overdue_${this.newTriggerNumber}_restrict`] =
378
                this.newRule.restrict
379
            circRule[`overdue_${this.newTriggerNumber}_mtt`] =
380
                this.newRule.mtt && this.newRule.mtt.length
381
                    ? this.newRule.mtt.join(",")
382
                    : null
313
383
314
            const client = APIClient.circRule
384
            const client = APIClient.circRule
315
            await client.circRules.update(circRule).then(
385
            await client.circRules.update(circRule).then(
Lines 367-377 export default { Link Here
367
            const client = APIClient.circRule
437
            const client = APIClient.circRule
368
            await client.circRules.getAll({}, { effective: false }).then(
438
            await client.circRules.getAll({}, { effective: false }).then(
369
                rules => {
439
                rules => {
370
                    const { rulesPerTrigger } = this.splitCircRulesByTriggerNumber(rules)
440
                    const { rulesPerTrigger } =
371
                    this.circRules = rulesPerTrigger.length ? rulesPerTrigger : rules
441
                        this.splitCircRulesByTriggerNumber(rules)
442
                    this.circRules = rulesPerTrigger.length
443
                        ? rulesPerTrigger
444
                        : rules
372
                },
445
                },
373
                error => {}
446
                error => {}
374
            )               
447
            )
375
        },
448
        },
376
        async handleContextChange() {
449
        async handleContextChange() {
377
            await this.checkForExistingRules()
450
            await this.checkForExistingRules()
Lines 411-417 export default { Link Here
411
                    const numberOfTriggers = Object.keys(rules[0]).filter(
484
                    const numberOfTriggers = Object.keys(rules[0]).filter(
412
                        key => regex.test(key) && rules[0][key] !== null
485
                        key => regex.test(key) && rules[0][key] !== null
413
                    ).length
486
                    ).length
414
                    const splitRules = this.filterCircRulesByContext(this.ruleBeingEdited)
487
                    const splitRules = this.filterCircRulesByContext(
488
                        this.ruleBeingEdited
489
                    )
415
                    this.newTriggerNumber = editMode
490
                    this.newTriggerNumber = editMode
416
                        ? routeParams.triggerNumber
491
                        ? routeParams.triggerNumber
417
                        : numberOfTriggers + 1
492
                        : numberOfTriggers + 1
Lines 429-459 export default { Link Here
429
                        lengthunit: rules[0].lengthunit,
504
                        lengthunit: rules[0].lengthunit,
430
                        numberOfTriggers: numberOfTriggers,
505
                        numberOfTriggers: numberOfTriggers,
431
                    }
506
                    }
507
508
                    this.setMinDelay()
509
                    this.setMaxDelay()
432
                },
510
                },
433
                error => { }
511
                error => {}
434
            )
512
            )
435
        },
513
        },
436
        filterCircRulesByContext(effectiveRule) {
514
        filterCircRulesByContext(effectiveRule) {
437
            const context = effectiveRule.context;
515
            const context = effectiveRule.context
438
        
516
439
            // Filter rules that match the context
517
            // Filter rules that match the context
440
            let contextRules = this.circRules.filter(rule => {
518
            let contextRules = this.circRules.filter(rule => {
441
                return Object.keys(context).every(key => {
519
                return Object.keys(context).every(key => {
442
                    return context[key] === rule.context[key];
520
                    return context[key] === rule.context[key]
443
                });
521
                })
444
            });
522
            })
445
        
523
446
            // Calculate the number of 'overdue_X_' triggers in the effectiveRule
524
            // Calculate the number of 'overdue_X_' triggers in the effectiveRule
447
            const regex = /overdue_(\d+)_delay/g;
525
            const regex = /overdue_(\d+)_delay/g
448
            const numberOfTriggers = Object.keys(effectiveRule).filter(
526
            const numberOfTriggers = Object.keys(effectiveRule).filter(
449
                key => regex.test(key) && effectiveRule[key] !== null
527
                key => regex.test(key) && effectiveRule[key] !== null
450
            ).length;
528
            ).length
451
        
529
452
            // Ensure there is one contextRule per 'X' from 1 to numberOfTriggers
530
            // Ensure there is one contextRule per 'X' from 1 to numberOfTriggers
453
            for (let i = 1; i <= numberOfTriggers; i++) {
531
            for (let i = 1; i <= numberOfTriggers; i++) {
454
                // Check if there's already a rule for overdue_X_ in contextRules
532
                // Check if there's already a rule for overdue_X_ in contextRules
455
                const matchingRule = contextRules.find(rule => rule[`overdue_${i}_delay`] !== undefined);
533
                const matchingRule = contextRules.find(
456
        
534
                    rule => rule[`overdue_${i}_delay`] !== undefined
535
                )
536
457
                if (!matchingRule) {
537
                if (!matchingRule) {
458
                    // Create a new rule with the same context and null overdue_X_* keys
538
                    // Create a new rule with the same context and null overdue_X_* keys
459
                    const placeholderRule = {
539
                    const placeholderRule = {
Lines 461-496 export default { Link Here
461
                        [`overdue_${i}_delay`]: null,
541
                        [`overdue_${i}_delay`]: null,
462
                        [`overdue_${i}_notice`]: null,
542
                        [`overdue_${i}_notice`]: null,
463
                        [`overdue_${i}_mtt`]: null,
543
                        [`overdue_${i}_mtt`]: null,
464
                        [`overdue_${i}_restrict`]: null
544
                        [`overdue_${i}_restrict`]: null,
465
                    };
545
                    }
466
        
546
467
                    // Add the new rule to contextRules
547
                    // Add the new rule to contextRules
468
                    contextRules.push(placeholderRule);
548
                    contextRules.push(placeholderRule)
469
                }
549
                }
470
            }
550
            }
471
551
472
            // Sort contextRules by the 'X' value in 'overdue_X_delay'
552
            // Sort contextRules by the 'X' value in 'overdue_X_delay'
473
            contextRules.sort((a, b) => {
553
            contextRules.sort((a, b) => {
474
                const getX = rule => {
554
                const getX = rule => {
475
                    const match = Object.keys(rule).find(key => regex.test(key));
555
                    const match = Object.keys(rule).find(key => regex.test(key))
476
                    return match ? parseInt(match.match(/\d+/)[0], 10) : 0;
556
                    return match ? parseInt(match.match(/\d+/)[0], 10) : 0
477
                };
557
                }
478
        
558
479
                return getX(a) - getX(b);
559
                return getX(a) - getX(b)
480
            });
560
            })
481
561
482
            return contextRules;
562
            return contextRules
483
        },
563
        },
484
        findFallbackRule(currentContext, key) {
564
        findFallbackRule(currentContext, key) {
485
486
            // Filter rules to only those with non-null values for the specified key and not the current context
565
            // Filter rules to only those with non-null values for the specified key and not the current context
487
            const relevantRules = this.circRules.filter(
566
            const relevantRules = this.circRules.filter(rule => {
488
                rule => {
567
                return (
489
                    return Object.keys(currentContext).some(key => currentContext[key] !== rule.context[key]) 
568
                    Object.keys(currentContext).some(
490
                        && rule[key] !== null
569
                        key => currentContext[key] !== rule.context[key]
491
                        && rule[key] !== undefined;
570
                    ) &&
492
                }
571
                    rule[key] !== null &&
493
            );
572
                    rule[key] !== undefined
573
                )
574
            })
494
575
495
            // Function to calculate specificity score
576
            // Function to calculate specificity score
496
            const getSpecificityScore = ruleContext => {
577
            const getSpecificityScore = ruleContext => {
Lines 503-509 export default { Link Here
503
                if (
584
                if (
504
                    ruleContext.patron_category_id !== "*" &&
585
                    ruleContext.patron_category_id !== "*" &&
505
                    ruleContext.patron_category_id ===
586
                    ruleContext.patron_category_id ===
506
                    currentContext.patron_category_id
587
                        currentContext.patron_category_id
507
                )
588
                )
508
                    score += 2
589
                    score += 2
509
                if (
590
                if (
Lines 524-530 export default { Link Here
524
605
525
            // If no rule found, return null
606
            // If no rule found, return null
526
            if (sortedRules.length === 0) {
607
            if (sortedRules.length === 0) {
527
                return null 
608
                return null
528
            }
609
            }
529
610
530
            // Get the value from the most specific rule
611
            // Get the value from the most specific rule
Lines 543-569 export default { Link Here
543
                    ? context.patron_category_id
624
                    ? context.patron_category_id
544
                    : rules[triggerNumber - 1].context.patron_category_id ||
625
                    : rules[triggerNumber - 1].context.patron_category_id ||
545
                      "*",
626
                      "*",
546
                delay: rules[triggerNumber - 1] ? rules[triggerNumber - 1][
627
                delay: rules[triggerNumber - 1]
547
                    `overdue_${triggerNumber}_delay`
628
                    ? rules[triggerNumber - 1][`overdue_${triggerNumber}_delay`]
548
                ] : null,
629
                    : null,
549
                notice: rules[triggerNumber - 1] ? rules[triggerNumber - 1][
630
                notice: rules[triggerNumber - 1]
550
                    `overdue_${triggerNumber}_notice`
631
                    ? rules[triggerNumber - 1][
551
                ] : null,
632
                          `overdue_${triggerNumber}_notice`
552
                mtt: rules[triggerNumber - 1] ? rules[triggerNumber - 1][`overdue_${triggerNumber}_mtt`]
633
                      ]
634
                    : null,
635
                mtt: rules[triggerNumber - 1]
636
                    ? rules[triggerNumber - 1][`overdue_${triggerNumber}_mtt`]
637
                        ? rules[triggerNumber - 1][
638
                              `overdue_${triggerNumber}_mtt`
639
                          ].split(",")
640
                        : []
641
                    : null,
642
                restrict: rules[triggerNumber - 1]
553
                    ? rules[triggerNumber - 1][
643
                    ? rules[triggerNumber - 1][
554
                          `overdue_${triggerNumber}_mtt`
644
                          `overdue_${triggerNumber}_restrict`
555
                      ].split(",")
645
                      ]
556
                    : [] : null,
646
                    : null,
557
                restrict: rules[triggerNumber - 1] ?
558
                    rules[triggerNumber - 1][
559
                        `overdue_${triggerNumber}_restrict`
560
                    ] : null,
561
            }
647
            }
562
            this.fallbackRule = {
648
            this.fallbackRule = {
563
                delay: this.findFallbackRule(context, `overdue_${triggerNumber}_delay`),
649
                delay: this.findFallbackRule(
564
                notice: this.findFallbackRule(context, `overdue_${triggerNumber}_notice`),
650
                    context,
565
                mtt: this.findFallbackRule(context, `overdue_${triggerNumber}_mtt`),
651
                    `overdue_${triggerNumber}_delay`
566
                restrict: this.findFallbackRule(context, `overdue_${triggerNumber}_restrict`)
652
                ),
653
                notice: this.findFallbackRule(
654
                    context,
655
                    `overdue_${triggerNumber}_notice`
656
                ),
657
                mtt: this.findFallbackRule(
658
                    context,
659
                    `overdue_${triggerNumber}_mtt`
660
                ),
661
                restrict: this.findFallbackRule(
662
                    context,
663
                    `overdue_${triggerNumber}_restrict`
664
                ),
665
            }
666
        },
667
        setMinDelay() {
668
            const priorTriggerNumber = parseInt(this.newTriggerNumber) - 1
669
            this.minDelay = this.ruleBeingEdited[
670
                `overdue_${priorTriggerNumber}_delay`
671
            ]
672
                ? parseInt(
673
                      this.ruleBeingEdited[
674
                          `overdue_${priorTriggerNumber}_delay`
675
                      ]
676
                  ) + 1
677
                : 0
678
        },
679
        setMaxDelay() {
680
            const nextTriggerNumber = parseInt(this.newTriggerNumber) + 1
681
            this.maxDelay = this.ruleBeingEdited[
682
                `overdue_${nextTriggerNumber}_delay`
683
            ]
684
                ? parseInt(
685
                      this.ruleBeingEdited[`overdue_${nextTriggerNumber}_delay`]
686
                  ) - 1
687
                : Infinity
688
        },
689
        incrementDelay() {
690
            // Check for minDelay and maxDelay
691
            const min = this.minDelay !== undefined ? this.minDelay : 1
692
            const max = this.maxDelay !== undefined ? this.maxDelay : Infinity
693
694
            // Set to minDelay if it's null or undefined
695
            if (
696
                this.newRule.delay === undefined ||
697
                this.newRule.delay === null
698
            ) {
699
                this.newRule.delay = min
700
            }
701
702
            // Increment within the valid range
703
            else {
704
                this.newRule["delay"] = Math.min(this.newRule.delay + 1, max)
705
            }
706
        },
707
        decrementDelay() {
708
            // Check for minDelay
709
            const min = this.minDelay !== undefined ? this.minDelay : 1
710
711
            // Decrement only if greater than minDelay
712
            if (this.newRule.delay > min) {
713
                this.newRule.delay--
567
            }
714
            }
568
        },
715
        },
569
    },
716
    },
Lines 598-603 form li { Link Here
598
    align-items: center;
745
    align-items: center;
599
}
746
}
600
747
748
.numeric-input-wrapper {
749
    position: relative;
750
    display: inline-block;
751
    width: 30%;
752
}
753
754
.input-with-clear {
755
    position: relative;
756
    display: flex;
757
    align-items: center;
758
    width: 100%;
759
}
760
761
.numeric-input {
762
    padding-right: 40px; /* Adjust to leave space for clear button */
763
    padding-left: 0.25em;
764
    padding-top: 2px;
765
    padding-bottom: 2px;
766
    width: 100%;
767
    border-radius: 4px;
768
    border: 1px solid #ccc;
769
    font-size: 16px;
770
    box-sizing: border-box;
771
    transition: border-color 0.2s ease;
772
}
773
774
.clear-btn {
775
    position: absolute;
776
    right: 22px; /* Adjust positioning */
777
    fill: var(--vs-controls-color);
778
    background-color: transparent;
779
    border: 0;
780
    font-size: 1.2em;
781
    color: #333;
782
    cursor: pointer;
783
    z-index: 2; /* Ensure it is above the input */
784
}
785
786
.button:active:hover,
787
.clear-btn:active:hover {
788
    background-color: #d4d4d4;
789
    border-color: #8c8c8c;
790
}
791
792
/* Chevron buttons container */
793
.chevron-buttons {
794
    display: flex;
795
    flex-direction: column;
796
    position: absolute;
797
    right: 0px;
798
    top: 0;
799
    bottom: 0;
800
    width: 16px;
801
    padding: 0px 5px 0px 2px;
802
    justify-content: center;
803
    z-index: 2;
804
}
805
806
/* Chevron button styles */
807
.increment-btn,
808
.decrement-btn {
809
    background-color: transparent;
810
    border: 0px solid #ccc;
811
    font-size: 10px;
812
    padding: 0px;
813
    cursor: pointer;
814
    color: rgba(60, 60, 60, 0.5);
815
    border-radius: 2px;
816
}
817
818
.increment-btn:hover,
819
.decrement-btn:hover {
820
    background-color: #ddd;
821
}
822
823
/* Hide the native increment/decrement buttons */
824
input[type="number"]::-webkit-inner-spin-button,
825
input[type="number"]::-webkit-outer-spin-button {
826
    -webkit-appearance: none;
827
    margin: 0;
828
}
829
830
input[type="number"] {
831
    -moz-appearance: textfield; /* For Firefox */
832
}
833
834
.numeric-input:focus,
835
.numeric-input:hover {
836
    border-color: #007bff; /* Match focus color of v-select */
837
    outline: none;
838
}
839
601
.dialog.alert
840
.dialog.alert
602
    fieldset:not(.bg-danger):not(.bg-warning):not(.bg-info):not(.bg-success):not(.bg-primary):not(.action),
841
    fieldset:not(.bg-danger):not(.bg-warning):not(.bg-info):not(.bg-success):not(.bg-primary):not(.action),
603
.dialog.error
842
.dialog.error
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue (-55 / +138 lines)
Lines 36-44 Link Here
36
            </thead>
36
            </thead>
37
            <tbody>
37
            <tbody>
38
                <tr
38
                <tr
39
                    v-for="(rule, i) in modal ? filterCircRulesByContext(ruleBeingEdited) : filterCircRulesByTabNumber(
39
                    v-for="(rule, i) in modal
40
                        triggerNumber
40
                        ? filterCircRulesByContext(ruleBeingEdited)
41
                    )"
41
                        : filterCircRulesByTabNumber(triggerNumber)"
42
                    v-bind:key="'rule' + i"
42
                    v-bind:key="'rule' + i"
43
                    :class="{
43
                    :class="{
44
                        selected_rule:
44
                        selected_rule:
Lines 70-80 Link Here
70
                    <td>
70
                    <td>
71
                        <span
71
                        <span
72
                            :class="{
72
                            :class="{
73
                                fallback: findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_delay`).isFallback,
73
                                fallback: findEffectiveRule(
74
                                    rule,
75
                                    `overdue_${
76
                                        modal ? i + 1 : triggerNumber
77
                                    }_delay`
78
                                ).isFallback,
74
                            }"
79
                            }"
75
                        >
80
                        >
76
                            {{
81
                            {{
77
                                findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_delay`).value +
82
                                findEffectiveRule(
83
                                    rule,
84
                                    `overdue_${
85
                                        modal ? i + 1 : triggerNumber
86
                                    }_delay`
87
                                ).value +
78
                                " " +
88
                                " " +
79
                                $__("days")
89
                                $__("days")
80
                            }}
90
                            }}
Lines 85-94 Link Here
85
                    <td>
95
                    <td>
86
                        <span
96
                        <span
87
                            :class="{
97
                            :class="{
88
                                fallback: findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_notice`).isFallback,
98
                                fallback: findEffectiveRule(
99
                                    rule,
100
                                    `overdue_${
101
                                        modal ? i + 1 : triggerNumber
102
                                    }_notice`
103
                                ).isFallback,
89
                            }"
104
                            }"
90
                        >
105
                        >
91
                            {{ handleNotice(findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_notice`).value) }}
106
                            {{
107
                                handleNotice(
108
                                    findEffectiveRule(
109
                                        rule,
110
                                        `overdue_${
111
                                            modal ? i + 1 : triggerNumber
112
                                        }_notice`
113
                                    ).value
114
                                )
115
                            }}
92
                        </span>
116
                        </span>
93
                    </td>
117
                    </td>
94
118
Lines 96-110 Link Here
96
                    <td>
120
                    <td>
97
                        <span
121
                        <span
98
                            :class="{
122
                            :class="{
99
                                fallback: findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_mtt`).isFallback,
123
                                fallback: findEffectiveRule(
124
                                    rule,
125
                                    `overdue_${
126
                                        modal ? i + 1 : triggerNumber
127
                                    }_mtt`
128
                                ).isFallback,
100
                            }"
129
                            }"
101
                        >
130
                        >
102
                            {{
131
                            {{
103
                                findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_notice`).value !== '' ? 
132
                                findEffectiveRule(
104
                                handleTransport(
133
                                    rule,
105
                                    findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_mtt`).value,
134
                                    `overdue_${
106
                                    "email"
135
                                        modal ? i + 1 : triggerNumber
107
                                ) : ''
136
                                    }_notice`
137
                                ).value !== ""
138
                                    ? handleTransport(
139
                                          findEffectiveRule(
140
                                              rule,
141
                                              `overdue_${
142
                                                  modal ? i + 1 : triggerNumber
143
                                              }_mtt`
144
                                          ).value,
145
                                          "email"
146
                                      )
147
                                    : ""
108
                            }}
148
                            }}
109
                        </span>
149
                        </span>
110
                    </td>
150
                    </td>
Lines 113-127 Link Here
113
                    <td>
153
                    <td>
114
                        <span
154
                        <span
115
                            :class="{
155
                            :class="{
116
                                fallback: findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_mtt`).isFallback,
156
                                fallback: findEffectiveRule(
157
                                    rule,
158
                                    `overdue_${
159
                                        modal ? i + 1 : triggerNumber
160
                                    }_mtt`
161
                                ).isFallback,
117
                            }"
162
                            }"
118
                        >
163
                        >
119
                            {{
164
                            {{
120
                                findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_notice`).value !== '' ? 
165
                                findEffectiveRule(
121
                                handleTransport(
166
                                    rule,
122
                                    findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_mtt`).value,
167
                                    `overdue_${
123
                                    "print"
168
                                        modal ? i + 1 : triggerNumber
124
                                ) : ''
169
                                    }_notice`
170
                                ).value !== ""
171
                                    ? handleTransport(
172
                                          findEffectiveRule(
173
                                              rule,
174
                                              `overdue_${
175
                                                  modal ? i + 1 : triggerNumber
176
                                              }_mtt`
177
                                          ).value,
178
                                          "print"
179
                                      )
180
                                    : ""
125
                            }}
181
                            }}
126
                        </span>
182
                        </span>
127
                    </td>
183
                    </td>
Lines 130-144 Link Here
130
                    <td>
186
                    <td>
131
                        <span
187
                        <span
132
                            :class="{
188
                            :class="{
133
                                fallback: findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_mtt`).isFallback,
189
                                fallback: findEffectiveRule(
190
                                    rule,
191
                                    `overdue_${
192
                                        modal ? i + 1 : triggerNumber
193
                                    }_mtt`
194
                                ).isFallback,
134
                            }"
195
                            }"
135
                        >
196
                        >
136
                            {{
197
                            {{
137
                                findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_notice`).value !== '' ? 
198
                                findEffectiveRule(
138
                                handleTransport(
199
                                    rule,
139
                                    findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_mtt`).value,
200
                                    `overdue_${
140
                                    "sms"
201
                                        modal ? i + 1 : triggerNumber
141
                                ) : ''
202
                                    }_notice`
203
                                ).value !== ""
204
                                    ? handleTransport(
205
                                          findEffectiveRule(
206
                                              rule,
207
                                              `overdue_${
208
                                                  modal ? i + 1 : triggerNumber
209
                                              }_mtt`
210
                                          ).value,
211
                                          "sms"
212
                                      )
213
                                    : ""
142
                            }}
214
                            }}
143
                        </span>
215
                        </span>
144
                    </td>
216
                    </td>
Lines 147-158 Link Here
147
                    <td>
219
                    <td>
148
                        <span
220
                        <span
149
                            :class="{
221
                            :class="{
150
                                fallback: findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_restrict`).isFallback,
222
                                fallback: findEffectiveRule(
223
                                    rule,
224
                                    `overdue_${
225
                                        modal ? i + 1 : triggerNumber
226
                                    }_restrict`
227
                                ).isFallback,
151
                            }"
228
                            }"
152
                        >
229
                        >
153
                            {{
230
                            {{
154
                                handleRestrictions(
231
                                handleRestrictions(
155
                                    findEffectiveRule(rule, `overdue_${modal ? i + 1 : triggerNumber}_restrict`).value
232
                                    findEffectiveRule(
233
                                        rule,
234
                                        `overdue_${
235
                                            modal ? i + 1 : triggerNumber
236
                                        }_restrict`
237
                                    ).value
156
                                )
238
                                )
157
                            }}
239
                            }}
158
                        </span>
240
                        </span>
Lines 167-173 Link Here
167
                                    item_type_id: rule.context.item_type_id,
249
                                    item_type_id: rule.context.item_type_id,
168
                                    patron_category_id:
250
                                    patron_category_id:
169
                                        rule.context.patron_category_id,
251
                                        rule.context.patron_category_id,
170
                                    triggerNumber: modal ? i + 1 : triggerNumber,
252
                                    triggerNumber: modal
253
                                        ? i + 1
254
                                        : triggerNumber,
171
                                },
255
                                },
172
                            }"
256
                            }"
173
                            class="btn btn-default btn-xs"
257
                            class="btn btn-default btn-xs"
Lines 203-234 export default { Link Here
203
                ? value.includes(type)
287
                ? value.includes(type)
204
                    ? this.$__("Yes")
288
                    ? this.$__("Yes")
205
                    : this.$__("No")
289
                    : this.$__("No")
206
                : ''
290
                : ""
207
        },
291
        },
208
        handleRestrictions(value) {
292
        handleRestrictions(value) {
209
            return value === "1" ? this.$__("Yes") : this.$__("No")
293
            return value === "1" ? this.$__("Yes") : this.$__("No")
210
        },
294
        },
211
        filterCircRulesByContext(effectiveRule) {
295
        filterCircRulesByContext(effectiveRule) {
212
            const context = effectiveRule.context;
296
            const context = effectiveRule.context
213
        
297
214
            // Filter rules that match the context
298
            // Filter rules that match the context
215
            let contextRules = this.circRules.filter(rule => {
299
            let contextRules = this.circRules.filter(rule => {
216
                return Object.keys(context).every(key => {
300
                return Object.keys(context).every(key => {
217
                    return context[key] === rule.context[key];
301
                    return context[key] === rule.context[key]
218
                });
302
                })
219
            });
303
            })
220
        
304
221
            // Calculate the number of 'overdue_X_' triggers in the effectiveRule
305
            // Calculate the number of 'overdue_X_' triggers in the effectiveRule
222
            const regex = /overdue_(\d+)_delay/g;
306
            const regex = /overdue_(\d+)_delay/g
223
            const numberOfTriggers = Object.keys(effectiveRule).filter(
307
            const numberOfTriggers = Object.keys(effectiveRule).filter(
224
                key => regex.test(key) && effectiveRule[key] !== null
308
                key => regex.test(key) && effectiveRule[key] !== null
225
            ).length;
309
            ).length
226
        
310
227
            // Ensure there is one contextRule per 'X' from 1 to numberOfTriggers
311
            // Ensure there is one contextRule per 'X' from 1 to numberOfTriggers
228
            for (let i = 1; i <= numberOfTriggers; i++) {
312
            for (let i = 1; i <= numberOfTriggers; i++) {
229
                // Check if there's already a rule for overdue_X_ in contextRules
313
                // Check if there's already a rule for overdue_X_ in contextRules
230
                const matchingRule = contextRules.find(rule => rule[`overdue_${i}_delay`] !== undefined);
314
                const matchingRule = contextRules.find(
231
        
315
                    rule => rule[`overdue_${i}_delay`] !== undefined
316
                )
317
232
                if (!matchingRule) {
318
                if (!matchingRule) {
233
                    // Create a new rule with the same context and null overdue_X_* keys
319
                    // Create a new rule with the same context and null overdue_X_* keys
234
                    const newRule = {
320
                    const newRule = {
Lines 236-260 export default { Link Here
236
                        [`overdue_${i}_delay`]: null,
322
                        [`overdue_${i}_delay`]: null,
237
                        [`overdue_${i}_notice`]: null,
323
                        [`overdue_${i}_notice`]: null,
238
                        [`overdue_${i}_mtt`]: null,
324
                        [`overdue_${i}_mtt`]: null,
239
                        [`overdue_${i}_restrict`]: null
325
                        [`overdue_${i}_restrict`]: null,
240
                    };
326
                    }
241
        
327
242
                    // Add the new rule to contextRules
328
                    // Add the new rule to contextRules
243
                    contextRules.push(newRule);
329
                    contextRules.push(newRule)
244
                }
330
                }
245
            }
331
            }
246
332
247
            // Sort contextRules by the 'X' value in 'overdue_X_delay'
333
            // Sort contextRules by the 'X' value in 'overdue_X_delay'
248
            contextRules.sort((a, b) => {
334
            contextRules.sort((a, b) => {
249
                const getX = rule => {
335
                const getX = rule => {
250
                    const match = Object.keys(rule).find(key => regex.test(key));
336
                    const match = Object.keys(rule).find(key => regex.test(key))
251
                    return match ? parseInt(match.match(/\d+/)[0], 10) : 0;
337
                    return match ? parseInt(match.match(/\d+/)[0], 10) : 0
252
                };
338
                }
253
        
339
254
                return getX(a) - getX(b);
340
                return getX(a) - getX(b)
255
            });
341
            })
256
342
257
            return contextRules;
343
            return contextRules
258
        },
344
        },
259
        filterCircRulesByTabNumber(number) {
345
        filterCircRulesByTabNumber(number) {
260
            return this.circRules.filter(
346
            return this.circRules.filter(
Lines 268-276 export default { Link Here
268
        },
354
        },
269
        handleNotice(notice) {
355
        handleNotice(notice) {
270
            const letter = this.letters.find(letter => letter.code === notice)
356
            const letter = this.letters.find(letter => letter.code === notice)
271
            return letter
357
            return letter ? letter.name : notice
272
                ? letter.name
273
                : notice
274
        },
358
        },
275
        findEffectiveRule(ruleSet, key) {
359
        findEffectiveRule(ruleSet, key) {
276
            // Check if the current rule's value for the key is null
360
            // Check if the current rule's value for the key is null
277
- 

Return to bug 10190