detail issue

This commit is contained in:
afornerot 2024-02-21 20:58:38 +01:00
parent 3d949eefce
commit 2df92a3b7f
7 changed files with 297 additions and 198 deletions

View File

@ -43,7 +43,7 @@
"symfony/web-link": "5.1.*",
"symfony/webpack-encore-bundle": "^1.7",
"symfony/yaml": "5.1.*",
"tetranz/select2entity-bundle": "^3.0"
"tetranz/select2entity-bundle": "^3.0",
},
"require-dev": {
"symfony/debug-pack": "*",
@ -53,7 +53,11 @@
"preferred-install": {
"*": "dist"
},
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"ocramius/package-versions": true,
"symfony/flex": true
}
},
"autoload": {
"psr-4": {

View File

@ -341,3 +341,7 @@ app_scrumissue_update:
app_scrumissue_ctrlchange:
path: /user/scrumissue/ctrlchange
defaults: { _controller: App\Controller\ScrumissueController:ctrlchange }
app_scrumissue_view:
path: /user/scrumissue/view/{id}
defaults: { _controller: App\Controller\ScrumissueController:view }

View File

@ -216,7 +216,7 @@ class ScrumController extends AbstractController
// Idgiteas
$gicol=$issue->getScrumcolumn()->getGiteaid();
$gijal=$issue->getGiteaMilestone();
$gijal=($issue->getGiteaMilestone()?$issue->getGiteaMilestone():-100);
// Liste des colonnes/jalons/sprint avec des issues
if(!in_array($idcol,$tbcols)) array_push($tbcols,$idcol);
@ -719,196 +719,6 @@ class ScrumController extends AbstractController
return new JsonResponse($output);
}
private function consolidateScrum($scrum,$giteamilestones,&$tbissues,&$tbestim) {
$em = $this->getDoctrine()->getManager();
$issues=$scrum->getScrumissues();
$tbissues=[];
$tbestim=[];
$tbcols=[];
$tbjals=[];
$tbsprs=[];
$viewclosed = $this->get('session')->get("viewclosed");
foreach($issues as $issue) {
// bypass closed
if($viewclosed=="false"&&$issue->getGiteastate()=="closed") continue;
// Ids
$idcol=$issue->getScrumcolumn()->getId();
$idjal=($issue->getGiteamilestone()?$issue->getGiteamilestone():-100);
$idspr=($issue->getScrumsprint()?$issue->getScrumsprint()->getId():-100);
// Roworders
$rowcol=$issue->getScrumcolumn()->getRowid();
$rowjal=($issue->getGiteaMilestonename()?$issue->getGiteaMilestonename():-100);
$rowspr=($issue->getScrumsprint()?$issue->getScrumsprint()->getRowid():-100);
// Names
$nmcol=$issue->getScrumcolumn()->getName();
$nmjal=($issue->getGiteaMilestonename()?$issue->getGiteaMilestonename():"Aucun");
$nmspr=($issue->getScrumsprint()?$issue->getScrumsprint()->getName():"Aucun");
// Idgiteas
$gicol=$issue->getScrumcolumn()->getGiteaid();
$gijal=$issue->getGiteaMilestone();
// Liste des colonnes/jalons/sprint avec des issues
if(!in_array($idcol,$tbcols)) array_push($tbcols,$idcol);
if(!in_array($idcol."|".$idjal,$tbjals)) array_push($tbjals,$idcol."|".$idjal);
if(!in_array($idcol."|".$idjal."|".$idspr,$tbsprs)) array_push($tbsprs,$idcol."|".$idjal."|".$idspr);
// Initialisation du tableau des estimations
if(!array_key_exists($idjal,$tbestim)) {
$tbestim[$idjal] = [
"rowjal" => $rowjal,
"idjal" => $idjal,
"nmjal" => $nmjal,
"gijal" => $gijal,
"nbjrs" => 0,
"sprints" => []
];
}
if(!array_key_exists($idspr,$tbestim[$idjal]["sprints"])) {
$tbestim[$idjal]["sprints"][$idspr] = [
"rowspr" => $rowspr,
"idspr" => $idspr,
"nmspr" => $nmspr,
"nbjrs" => 0,
];
}
// Initialisation du tableau des colonnes
if(!array_key_exists($idcol,$tbissues)) {
$tbissues[$idcol]=[
"rowcol" => $rowcol,
"idcol" => $idcol,
"nmcol" => $nmcol,
"gicol" => $gicol,
"nbjrs" => 0,
"jalons" => [],
];
}
// Initialisation du tableau des jalons de la colonne encours
if(!array_key_exists($idjal,$tbissues[$idcol]["jalons"])) {
$tbissues[$idcol]["jalons"][$idjal] = [
"rowjal" => $rowjal,
"idjal" => $idjal,
"nmjal" => $nmjal,
"gijal" => $gijal,
"nbjrs" => 0,
"sprints" => [],
];
}
// Initialisation du tableau des sprint de la colonne/jalon encours
if(!array_key_exists($idspr,$tbissues[$idcol]["jalons"][$idjal]["sprints"])) {
$tbissues[$idcol]["jalons"][$idjal]["sprints"][$idspr] = [
"rowspr" => $rowspr,
"idspr" => $idspr,
"nmspr" => $nmspr,
"nbjrs" => 0,
"issues" => [],
];
}
// On cumule les estimations
$tbissues[$idcol]["nbjrs"]+=$issue->getWeight();
$tbissues[$idcol]["jalons"][$idjal]["nbjrs"]+=$issue->getWeight();
$tbissues[$idcol]["jalons"][$idjal]["sprints"][$idspr]["nbjrs"]+=$issue->getWeight();
$tbestim[$idjal]["nbjrs"]+=$issue->getWeight();
$tbestim[$idjal]["sprints"][$idspr]["nbjrs"]+=$issue->getWeight();
// On sauvegarde l'issue
array_push($tbissues[$idcol]["jalons"][$idjal]["sprints"][$idspr]["issues"],$issue);
}
// On ajoute les colonnes sans issues
$columns=$scrum->getScrumcolumns();
foreach($columns as $column) {
if(!in_array($column->getId(),$tbcols)) {
$tbissues[$column->getId()] = [
"rowcol" => $column->getRowid(),
"idcol" => $column->getId(),
"nmcol" => $column->getName(),
"gicol" => $column->getGiteaid(),
"nbjrs" => 0,
"jalons" => [],
];
}
// On ajoute les jalons sans issues
foreach($giteamilestones as $milestone) {
if(!in_array($column->getId()."|".$milestone->id,$tbjals)) {
$tbissues[$column->getId()]["jalons"][$milestone->id] = [
"rowjal" => $milestone->title,
"idjal" => $milestone->id,
"nmjal" => $milestone->title,
"gijal" => $milestone->id,
"nbjrs" => 0,
"sprints" => [],
];
}
}
// On ajoute le jalon aucun si sans issue
if(!in_array($column->getId()."|-100",$tbjals)) {
$tbissues[$column->getId()]["jalons"][-100] = [
"rowjal" => -100,
"idjal" => -100,
"nmjal" => "Aucun",
"gijal" => null,
"nbjrs" => 0,
"sprints" => [],
];
}
// On ajoutes les sprints sans issues
foreach($tbissues[$column->getId()]["jalons"] as $jalon) {
$sprints=$em->getRepository("App:Scrumsprint")->findBy(["scrum"=>$scrum,"giteamilestone"=>$jalon["idjal"]]);
foreach($sprints as $sprint) {
if(!in_array($column->getId()."|".$jalon["idjal"]."|".$sprint->getId(),$tbsprs)) {
$tbissues[$column->getId()]["jalons"][$jalon["idjal"]]["sprints"][$sprint->getId()] = [
"rowspr" => $sprint->getRowid(),
"idspr" => $sprint->getId(),
"nmspr" => $sprint->getName(),
"nbjrs" => 0,
"issues" => [],
];
}
}
// On ajoute les sprint aucun sans issue
if(!in_array($column->getId()."|".$jalon["idjal"]."|-100",$tbsprs)) {
$tbissues[$column->getId()]["jalons"][$jalon["idjal"]]["sprints"][-100] = [
"rowspr" => -100,
"idspr" => -100,
"nmspr" => "Aucun",
"nbjrs" => 0,
"issues" => [],
];
}
}
}
// Tri des issues par colonne/jalon/sprint/issue
$rowcol = array_column($tbissues, 'rowcol');
array_multisort($rowcol, SORT_ASC, $tbissues);
foreach($tbissues as $keycol=>$column) {
$rowjal = array_column($tbissues[$keycol]["jalons"], 'rowjal');
array_multisort($rowjal, SORT_DESC, $tbissues[$keycol]["jalons"]);
foreach($tbissues[$keycol]["jalons"] as $keyjal=>$jalon) {
$rowspr = array_column($tbissues[$keycol]["jalons"][$keyjal]["sprints"], 'rowspr');
array_multisort($rowspr, SORT_DESC, $tbissues[$keycol]["jalons"][$keyjal]["sprints"]);
}
}
}
protected function getErrorForm($id,$form,$request,$data,$mode) {
if ($form->get('submit')->isClicked()&&$mode=="delete") {
}

View File

@ -12,6 +12,7 @@ use App\Entity\Scrumissue as Entity;
use App\Form\ScrumissueType as Form;
use App\Service\giteaService;
use stdClass;
class ScrumissueController extends AbstractController
{
@ -141,6 +142,68 @@ class ScrumissueController extends AbstractController
return new JsonResponse($output);
}
public function view($id, Request $request) {
$em = $this->getDoctrine()->getManager();
$issue=$em->getRepository("App:Scrumissue")->find($id);
$scrum = $issue->getScrum();
$repoid = $scrum->getGiteaid();
$repoowner = $scrum->getGiteajson()["owner"]["login"];
$reponame = $scrum->getGiteajson()["name"];
$repo=$this->giteaservice->getRepo($repoid);
$giteaissue=$this->giteaservice->getIssue($repoowner,$reponame,$issue->getGiteanumber());
$giteaissue->body = $this->giteaservice->markdown("/".$scrum->getGiteajson()["full_name"],"comment",$giteaissue->body);
$giteaissue->comments=$this->giteaservice->getIssueComments($repoowner,$reponame,$giteaissue->number);
$giteaissue->statuslife=$issue->getScrumcolumn()->getName();
$giteaissue->sprint=($issue->getScrumsprint()?$issue->getScrumsprint()->getName():null);
foreach($giteaissue->comments as $keycomment => $comment) {
$giteaissue->comments[$keycomment]->body=$this->giteaservice->markdown("/".$scrum->getGiteajson()["full_name"],"comment",$giteaissue->comments[$keycomment]->body);
}
$giteaissue->timelines=$this->giteaservice->getIssueTimelines($repoowner,$reponame,$giteaissue->number);
$giteaissue->labelhistos=[];
$giteaissue->refs=[];
foreach($giteaissue->timelines as $key => $timeline) {
if($timeline->type == "label"){
$tmp=new stdClass();
$tmp->label=($timeline->body==1?"Ajout Label":"Suppression Label")." <i>".$timeline->label->name."<i>";
$tmp->user=$timeline->user;
$tmp->created_at=$timeline->created_at;
array_push($giteaissue->labelhistos,$tmp);
unset($giteaissue->timelines[$key]);
}
elseif($timeline->type == "comment_ref" || $timeline->type == "pull_ref" || $timeline->type == "issue_ref"){
$tmp=new stdClass();
$tmp->label ="<a href='".$timeline->ref_issue->html_url."' target='_blank'>";
$tmp->label.=($timeline->type=="pull_ref"?"Request":"Issue")." = ";
$tmp->label.="#".$timeline->ref_issue->number." = ".$timeline->ref_issue->title."</a></i>";
$tmp->user=$timeline->user;
$tmp->created_at=$timeline->created_at;
array_push($giteaissue->refs,$tmp);
unset($giteaissue->timelines[$key]);
}
}
// Affichage du formulaire
return $this->render('Scrum/issue.html.twig', [
'useheader' => false,
'usesidebar' => false,
'maxwidth' => true,
'repo' => $repo,
'issue' => $giteaissue,
]);
}
public function update(Request $request)
{
$em = $this->getDoctrine()->getManager();

View File

@ -45,7 +45,7 @@
{% for comment in issue.comments %}
<h3 class='mt-3'>{{comment.user.login}} le {{comment.created_at|date("d/m/Y H:i")}}</h3>
<div class='card card-body'>
{{comment.body|markdown_to_html}}
{{comment.body|raw}}
</div>
{% endfor %}
{% endif %}
@ -86,7 +86,7 @@
<div class='card card-body mb-3'>
{% for timeline in issue.timelines %}
{% if timeline.type!="comment" and timeline.type!="project" and timeline.type!="added_deadline" and timeline.type!="modified_deadline"%}
{% if timeline.type!="comment" and timeline.type!="project" and timeline.type!="added_deadline" and timeline.type!="modified_deadline" and timeline.type!="label" %}
<li><b>{{timeline.user.login}} le {{timeline.created_at|date("d/m/Y H:i")}}</b><br>
{% if timeline.type == "change_title" %}

View File

@ -0,0 +1,196 @@
{% extends "base.html.twig" %}
{% block localstyle %}
.issuecontent {
width:75%;
}
.issuedetail {
width:25%;
padding-right: 10px;
zoom:80%;
}
.text-small {
font-size:80%;
}
.card-header, .card-body {
padding:10px;
background-color: var(--colorbgbodylight-darker);
}
.issue-body {
zoom: 80%;
}
.badge {
color: white;
zoom:120%;
}
{% endblock %}
{% block body %}
<h3 id='issuetitle{{issue.number}}' class='issuetitle'>#{{issue.number}} = {{issue.title}}</h3>
<div id='issuediv{{issue.number}}' class='d-flex'>
<div class='issuecontent' class='d-flex flex-column'>
<div class="card mb-3">
<div class="card-header d-flex">
<div class="flex-grow-1">{{issue.user.login}}</div>
<div class="text-small"> le {{issue.created_at|date("d/m/Y H:i")}}</div>
</div>
<div class='card-body issue-body'>
{{issue.body|raw}}
</div>
</div>
{% if issue.comments %}
{% for comment in issue.comments %}
<div class="card mb-3">
<div class="card-header d-flex">
<div class="flex-grow-1">{{comment.user.login}}</div>
<div class="text-small"> le {{comment.created_at|date("d/m/Y H:i")}}</div>
</div>
<div class='card-body issue-body'>
{{comment.body|raw}}
</div>
</div>
{% endfor %}
{% endif %}
</div>
<div class='pl-3 issuedetail'>
<a target="_blank" class="btn btn-success w-100 mb-3" href="{{issue.html_url}}" style="zoom:120%">Modifier dans Gitea</a>
<div class='card mb-3'>
<div class="card-header">Statut</div>
<div class="card-body">
{% if issue.closed_at %}
Clos le {{issue.closed_at|date("d/m/Y H:i")}}
{% else %}
{{issue.statuslife}}
{% endif %}
</div>
</div>
<div class='card mb-3'>
<div class="card-header">Jalon</div>
<div class="card-body">
{% if issue.milestone %}
{{ issue.milestone.title|raw }}
{% else %}
Backlog
{% endif %}
</div>
</div>
{% if issue.sprint %}
<div class='card mb-3'>
<div class="card-header">Sprint</div>
<div class="card-body">
{{ issue.sprint }}
</div>
</div>
{% endif %}
{% if issue.refs %}
<div class='card mb-3'>
<div class="card-header">Références</div>
<div class='card-body mb-3'>
{% for histo in issue.refs %}
<div>
{{histo.label|raw}}
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if issue.labels %}
<div class='card mb-3'>
<div class="card-header">Labels</div>
<div class='card-body mb-3'>
{% for label in issue.labels %}
<span class='badge mr-1 mb-1 p-2' style='background-color:#{{label.color}}'>{{label.name}}</span>
{% endfor %}
{% for histo in issue.labelhistos %}
<div class="mt-1">
<b>{{histo.user.login}} le {{histo.created_at|date("d/m/Y H:i")}}</b><br>
{{histo.label|raw}}
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if issue.timelines %}
<div class='card mb-3'>
<div class="card-header">Historique</div>
<div class="card-body">
{% for timeline in issue.timelines %}
{% if timeline.type!="label" and timeline.type!="comment" and timeline.type!="project" and timeline.type!="added_deadline" and timeline.type!="modified_deadline"%}
<li><b>{{timeline.user.login}} le {{timeline.created_at|date("d/m/Y H:i")}}</b><br>
{% if timeline.type == "change_title" %}
<div class='pl-4'>Modification titre de <i>{{timeline.old_title}}</i> à <i>{{timeline.new_title}}</i></div>
{% elseif timeline.type == "milestone" %}
{% if timeline.milestone %}
<div class='pl-4'>Affectation au Jalon <i>{{timeline.milestone.title}}</i></div>
{% else %}
<div class='pl-4'>Suppression du Jalon</div>
{% endif %}
{% elseif timeline.type == "comment_ref" or timeline.type == "pull_ref" or timeline.type == "issue_ref" %}
<div class='pl-4'>Référencé le ticket <i>#{{timeline.ref_issue.number}} - {{timeline.ref_issue.title}}</i></div>
{% elseif timeline.type == "add_dependency" %}
<div class='pl-4'>Ajouté dépendance au ticket <i>#{{timeline.dependent_issue.number}} - {{timeline.dependent_issue.title}}</i></div>
{% elseif timeline.type == "remove_dependency" %}
<div class='pl-4'>Supprimé dépendance au ticket <i>#{{timeline.dependent_issue.number}} - {{timeline.dependent_issue.title}}</i></div>
{% elseif timeline.type == "pull_push" %}
<div class='pl-4'>Ajout révision</i></div>
{% elseif timeline.type == "assignees" %}
<div class='pl-4'>Affecté intervenant <i>{{timeline.assignee.login}}</i></div>
{% elseif timeline.type == "commit_ref" %}
<div class='pl-4'>Référencé depuis commit <i>#{{timeline.body|replace({'href="/':'target="_blank" href="'~giteaUrl~'/'})|raw}}</i></div>
{% elseif timeline.type == "merge_pull" %}
<div class='pl-4'>Révision fusionnée</div>
{% elseif timeline.type == "delete_branch" %}
<div class='pl-4'>Suppression branche {{timeline.old_ref|raw}}</div>
{% elseif timeline.type == "close" %}
<div class='pl-4'>Clos <i>Fermeture du ticket</i></div>
{% elseif timeline.type == "review" %}
<div class='pl-4'>Revue acceptée</div>
{% elseif timeline.type == "review_request" %}
<div class='pl-4'>Demande de révision</div>
{% elseif timeline.type == "reopen" %}
<div class='pl-4'>Réouverture du ticket</div>
{% else %}
{{ dump(timeline) }}
{%endif%}
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
</div>
</div>
{% endblock %}

View File

@ -220,7 +220,7 @@
<div id="issu{{ issue.id }}" data-id="{{ issue.id }}" data-issue="{{ issue.id }}" data-column="{{column.gicol}}" data-milestone="{{jalon.gijal}}" data-sprint="{{sprint.idspr}}" class="card mb-1 issue issue-{{issue.id}} {{datateams}} {{datatypes}} {{dataprioritys}} {{datalabels}} {{dataassignees}} state-{{issue.giteastate}}">
<div class="card-footer p-1 d-flex" style="line-height:16px; border-top:none;">
<div class="flex-grow-1 d-flex align-items-center">
<div class="flex-grow-1 d-flex align-items-center" style="max-width:224px";>
<div class="pr-2 issu-id" style="cursor:move">#{{issue.giteanumber}} </div>
<div class="text-small" style="cursor:pointer; word-break: break-word;" onClick="$('#issu-detail{{ issue.id }}').toggle()">{{ issue.giteatitle }}</div>
</div>
@ -231,14 +231,15 @@
<div id="submenu{{issue.id}}" class="submenu" onmouseleave="issuout(this)" style="
position: absolute;
left: 230px;
top: 0px;
left: 227px;
top: -1px;
width:200px;
z-index:1200;
display:none;
background-color:#f7f7f7;
flex-direction: column;
border: 1px solid #cdcdcd;
border-radius: .25rem;
">
<a target="_blank" href="{{issue.giteajson.html_url}}" style="cursor:pointer" class="modcolumn mb-2">
@ -246,6 +247,13 @@
<span>Modifier dans Gitea</span>
</a>
<div id="viewissu{{ issue.id }}" class="viewissu mb-2" data-issue="{{ issue.id }}" data-giteaid="{{issue.giteanumber}}" data-giteatitle="{{ issue.giteatitle }}" type="button">
<i class="btn btn-link fas fa-eye p-0 m-0 fa-fw pl-1 pl-1"></i>
<span>
Aperçu Ticket
</span>
</div>
<div id="modissu{{ issue.id }}" class="modissu mb-2" data-issue="{{ issue.id }}" data-giteaid="{{issue.giteanumber}}" data-giteatitle="{{ issue.giteatitle }}" type="button">
<i class="btn btn-link fas fa-weight-hanging p-0 m-0 fa-fw pl-1 pl-1"></i>
<span>
@ -397,6 +405,7 @@
if($("#filtermilestones").val().length !== 0 && $("#filtersprints").val().length === 0) {
$("[data-milestone]").hide();
$.each($("#filtermilestones").val(), function( index, value ) {
console.log(value);
$("[data-milestone="+value+"]").show();
});
}
@ -577,6 +586,14 @@
});
});
$(document).on('click','.viewissu',function(){
$(".submenu").hide();
url="{{path('app_scrumissue_view',{id:"xxx"})}}";
url=url.replace("xxx",$(this).data("issue"));
ModalLoad('mymodallarge','Aperçu Ticket',url);
});
$("#issu_update").click(function(){
$.ajax({
method: "POST",
@ -864,7 +881,11 @@
handle: ".issu-id",
connectWith: ".scrumcolumn",
cursor: "move",
start: function( event, ui ) {
$(".submenu").hide();
},
update: function( event, ui ) {
id=$(ui.item).data("issue");
oldcolumn=$(ui.item).data("column");
oldmilestone=$(ui.item).data("milestone");
@ -941,6 +962,7 @@
});
function issuhover(btn,idissu) {
$(".submenu").hide();
$("#submenu"+idissu).css("display","flex");
}