Skip to content

Commit fb3b491

Browse files
committed
Merge branch 'master' into ia
2 parents 6539734 + 5d5bb7f commit fb3b491

File tree

8 files changed

+67
-69
lines changed

8 files changed

+67
-69
lines changed

source/src/main/webapp/ReportingCampaignStatistics.jsp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
<div class="mt-6">
164164
<button
165165
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md h-10"
166+
id="reportingCampaingStatisticsLoadButton"
166167
@click.prevent="$dispatch('load-stats')">
167168
Load
168169
</button>

source/src/main/webapp/TestCaseList.jsp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,11 @@
4949
<%@ include file="include/global/messagesArea.html"%>
5050
<%@ include file="include/utils/modal-confirmation.html"%>
5151
<%@ include file="include/transversalobject/TestCase.html"%>
52-
<jsp:include page="include/transversal/TestCaseSimpleCreation.html"/>
5352
<jsp:include page="include/transversal/TestCaseSimpleExecution.html"/>
5453
<%@ include file="include/transversalobject/Application.html"%>
5554
<%@ include file="include/pages/testcaselist/importTestCaseFromTestLink.html"%>
5655
<jsp:include page="include/transversal/TestCaseListMassActionUpdate.html"/>
5756
<jsp:include page="include/transversal/TestCaseListMassActionLabel.html"/>
58-
<jsp:include page="include/transversal/TestCaseSimpleCreationImport.html"/>
5957
<jsp:include page="include/templates/selectDropdown.html"/>
6058

6159
<h1 class="page-title-line" id="title">Test Case</h1>

source/src/main/webapp/include/templates/datepicker.html

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<!-- Bouton principal -->
55
<button type="button"
66
@click="toggle()"
7+
:id="id + '-mainbutton'"
78
class="flex h-10 items-center justify-between w-full rounded-md border px-3 py-2 text-sm
89
dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300 dark:hover:bg-slate-700
910
bg-white border-slate-300 text-slate-900 hover:bg-slate-100 transition-all">
@@ -23,17 +24,17 @@
2324

2425
<!-- Tabs en haut -->
2526
<div class="w-full flex bg-slate-200 dark:bg-slate-700 p-1 rounded-lg shadow-sm mb-8 h-10">
26-
<button type="button" @click="goToTab('years')" class="flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-md transition-colors duration-200" :class="activeTab==='years' ? 'bg-slate-50 font-semibold dark:bg-slate-900' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white'">Année</button>
27-
<button type="button" @click="goToTab('months')" class="flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-md transition-colors duration-200" :class="activeTab==='months' ? 'bg-slate-50 font-semibold dark:bg-slate-900' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white'">Mois</button>
28-
<button type="button" @click="goToTab('days')" class="flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-md transition-colors duration-200" :class="activeTab==='days' ? 'bg-slate-50 font-semibold dark:bg-slate-900' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white'">Jour</button>
29-
<button type="button" @click="goToTab('hours')" class="flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-md transition-colors duration-200" :class="activeTab==='hours' ? 'bg-slate-50 font-semibold dark:bg-slate-900' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white'">Heure</button>
27+
<button type="button" :id="parent.id + '-years'" @click="goToTab('years')" class="flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-md transition-colors duration-200" :class="activeTab==='years' ? 'bg-slate-50 font-semibold dark:bg-slate-900' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white'">Année</button>
28+
<button type="button" :id="parent.id + '-months'" @click="goToTab('months')" class="flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-md transition-colors duration-200" :class="activeTab==='months' ? 'bg-slate-50 font-semibold dark:bg-slate-900' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white'">Mois</button>
29+
<button type="button" :id="parent.id + '-days'" @click="goToTab('days')" class="flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-md transition-colors duration-200" :class="activeTab==='days' ? 'bg-slate-50 font-semibold dark:bg-slate-900' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white'">Jour</button>
30+
<button type="button" :id="parent.id + '-hours'" @click="goToTab('hours')" class="flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-md transition-colors duration-200" :class="activeTab==='hours' ? 'bg-slate-50 font-semibold dark:bg-slate-900' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white'">Heure</button>
3031
</div>
3132

