This commit is contained in:
2025-07-09 08:52:18 +02:00
parent dbbf14bbf4
commit 0a178899d7
2 changed files with 269 additions and 161 deletions

View File

@ -3,7 +3,7 @@
<div class="mb-0 d-flex" style="align-items:baseline"> <div class="mb-0 d-flex" style="align-items:baseline">
<h5 style="flex-grow:1">#{{ issue.redmine.id }} {{ issue.redmine.subject }}</h5> <h5 style="flex-grow:1">#{{ issue.redmine.id }} {{ issue.redmine.subject }}</h5>
<a href="{{redmineUrl}}/issues/{{issue.id}}" target="_blank" class="btn btn-primary"><i class="fas fa-eye"></i></a> <a href="{{redmineUrl}}/issues/{{issue.id}}" target="_blank" class="btn btn-primary"><i class="fas fa-eye"></i></a>
<div class="btn btn-secondary" onClick="$('.issueContainer').hide();$('.scrumContainer').css('padding-left','0px');"><i class="fas fa-window-close"></i></div> <div class="btn btn-secondary" onClick="hideIssue()"><i class="fas fa-window-close"></i></div>
</div> </div>
<small class="text-muted">Projet : {{ issue.redmine.project.name }} • Tracker : {{ issue.redmine.tracker.name }}</small> <small class="text-muted">Projet : {{ issue.redmine.project.name }} • Tracker : {{ issue.redmine.tracker.name }}</small>
@ -70,6 +70,8 @@
</ul> </ul>
</div> </div>
{% endif %} {% endif %}
{{dump(issue.redmine)}}
</div> </div>
<br><br> <br><br>
</div> </div>

View File