3233
<!-- Header avec navigation < > -->
3334
<div class="flex items-center justify-between mb-2">
34-
<button @click="previous()" class="p-2 hover:bg-gray-100 rounded-lg">&lt;</button>
35+
<button :id="parent.id + '-previous'" @click="previous()" class="p-2 hover:bg-gray-100 rounded-lg">&lt;</button>
3536
<div class="font-bold" x-text="headerText"></div>
36-
<button @click="next()" class="p-2 hover:bg-gray-100 rounded-lg">&gt;</button>
37+
<button :id="parent.id + '-next'" @click="next()" class="p-2 hover:bg-gray-100 rounded-lg">&gt;</button>
3738
</div>
3839

3940
<!-- Contenu principal selon tab -->
@@ -57,6 +58,7 @@
5758
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2 w-full max-w-[500px]">
5859
<template x-for="(month, index) in monthNames" :key="index">
5960
<button type="button"
61+
:id="parent.id + '-month-' + index"
6062
@click.stop="selectedMonth = index; goToTab('days')"
6163
:class="{'bg-blue-500 text-white': index===selectedMonth, 'hover:bg-gray-100': index!==selectedMonth}"
6264
class="aspect-square flex items-center justify-center rounded-lg text-sm transition"
@@ -79,6 +81,7 @@
7981
<div class="grid grid-cols-7 gap-1">
8082
<template x-for="day in calendarDays" :key="day.day+'-'+day.isCurrentMonth">
8183
<button type="button"
84+
:id="parent.id + '-day-' + day.day+'-'+day.isCurrentMonth"
8285
@click="selectDate(day)"
8386
x-text="day.day"
8487
:class="{
@@ -115,6 +118,7 @@
115118
<script>
116119
function dateTimePicker(config = {}) {
117120
return {
121+
id: config.id || 'datepicker',
118122
open: false,
119123
model: config.model,
120124
modelField: config.modelField,

source/src/main/webapp/include/templates/selectDropdown.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@
3131
<div class="bg-white dark:bg-slate-800 max-h-64 overflow-hidden rounded">
3232

3333
<!-- Search -->
34-
<div class="p-2 border-b dark:border-slate-700">
34+
<div class="p-2 border-b dark:border-slate-700 border-slate-300">
3535
<input x-model="search" type="text" placeholder="Search..."
3636
:id="id + '-search'"
37-
class="w-full text-sm border rounded px-2 py-1 dark:bg-slate-700 dark:border-slate-600">
37+
class="w-full text-sm border rounded px-2 py-1 dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300 dark:hover:bg-slate-700
38+
bg-white border-slate-300 text-slate-900 hover:bg-slate-100">
3839
</div>
3940

4041
<!-- Items -->

source/src/main/webapp/include/templates/selectMultipleDropdown.html

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717
<div class="flex gap-1 items-center" @click.stop>
1818
<!-- Select all items -->
1919
<button @click="selectAll()" x-show="open" type="button"
20+
:id="id + '-all'"
2021
class="text-[10px] px-2 py-0.5 bg-slate-200 hover:bg-slate-300 dark:bg-slate-700 dark:text-slate-200 rounded">
2122
<span x-text="$store.labels.getLabel('common','all')">All</span>
2223
</button>
2324

2425
<!-- Clear all selections -->
2526
<button @click="clearAll()" x-show="open" type="button"
27+
:id="id + '-none'"
2628
class="text-[10px] px-2 py-0.5 bg-slate-200 hover:bg-slate-300 dark:bg-slate-700 dark:text-slate-200 rounded">
2729
<span x-text="$store.labels.getLabel('common','none')">None</span>
2830
</button>
@@ -32,19 +34,20 @@
3234
<!-- Dropdown content, teleported to <body> to avoid overflow clipping -->
3335
<template x-teleport="body">
3436
<div x-show="open"
35-
@click.outside="open = false"
3637
x-transition
3738
class="absolute rounded-md border shadow-lg z-50
3839
dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300
3940
bg-white border-slate-300 text-slate-900"
40-
:style="{ top: `${top}px`, left: `${left}px`, minWidth: `${width}px` }">
41+
:style="{ top: `${top}px`, left: `${left}px`, minWidth: `${width}px` }"
42+
:id="id + '-dropdown'">
4143

4244
<div class="bg-white dark:bg-slate-800 max-h-64 overflow-hidden rounded-md dark:border-slate-600">
4345

4446
<!-- Search bar -->
45-
<div class="p-2 border-b dark:border-slate-700">
46-
<input type="text" x-model="search" :placeholder="$store.labels.getLabel('common','search')"
47-
class="w-full text-sm border rounded px-2 py-1 dark:bg-slate-700 dark:border-slate-600">
47+
<div class="p-2 border-b dark:border-slate-700 border-slate-300">
48+
<input type="text" x-model="search" :placeholder="$store.labels.getLabel('common','search')" :id="id + '-search'"
49+
class="w-full text-sm border rounded px-2 py-1 dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300 dark:hover:bg-slate-700
50+
bg-white border-slate-300 text-slate-900 hover:bg-slate-100">
4851
</div>
4952

5053
<!-- Selectable list of items -->
@@ -102,7 +105,7 @@
102105
this.$el.appendChild(tpl);
103106

104107
// Load dropdown items using the provided loader function
105-
this.items = this.loader();
108+
this.items = await this.loader();
106109

107110
// Set preselected values (if any)
108111
if (this.preselected.length) {
@@ -114,7 +117,16 @@
114117

115118
// Close dropdown when clicking outside of it
116119
document.addEventListener('click', e => {
117-
if (this.open && !this.$el.contains(e.target)) this.open = false;
120+
const dropdown = document.getElementById(this.id + '-dropdown');
121+
122+
if (
123+
this.open &&
124+
!this.$el.contains(e.target) &&
125+
dropdown &&
126+
!dropdown.contains(e.target)
127+
) {
128+
this.open = false;
129+
}
118130
});
119131

120132
// Listen to external refresh event for dynamic updates

source/src/main/webapp/include/transversal/TestCaseSimpleCreation.html

Lines changed: 23 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
x-transition:leave="transition ease-in duration-200"
2020
x-transition:leave-start="opacity-100 scale-100"
2121
x-transition:leave-end="opacity-0 scale-95"
22-
@click.away="open = false">
22+
@click.away="if (!$event.target.closest('.single-select-dropdown')) open = false">
2323

2424
<!-- HEADER -->
2525
<div class="flex items-center justify-between px-6 py-4 mb-8">
@@ -89,44 +89,26 @@ <h2 class="!text-lg !font-semibold !mb-0 !mt-2" x-text="$store.labels.getLabel('
8989

9090
<!-- Bloc SELECTION d'application existante -->
9191
<div x-show="!creatingApplication" x-transition>
92-
<div class="relative" @click.away="open = false">
93-
94-
<!-- Bouton dropdown -->
95-
<button type="button"
96-
@click="open = !open"
97-
id="editTestCaseSimpleCreationApplication"
98-
class="flex h-10 items-center justify-between w-full rounded-md border px-3 py-2 text-sm
99-
dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300 dark:hover:bg-slate-700
100-
bg-white border-slate-300 text-slate-900 hover:bg-slate-100 transition-all">
101-
<span x-text="applicationDropdown.selectedLabel()"></span>
102-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-2"
103-
fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
104-
<path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/>
105-
</svg>
106-
</button>
107-
108-
<!-- Liste dropdown -->
109-
<div x-show="open" x-transition
110-
class="absolute mt-1 w-full rounded-md border shadow-lg z-50
111-
dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300
112-
bg-white border-slate-300 text-slate-900 max-h-48 overflow-auto">
113-
<template x-for="item in applicationDropdown.items" :key="item">
114-
<div>
115-
<button type="button"
116-
:id="`editTestCaseSimpleCreationApplication_${item}`"
117-
@click="applicationDropdown.select(item); form.application = item; nextStepIfValid('application'); open=false"
118-
class="w-full flex items-center gap-2 px-3 py-2 dark:hover:bg-slate-700 hover:bg-slate-100 transition-colors">
119-
<span x-text="item"></span>
120-
</button>
121-
</div>
122-
</template>
123-
</div>
92+
<div x-data="singleSelectDropdown({
93+
id: 'editTestCaseSimpleCreationApplication',
94+
loader: async () => {
95+
try {
96+
const r = await fetch('ReadApplication');
97+
const d = await r.json();
98+
return d.contentTable.map(a => a.application);
99+
} catch (e) {
100+
console.error('Failed to load applications:', e);
101+
return [];
102+
}
103+
}
104+
})"
105+
x-modelable="selectedValue"
106+
x-model="form.application">
124107
</div>
125108

126-
<!-- Bouton "Créer une nouvelle application" -->
127109
<div class="mt-2">
128110
<button type="button"
129-
@click="creatingApplication = true; form.application=''; open=false"
111+
@click="creatingApplication = true; form.application=''"
130112
class="text-sm text-blue-600 hover:underline">
131113
+ Create a new application
132114
</button>
@@ -380,10 +362,8 @@ <h2 class="!text-lg !font-semibold !mb-0 !mt-2" x-text="$store.labels.getLabel('
380362
environments: [],
381363
appTypes: [],
382364

383-
applicationDropdown: { items: [], selected:'', open:false, select(item){ this.selected=item; this.open=false; }, selectedLabel(){ return this.selected || '-- Select --'; } },
384365

385366
async setDefaultTest(test){
386-
await this.loadApplications();
387367
await this.loadTests();
388368
await this.loadInvariants();
389369

@@ -395,12 +375,6 @@ <h2 class="!text-lg !font-semibold !mb-0 !mt-2" x-text="$store.labels.getLabel('
395375
}
396376
},
397377