@ -24,21 +24,24 @@
padding:0px; padding:0px;
} }
.scrumContainer {
display:none;
}
.issueContainer { .issueContainer {
position:fixed; position:fixed;
width:750px; width:750px;
} }
.filtreContainer{ .filtreContainer{
position:fixed;
display:flex; display:flex;
width:300px; width:300px;
flex-direction:column; flex-direction:column;
background-color: var(--bs-dark); background-color: var(--bs-dark);
padding:5px; padding:5px;
z-index: 900;
}
.scrumContainer {
display:none;
padding-left:300px;
} }
.containerStatus{ .containerStatus{
@ -128,6 +131,19 @@
text-align: left; text-align: left;
} }
@keyframes pulse {
0% { transform: scale(1); }
25% { transform: scale(1.1); }
50% { transform: scale(1); }
75% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.pulse-highlight {
animation: pulse 1.5s ease-in-out 1;
z-index: 1000;
position: relative;
}
</style> </style>
{% endblock %} {% endblock %}
@ -137,8 +153,10 @@
<div class='issueContainer'> <div class='issueContainer'>
</div> </div>
<div class='scrumContainer'>
<div class='filtreContainer'> <div class='filtreContainer'>
<label>Issue</label>
<input type="number" id="issueSearchInput" class="form-control" placeholder="Rechercher une issue" />
<label>Statut</label> <label>Statut</label>
<select id="statusFilter" class="select2 form-select" multiple="true" tabindex="-1" aria-hidden="true"> <select id="statusFilter" class="select2 form-select" multiple="true" tabindex="-1" aria-hidden="true">
{% for statut in project.redmine.issue_statuses %} {% for statut in project.redmine.issue_statuses %}
@ -182,10 +200,14 @@
{% endfor %} {% endfor %}
</select> </select>
<label>Détail Issue</label>
<button id="toggleIssueBody" class="btn btn-secondary btn-sm mt-3">Afficher Détail</button> <select id="detailFilter" class="select2 form-select" tabindex="-1" aria-hidden="true">
<option value="0">Non</option>
<option value="1">Oui</option>
</select>
</div> </div>
<div class='scrumContainer'>
<div class='containerStatus'> <div class='containerStatus'>
{% for status in project.redmine.issue_statuses %} {% for status in project.redmine.issue_statuses %}
{% if status.id not in project.hiddenstatuses %} {% if status.id not in project.hiddenstatuses %}
@ -250,7 +272,7 @@
<div class='issueId'>#{{issue.id}}</div> <div class='issueId'>#{{issue.id}}</div>
<div class='issueSubject'>{{issue.redmine.subject}}</div> <div class='issueSubject'>{{issue.redmine.subject}}</div>
<div class='issueAction'> <div class='issueAction'>
<i class='fas fa-eye' onClick='fetchAndRenderIssue({{issue.id}})'></i> <i class='fas fa-eye' onClick='viewIssue({{issue.id}})'></i>
<verysmall>{{issue.redmine.sprint.story_points}}</verysmall> <verysmall>{{issue.redmine.sprint.story_points}}</verysmall>
</div> </div>
</div> </div>
@ -267,16 +289,158 @@
{% block javascripts %} {% block javascripts %}
<script> <script>
let showIssuebody = false; const projectId = '{{ project.id }}';
const viewedIssueKey = `project_${projectId}_viewedIssue`;
const filterIds = [
'statusFilter',
'sprintFilter',
'versionFilter',
'trackerFilter',
'categoryFilter',
'detailFilter'
];
// Pulse
function highlightAndScroll($element) {
if (!$element || !$element.length) return;
if (!$element.is(':visible')) return;
// Scroll vertical (retourne une promesse)
const scrollTopPromise = new Promise(resolve => {
$('html, body').animate({
scrollTop: $element.offset().top - 100
}, 500, resolve);
});
// Scroll horizontal (retourne une promesse)
const scrollLeftPromise = new Promise(resolve => {
$('html, body').animate({
scrollLeft: $element.offset().left - 315
}, 500, resolve);
});
// Attendre que les deux scrolls soient terminés
Promise.all([scrollTopPromise, scrollLeftPromise]).then(() => {
$element.addClass('pulse-highlight');
setTimeout(() => {
$element.removeClass('pulse-highlight');
}, 3000); // Ajuster selon la durée de l'animation CSS
});
}
// Ranger les issues dans status / sprint / version
$(function () {
$('.issueCard').each(function () {
const id = $(this).data('status')+'|'+$(this).data('sprint')+'|'+$(this).data('version');
const $column = $(`[data-id='${id}']`);
if ($column.length) {
$column.append($(this));
}
else {
console.log ('no ='+id);
$(this).remove();
}
});
$('.scrumContainer').css('display', 'flex');
});
// Ajuster les dom en fonction de la window
function adjustHeight() { function adjustHeight() {
let ele = $(".issueDescription"); console.log('adjustHeight');
if (ele.length) {
ele.css("height", window.innerHeight - ele.offset().top + "px"); let ele = document.querySelector(".issueDescription");
} if (ele) {
const top = ele.getBoundingClientRect().top;
ele.style.height = (window.innerHeight - top) + "px";
} }
ele = document.querySelector(".filtreContainer");
if (ele) {
const top = ele.getBoundingClientRect().top;
ele.style.height = (window.innerHeight - top) + "px";
}
}
window.addEventListener("resize", adjustHeight);
window.addEventListener("load", function () {
adjustHeight();
});
// Recherche Issue
$(function () {
$('#issueSearchInput').on('input', function () {
const value = $(this).val().trim();
if (!value || isNaN(value)) return;
const $target = $(`.issueCard[data-id="${value}"]`);
if ($target.length > 0) {
highlightAndScroll($target);
} else {
// Non trouvé → optionnel
// hideIssue();
console.warn('Issue non trouvée');
}
});
});
// Affichage Issue
function viewIssue(issueId) {
localStorage.setItem(viewedIssueKey, issueId);
url='{{path('app_issue_view',{id:'xxx'})}}';
url=url.replace('xxx',issueId);
console.log(url);
$.ajax({
url: url,
method: 'GET',
dataType: 'html',
success: function (html) {
$('.issueContainer').html(html);
$('.issueContainer').show();
$('.scrumContainer').css('padding-left','750px');
$('.issueContainer').css('z-index','1000');
$('.issueDescription').animate({scrollTop: 0}, 0);
adjustHeight();
},
error: function (xhr, status, error) {
console.error('Erreur lors du chargement de lissue :', error);
$('.issueContainer').html('<div class="alert alert-danger">Erreur lors du chargement de lissue.</div>');
}
});
}
function hideIssue() {
localStorage.removeItem(viewedIssueKey);
$('.issueContainer').hide();
$('.scrumContainer').css('padding-left','0px');
}
// Filtre sur les issues et backup des filtres en localstorage
$(function () {
// Fonction pour construire une clé unique par projet
const getKey = (id) => `project_${projectId}_${id}`;
// Initialiser les sélections depuis localStorage
filterIds.forEach(id => {
const saved = localStorage.getItem(getKey(id));
if (saved) {
const values = JSON.parse(saved);
$(`#${id}`).val(values).trigger('change');
}
});
// Afficher / Cacher les issues
function showhide() { function showhide() {
// Backup des filtres en localstorage
filterIds.forEach(id => {
const selected = $(`#${id}`).val() || [];
localStorage.setItem(getKey(id), JSON.stringify(selected));
});
// Statut // Statut
selected = $('#statusFilter').val(); selected = $('#statusFilter').val();
if (!selected || selected.length === 0) { if (!selected || selected.length === 0) {
@ -334,89 +498,31 @@
if(hasValidTracker&&hasValidCategory) $(this).show(); if(hasValidTracker&&hasValidCategory) $(this).show();
}); });
// Tracker // Filtre detail
selected = $('#versionFilter').val(); selected = $('#detailFilter').val();
if (!selected || selected.length === 0) { if(selected=="0")
$('.versionCard').show();
}
else {
$('.versionCard').hide();
selected.forEach(function (id) {
$('.versionCard' + id).show();
});
}
}
function toogleIssueBody() {
if (showIssuebody) {
$('.issueBody').show();
$(this).text('Masquer Détail');
} else {
$('.issueBody').hide(); $('.issueBody').hide();
$(this).text('Afficher Détail'); else
$('.issueBody').show();
// Afficher l'issue
const savedIssueId = localStorage.getItem(viewedIssueKey);
if (savedIssueId) {
viewIssue(savedIssueId);
} }
showIssuebody=!showIssuebody;
} }
$(document).ready(function () { // Écouteurs sur tous les filtres
// Ranger les issues filterIds.forEach(id => {
$('.issueCard').each(function () { $(`#${id}`).on('change', showhide);
const id = $(this).data('status')+'|'+$(this).data('sprint')+'|'+$(this).data('version');
const $column = $(`[data-id='${id}']`);
if ($column.length) {
$column.append($(this));
}
else {
console.log ('no ='+id);
$(this).remove();
}
}); });
// Afficher le scrum après rangement // Lancer une première fois après initialisation
$('.scrumContainer').css('display', 'flex');
// Filtre
$('#statusFilter').on('change',showhide);
$('#sprintFilter').on('change',showhide);
$('#versionFilter').on('change',showhide);
$('#trackerFilter').on('change',showhide);
$('#categoryFilter').on('change',showhide);
showhide(); showhide();
// issueBody
$('#toggleIssueBody').on('click',toogleIssueBody);
toogleIssueBody();
// Ajuste height
adjustHeight();
window.addEventListener("resize", adjustHeight);
}); });
function fetchAndRenderIssue(issueId) {
url='{{path('app_issue_view',{id:'xxx'})}}';
url=url.replace('xxx',issueId);
console.log(url);
$.ajax({
url: url,
method: 'GET',
dataType: 'html',
success: function (html) {
$('.issueContainer').html(html);
$('.issueContainer').show();
$('.scrumContainer').css('padding-left','750px');
$('.issueContainer').css('z-index','1000');
$('.issueDescription').animate({scrollTop: 0}, 0);
adjustHeight();
},
error: function (xhr, status, error) {
console.error('Erreur lors du chargement de lissue :', error);
$('.issueContainer').html('<div class="alert alert-danger">Erreur lors du chargement de lissue.</div>');
}
});
}
// Déplacement des issues
$(function () { $(function () {
let $sourceContainer = null; let $sourceContainer = null;
let $movedItem = null; let $movedItem = null;