398-
async loadApplications(){
399-
const resp = await fetch('ReadApplication');
400-
const data = await resp.json();
401-
this.applications = data.contentTable.map(c => c.application);
402-
this.applicationDropdown.items = this.applications;
403-
},
404378

405379
async loadTests(){
406380
const resp = await fetch('ReadTest?iSortCol_0=0&sSortDir_0=asc&sColumns=test&iDisplayLength=100');
@@ -471,7 +445,6 @@ <h2 class="!text-lg !font-semibold !mb-0 !mt-2" x-text="$store.labels.getLabel('
471445
.then(respData => {
472446
console.log("Create response:", respData);
473447

474-
// 🔹 Tolère les 2 conventions de Cerberus : "OK" ou "success"
475448
if (respData.messageType === 'success' || respData.messageType === 'OK') {
476449
if (respData.test && respData.testcase) {
477450
window.location.href = `./TestCaseScript.jsp?test=${encodeURIComponent(respData.test)}&testcase=${encodeURIComponent(respData.testcase)}&oneclickcreation=true`;
@@ -490,9 +463,14 @@ <h2 class="!text-lg !font-semibold !mb-0 !mt-2" x-text="$store.labels.getLabel('
490463
},
491464

492465
async init(){
493-
await this.loadApplications();
494466
await this.loadTests();
495467
await this.loadInvariants();
468+
469+
this.$watch('form.application', (value) => {
470+
if (value && this.step === 0) {
471+
this.nextStepIfValid('application');
472+
}
473+
});
496474
}
497475
}
498476
}

source/src/main/webapp/js/global/table-filter.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -511,21 +511,27 @@ function _buildColumnFilter(opts) {
511511
+ '<line x1="10" y1="18" x2="14" y2="18"/>'
512512
+ '</svg>';
513513

514+
var filterId = 'columnButtonFilter_' + index;
514515
var $triggerBtn = $('<span>')
515-
.attr({ 'data-col-index': index, title: hasValues ? valueFiltered.join(', ') : '' })
516+
.attr({ id: filterId, 'data-col-index': index, title: hasValues ? valueFiltered.join(', ') : '' })
516517
.addClass(
517518
'col-filter-trigger inline-flex items-center justify-end ml-auto cursor-pointer rounded transition-colors duration-150 ' +
518519
(hasValues
519-
? 'text-blue-500 dark:text-blue-400'
520+
? 'text-blue-500 dark:text-blue-400 font-bold'
520521
: 'text-gray-300 dark:text-gray-600 hover:text-gray-500 dark:hover:text-gray-400')
521522
)
522523
.html(svgFunnel);
523524

524525
// Injecter l'icône dans le th principal (à côté du label de colonne).
525526
// On cible le <th> de la première ligne de headers via columnVisibleIndex.
526527
var $th = $($('#' + tableId + '_wrapper .dataTables_scrollHeadInner table thead tr:first th')[opts.columnVisibleIndex]);
527-
$th.find('.col-filter-trigger').remove(); // éviter les doublons au refresh
528-
$th.append($triggerBtn);
528+
529+
if (!$th.find('.th-content').length) {
530+
$th.wrapInner('<div class="th-content flex items-center w-full"></div>');
531+
}
532+
533+
$th.find('.col-filter-trigger').remove();
534+
$th.find('.th-content').append($triggerBtn);
529535

530536
// filterHeader reste vide — c'est juste un spacer structurel
531537
$(tableCell).empty();

0 commit comments

Comments
 (0)