mise en oeuvre des estimations de tickets

This commit is contained in:
afornerot 2022-09-21 11:05:17 +02:00
parent 3fd8afbc8f
commit 6df0706729
11 changed files with 823 additions and 15 deletions

View File

@ -3613,6 +3613,7 @@
"mail",
"mailer"
],
"abandoned": "symfony/mailer",
"time": "2019-11-12T09:31:26+00:00"
},
{
@ -5226,6 +5227,7 @@
"symfony",
"words"
],
"abandoned": "EnglishInflector from the String component",
"time": "2020-05-20T17:43:50+00:00"
},
{
@ -7293,6 +7295,7 @@
],
"description": "Symfony SwiftmailerBundle",
"homepage": "http://symfony.com",
"abandoned": "symfony/mailer",
"time": "2019-11-14T16:18:31+00:00"
},
{
@ -8362,12 +8365,12 @@
"version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "9dc4f203e36f2b486149058bade43c851dd97451"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/9dc4f203e36f2b486149058bade43c851dd97451",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/9dc4f203e36f2b486149058bade43c851dd97451",
"reference": "9dc4f203e36f2b486149058bade43c851dd97451",
"shasum": ""
},

View File

@ -164,6 +164,11 @@ app_group_select:
path: /user/group/select
defaults: { _controller: App\Controller\GroupController:select }
#== Report =======================================================================================================
app_report:
path: /user/report/{id}
defaults: { _controller: App\Controller\ReportController:list }
#== Scrum ========================================================================================================
app_scrum:
path: /user/scrum
@ -181,6 +186,10 @@ app_scrum_stat:
path: /user/scrum/stat/{id}
defaults: { _controller: App\Controller\ScrumController:stat }
app_scrum_info:
path: /user/scrum/info/{id}
defaults: { _controller: App\Controller\ScrumController:info }
app_scrum_update:
path: /master/scrum/update/{id}
defaults: { _controller: App\Controller\ScrumController:update }
@ -265,6 +274,14 @@ app_scrumissue_order:
path: /user/scrumissue/order
defaults: { _controller: App\Controller\ScrumissueController:order }
app_scrumissue_info:
path: /user/scrumissue/info
defaults: { _controller: App\Controller\ScrumissueController:info }
app_scrumissue_update:
path: /user/scrumissue/update
defaults: { _controller: App\Controller\ScrumissueController:update }
app_scrumissue_ctrlchange:
path: /user/scrumissue/ctrlchange
defaults: { _controller: App\Controller\ScrumissueController:ctrlchange }

View File

@ -64,6 +64,19 @@ class IssueController extends AbstractController
$json=$scrum->getGiteajson();
$json["issues"]=$giteaissues;
$json["category"]=$scrum->getCategory();
foreach($json["issues"] as $key => $giteaissue) {
$issue=$em->getRepository("App:Scrumissue")->findOneBy(["giteaid"=>$giteaissue->id]);
if($issue) {
$json["issues"][$key]->weight=$issue->getWeight();
$json["issues"][$key]->issueid=$issue->getId();
$json["issues"][$key]->scrumid=$issue->getScrum()->getId();
}
else {
$json["issues"][$key]->weight=0;
$json["issues"][$key]->issueid=0;
$json["issues"][$key]->scrumid=0;
}
}
$tmp=[];
foreach($scrum->getScrumcolumns() as $column) {

View File

@ -0,0 +1,310 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\FormError;
use App\Entity\Scrum as Entity;
use App\Entity\Scrumissue as Scrumissue;
use App\Form\ScrumType as Form;
use App\Service\giteaService;
class ReportController extends AbstractController
{
public function __construct(giteaService $giteaservice) { $this->giteaservice = $giteaservice; }
public function list($id,Request $request)
{
set_time_limit(0);
$em = $this->getDoctrine()->getManager();
$scrum = $em->getRepository("App:Scrum")->find($id);
$repoid = $scrum->getGiteaid();
$repoowner = $scrum->getGiteajson()["owner"]["login"];
$reponame = $scrum->getGiteajson()["name"];
$repo=$this->giteaservice->getRepo($repoid);
$issues=$this->giteaservice->getIssues($repoowner,$reponame,"?state=all");
foreach($issues as $keyissue => $issue) {
$issues[$keyissue]->body = $this->giteaservice->markdown("/".$scrum->getGiteajson()["full_name"],"comment",$issues[$keyissue]->body);
$issues[$keyissue]->comments=$this->giteaservice->getIssueComments($repoowner,$reponame,$issue->number);
foreach($issues[$keyissue]->comments as $keycomment => $comment) {
$issues[$keyissue]->comments[$keycomment]->body=$this->giteaservice->markdown("/".$scrum->getGiteajson()["full_name"],"comment",$issues[$keyissue]->comments[$keycomment]->body);
}
$issues[$keyissue]->timelines=$this->giteaservice->getIssueTimelines($repoowner,$reponame,$issue->number);
}
// Affichage du formulaire
return $this->render('Report/list.html.twig', [
'useheader' => false,
'usesidebar' => false,
'maxwidth' => true,
'repo' => $repo,
'issues' => $issues,
]);
}
public function submit(Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data = new Entity();
// Récupérer les repos de gitea
$gitearepos=$this->giteaservice->getRepos();
// Création du formulaire
$form = $this->createForm(Form::class,$data,array("mode"=>"submit","gitearepos"=>$gitearepos));
// Récupération des data du formulaire
$form->handleRequest($request);
// Sur erreur
$this->getErrorForm(null,$form,$request,$data,"submit");
// Sur validation
if ($form->get('submit')->isClicked() && $form->isValid()) {
$data = $form->getData();
$gitearepo=$this->giteaservice->getRepo($data->getGiteaid());
$data->setGiteaname($gitearepo->full_name);
$data->setGiteajson(json_decode(json_encode($gitearepo), true));
$em->persist($data);
$em->flush();
// Retour à la liste
return $this->redirectToRoute($this->route);
}
// Affichage du formulaire
return $this->render($this->render.'edit.html.twig', [
'useheader' => true,
'usesidebar' => false,
'maxwidth' => true,
$this->data => $data,
'mode' => 'submit',
'form' => $form->createView()
]);
}
public function update($id,Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
// Récupérer les repos de gitea
$gitearepos=$this->giteaservice->getRepos();
// Création du formulaire
$form = $this->createForm(Form::class,$data,array("mode"=>"update","gitearepos"=>$gitearepos));
// Récupération des data du formulaire
$form->handleRequest($request);
// Sur erreur
$this->getErrorForm(null,$form,$request,$data,"update");
// Sur validation
if ($form->get('submit')->isClicked() && $form->isValid()) {
$data = $form->getData();
$gitearepo=$this->giteaservice->getRepo($data->getGiteaid());
$data->setGiteaname($gitearepo->full_name);
$data->setGiteajson(json_decode(json_encode($gitearepo), true));
$em->persist($data);
$em->flush();
// Retour à la liste
return $this->redirectToRoute($this->route);
}
// Affichage du formulaire
return $this->render($this->render.'edit.html.twig', [
'useheader' => true,
'usesidebar' => false,
'maxwidth' => true,
$this->data => $data,
'mode' => 'update',
'form' => $form->createView()
]);
}
public function delete($id,Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
// Controle avant suppression
$error=false;
if($id<0) $error=true;
if($error)
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
else {
$em->remove($data);
$em->flush();
// Retour à la liste
return $this->redirectToRoute($this->route);
}
}
public function view($id,Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
if(!$data) return $this->redirectToRoute($this->route);
$em->getRepository("App:Scrum")->getGitea($data,$giteaassignees,$giteacolumns,$giteamilestones,$giteateams,$giteaprioritys,$gitealabels);
// Préférences utilisateur
$filtermilestones = $em->getRepository("App:User")->getUserpreference($this->getUser(),"filtermilestones",$id);
$filterteams = $em->getRepository("App:User")->getUserpreference($this->getUser(),"filterteams",$id);
$filterprioritys = $em->getRepository("App:User")->getUserpreference($this->getUser(),"filterprioritys",$id);
$filterlabels = $em->getRepository("App:User")->getUserpreference($this->getUser(),"filterlabels",$id);
$filterassignees = $em->getRepository("App:User")->getUserpreference($this->getUser(),"filterassignees",$id);
$filterexcludes = $em->getRepository("App:User")->getUserpreference($this->getUser(),"filterexcludes",$id);
$showfilters = $em->getRepository("App:User")->getUserpreference($this->getUser(),"showfilters",$id);
return $this->render($this->render.'view.html.twig', [
'useheader' => true,
'usesidebar' => false,
'usetitle' => $data->getName(),
'giteaassignees' => $giteaassignees,
'giteacolumns' => $giteacolumns,
'giteamilestones' => $giteamilestones,
'giteateams' => $giteateams,
'giteaprioritys' => $giteaprioritys,
'gitealabels' => $gitealabels,
'filtermilestones' => $filtermilestones,
'filterteams' => $filterteams,
'filterprioritys' => $filterprioritys,
'filterlabels' => $filterlabels,
'filterassignees' => $filterassignees,
'filterexcludes' => $filterexcludes,
'showfilters' => $showfilters,
$this->data => $data,
]);
}
public function stat($id,Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
if(!$data) return $this->redirectToRoute($this->route);
$em->getRepository("App:Scrum")->getGitea($data,$giteaassignees,$giteacolumns,$giteamilestones,$giteateams,$giteaprioritys,$gitealabels);
// Préférences utilisateur
$filtermilestones = $em->getRepository("App:User")->getUserpreference($this->getUser(),"filtermilestones",$id);
$filterteams = $em->getRepository("App:User")->getUserpreference($this->getUser(),"filterteams",$id);
$showfilters = $em->getRepository("App:User")->getUserpreference($this->getUser(),"showfilters",$id);
$tbstat=[];
foreach($data->getScrumIssues() as $issue) {
$labels=$issue->getGiteajson()["labels"];
$haveteams=true;
if($filterteams) {
$haveteams=false;
foreach($filterteams as $filterteam) {
foreach($labels as $label) {
if($label["id"]==$filterteam) {
$haveteams=true;
}
}
}
}
if($haveteams) {
$idmilestone=($issue->getGiteamilestone()?$issue->getGiteamilestone():-100);
$lbmilestone=($issue->getGiteamilestone()?$issue->getGiteamilestonename():"Aucun");
if(!array_key_exists($idmilestone,$tbstat)) {
$tbstat[$idmilestone]=["id"=>$idmilestone,"name"=>$lbmilestone,"stat"=>[]];
}
if(!array_key_exists($issue->getScrumcolumn()->getId(),$tbstat[$idmilestone]["stat"])) {
$tbstat[$idmilestone]["stat"][$issue->getScrumcolumn()->getId()]=[
"id"=>$issue->getScrumcolumn()->getId(),
"label"=>$issue->getScrumcolumn()->getName(),
"total"=>0,
"color"=>"#".$issue->getScrumcolumn()->getGiteajson()["color"],
"labels"=>[],
];
}
foreach($labels as $label) {
if($issue->getScrumcolumn()->getGiteaid()!=$label["id"]) {
if(!array_key_exists($label["id"],$tbstat[$idmilestone]["stat"][$issue->getScrumcolumn()->getId()]["labels"])) {
$tbstat[$idmilestone]["stat"][$issue->getScrumcolumn()->getId()]["labels"][$label["id"]] = [
"id"=>$label["id"],
"label"=>$label["name"],
"total"=>0,
"color"=>"#".$label["color"],
];
}
$tbstat[$idmilestone]["stat"][$issue->getScrumcolumn()->getId()]["labels"][$label["id"]]["total"]++;
}
}
$tbstat[$idmilestone]["stat"][$issue->getScrumcolumn()->getId()]["total"]++;
}
}
foreach($tbstat as $k1=>$milestone) {
foreach($milestone["stat"] as $k2=>$statut) {
$keysort = array_column($tbstat[$k1]["stat"][$k2]["labels"], 'label');
array_multisort($keysort, SORT_ASC, $tbstat[$k1]["stat"][$k2]["labels"]);
}
}
return $this->render($this->render.'stat.html.twig', [
'useheader' => true,
'usesidebar' => false,
'usetitle' => $data->getName(),
'giteaassignees' => $giteaassignees,
'giteacolumns' => $giteacolumns,
'giteamilestones' => $giteamilestones,
'giteateams' => $giteateams,
'giteaprioritys' => $giteaprioritys,
'gitealabels' => $gitealabels,
'filtermilestones' => $filtermilestones,
'filterteams' => $filterteams,
'showfilters' => $showfilters,
$this->data => $data,
'tbstat' => $tbstat,
]);
}
protected function getErrorForm($id,$form,$request,$data,$mode) {
if ($form->get('submit')->isClicked()&&$mode=="delete") {
}
if ($form->get('submit')->isClicked() && $mode=="submit") {
}
if ($form->get('submit')->isClicked() && ($mode=="submit" || $mode=="update")) {
}
if ($form->get('submit')->isClicked() && !$form->isValid()) {
$this->get('session')->getFlashBag()->clear();
$errors = $form->getErrors();
foreach( $errors as $error ) {
$request->getSession()->getFlashBag()->add("error", $error->getMessage());
}
}
}
}

View File

@ -5,6 +5,7 @@ namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Form\FormError;
use App\Entity\Scrum as Entity;
@ -298,6 +299,34 @@ class ScrumController extends AbstractController
]);
}
public function info($id,Request $request)
{
$em = $this->getDoctrine()->getManager();
// Rechercher du scrum en cours
$scrum=$em->getRepository("App:Scrum")->find($id);
if(!$scrum) return new JsonResponse(['message' => 'No Issue'], 403);
$giteaissues=$this->giteaservice->getIssues($scrum->getGiteajson()["owner"]["login"],$scrum->getGiteajson()["name"]);
$weights=[];
foreach($giteaissues as $giteaissue) {
$scrumissue=$em->getRepository("App:Scrumissue")->findOneBy(["scrum"=>$scrum,"giteaid"=>$giteaissue->id]);
if($scrumissue) {
if($giteaissue->milestone) $milestoneid=$giteaissue->milestone->id;
else $milestoneid=-100;
if(!array_key_exists($milestoneid,$weights)) $weights[$milestoneid]=0;
$weights[$milestoneid]=$weights[$milestoneid]+$scrumissue->getWeight();
}
}
$output=[];
$output["weights"]=$weights;
return new JsonResponse($output);
}
protected function getErrorForm($id,$form,$request,$data,$mode) {
if ($form->get('submit')->isClicked()&&$mode=="delete") {
}

View File

@ -105,10 +105,55 @@ class ScrumissueController extends AbstractController
$em->flush();
return new JsonResponse();
}
public function info(Request $request)
{
$em = $this->getDoctrine()->getManager();
$id=$request->get('id');
// Rechercher l'issue en cours
$scrumissue=$em->getRepository("App:Scrumissue")->find($id);
if(!$scrumissue) return new JsonResponse(['message' => 'No Issue'], 403);
$output=[];
$output["weight"]=$scrumissue->getWeight();
return new JsonResponse($output);
}
public function update(Request $request)
{
$em = $this->getDoctrine()->getManager();
$id=$request->get('id');
$weight=$request->get('weight');
// Rechercher l'issue en cours
$scrumissue=$em->getRepository("App:Scrumissue")->find($id);
if(!$scrumissue) return new JsonResponse(['message' => 'No Issue'], 403);
$scrumissue->setWeight($weight);
$em->flush();
$giteaissues=$this->giteaservice->getIssues($scrumissue->getScrum()->getGiteajson()["owner"]["login"],$scrumissue->getScrum()->getGiteajson()["name"]);
$weights=[];
foreach($giteaissues as $giteaissue) {
$issue=$em->getRepository("App:Scrumissue")->findOneBy(["scrum"=>$scrumissue->getScrum(),"giteaid"=>$giteaissue->id]);
if($issue) {
if($giteaissue->milestone) $milestoneid=$giteaissue->milestone->id;
else $milestoneid=-100;
if(!array_key_exists($milestoneid,$weights)) $weights[$milestoneid]=0;
$weights[$milestoneid]=$weights[$milestoneid]+$issue->getWeight();
}
}
return new JsonResponse($weights);
}
public function ctrlchange(Request $request)
{
$em = $this->getDoctrine()->getManager();

View File

@ -26,6 +26,11 @@ class Scrumissue
*/
private $rowid;
/**
* @ORM\Column(type="integer")
*/
private $weight=0;
/**
* @ORM\Column(type="integer")
*/
@ -198,5 +203,17 @@ class Scrumissue
return $this;
}
public function getWeight(): ?int
{
return $this->weight;
}
public function setWeight(int $weight): self
{
$this->weight = $weight;
return $this;
}
}

View File

@ -10,10 +10,12 @@ class giteaService
private $params;
private $session;
private $url;
private $giteaUrl;
public function __construct(SessionInterface $session,ParameterBagInterface $params,$giteaUrl)
{
$this->params = $params;
$this->giteaUrl = $giteaUrl;
$this->url = $giteaUrl."/api/v1";
$this->session = $session;
}
@ -29,6 +31,7 @@ class giteaService
];
$body = \Unirest\Request\Body::json($query);
$response=$this->api("POST",$apiurl,$body);
if(!$response||$response->code!="200") return false;
@ -38,6 +41,31 @@ class giteaService
}
}
public function deletetoken($username) {
$apiurl=$this->url."/users/".$username."/tokens/".$this->session->get("giteatoken");
$response=$this->api("DELETE",$apiurl,null,$this->session->get("giteatoken"));
}
public function markdown($context,$mode,$body) {
$apiurl = $this->url."/markdown";
$query= [
"Context" => $context,
"Mode" => $mode,
"Text" => $body,
"Wiki" => false,
];
$body = \Unirest\Request\Body::json($query);
$response=$this->api("POST",$apiurl,$body,$this->session->get("giteatoken"));
if(!$response||$response->code!="200") return false;
else {
$response->body= str_replace($this->giteaUrl,$this->giteaUrl.$context,$response->body);
return $response->body;
}
}
public function getuser() {
$apiurl = $this->url."/user";
$response=$this->api("GET",$apiurl,null,$this->session->get("giteatoken"));
@ -48,7 +76,6 @@ class giteaService
public function getuserprofil($id) {
$apiurl = $this->url."/users/$id";
$response=$this->api("GET",$apiurl,null,$this->session->get("giteatoken"));
dump($response);
if(!$response||$response->code!="200") return false;
else return $response->body;
}
@ -156,8 +183,9 @@ class giteaService
else return $response->body;
}
public function getissues($owner,$name) {
$apiurl = $this->url."/repos/$owner/$name/issues?state=open";
public function getissues($owner,$name,$state="?state=open") {
$apiurl = $this->url."/repos/$owner/$name/issues".$state;
$page=1;
$limit=20;
$issues=[];
@ -210,11 +238,25 @@ class giteaService
$apiurl = $this->url."/repos/$owner/$name/issues/$index";
$body = \Unirest\Request\Body::json($patchs);
$response=$this->api("PATCH",$apiurl,$body,$this->session->get("giteatoken"));
dump($response);
if(!$response||$response->code!="201") return false;
else return $response->body;
}
public function getissuecomments($owner,$name,$index) {
$apiurl = $this->url."/repos/$owner/$name/issues/$index/comments";
$response=$this->api("GET",$apiurl,null,$this->session->get("giteatoken"));
if(!$response||$response->code!="200") return false;
else return $response->body;
}
public function getissuetimelines($owner,$name,$index) {
$apiurl = $this->url."/repos/$owner/$name/issues/$index/timeline";
$response=$this->api("GET",$apiurl,null,$this->session->get("giteatoken"));
if(!$response||$response->code!="200") return false;
else return $response->body;
}
private function api($method,$url,$query,$token=null) {
// Entete
$headers = [

View File

@ -146,6 +146,7 @@
<th style="width:1000px">Titre</th>
<th style="width:200px">Equipe</th>
<th style="width:250px">Priorité</th>
<th style="width:70px">Poid</th>
<th style="width:135px">Affecté à</th>
<th style="width:135px">Statut</th>
<th style="width:300px">Etiquettes</th>
@ -204,6 +205,13 @@
<td><a target="_blank" href="{{giteaissue.html_url}}">{{ giteaissue.title }}</a></td>
<td>{{ teams|raw }}</td>
<td>{{ prioritys|raw }}</td>
<td>
<div id="modissu{{ giteaissue.issueid }}" data-issue="{{ giteaissue.issueid }}" data-giteaid="{{giteaissue.number}}" data-giteatitle="{{ giteaissue.title }}" type="button" class="modissu btn btn-link">
<i class="fas fa-weight-hanging"></i> = <span id="issue{{giteaissue.issueid}}-weight">{{ giteaissue.weight }}</span>
</div>
</td>
{% set dataorder="" %}
{% for assignee in giteaissue.assignees %}
{% set dataorder=dataorder~assignee.username %}
@ -224,6 +232,31 @@
</table>
</div>
</div>
<div id="mymodalissue" class="modal" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group ">
<label class="control-label required" for="issu_weight">
Poid
</label>
<input type="hidden" id="modal-issueid" name="modal-issueid" required="required" class=" form-control" value="">
<input type="integer" id="modal-issueweight" name="modal-issueweight" required="required" class=" form-control" value="">
</div>
<button id="issu_update" class="btn btn-success">Enregistrer</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
@ -580,6 +613,58 @@
showhide();
}
function refreshinfo() {
$.ajax({
method: "POST",
url: "{{path("app_scrum_info",{id:id})}}",
success: function(data) {
$(".totalweight").html("0");
Object.entries(data.weights).forEach(entry => {
const [key, value] = entry;
$("#total"+key).html(value);
});
}
});
}
$(document).on('click','.modissu',function(){
$(".modal-title").html("#"+$(this).data("giteaid")+" - "+$(this).data("giteatitle"));
$("#modal-issueid").val($(this).data("issue"));
$.ajax({
method: "POST",
url: "{{path("app_scrumissue_info")}}",
data: {
id:$("#modal-issueid").val(),
},
success: function(data) {
$("#modal-issueweight").val(data.weight);
$("#mymodalissue").modal('show');
$("#modal-issueweight").focus();
},
});
});
$("#issu_update").click(function(){
$.ajax({
method: "POST",
url: "{{path("app_scrumissue_update")}}",
data: {
id:$("#modal-issueid").val(),
weight:$("#modal-issueweight").val(),
},
success: function(data) {
$("#issue"+$("#modal-issueid").val()+"-weight").html($("#modal-issueweight").val());
refreshinfo();
$("#mymodalissue").modal('hide');
},
error: function (request, status, error) {
$("#mymodalissue").modal('hide');
}
});
});
$(document).ready(function() {
{% if id== 0 %}
$('#filtercategorys').select2();
@ -725,7 +810,8 @@
$("#filters").removeClass("d-flex");
{% endif %}
showhide();
showhide();
$("#mycontent").show();
});
{% endblock %}

View File

@ -0,0 +1,153 @@
{% extends "base.html.twig" %}
{% block localstyle %}
body {
background-color: #efefef;
}
.issuetitle {
margin-top:100px;
page-break-before: always;
}
.issuediv {
zoom:60%;
}
.issuecontent {
width:80%;
}
.issuedetail {
width:20%;
}
@media print {
body {
background-color: transparent;
}
}
{% endblock %}
{% block body %}
<h1>{{repo.full_name}}</h1>
{% for issue in issues %}
<h2 id='issuetitle{{issue.number}}' class='issuetitle'>#{{issue.number}} = {{issue.title}}</h2>
<div id='issuediv{{issue.number}}' class='issuediv d-flex'>";
<div class='issuecontent'>
<h3>{{issue.user.login}} le {{issue.created_at|date("d/m/Y H:i")}}</h3>
<div class='card card-body'>
{{issue.body|raw}}
</div>
{% if issue.comments %}
{% 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|raw}}
</div>
{% endfor %}
{% endif %}
</div>
<div class='pl-3 issuedetail'>
<h3>Statut</h3>
<div class='card card-body mb-3'>
{% if issue.closed_at %}
Clos le {{issue.closed_at|date("d/m/Y H:i")}}
{% else %}
En Cours
{% endif %}
</div>
<h3>Jalon</h3>
<div class='card card-body mb-3'>
{% if issue.milestone %}
{{ issue.milestone.title|raw }}
{% else %}
Backlog
{% endif %}
</div>
{% if issue.labels %}
<h3>Labels</h3>
<div class='card'>
<div class='card-body mb-3'>
{% for label in issue.labels %}
<span class='badge mr-2 mb-2 p-2' style='background-color:#{{label.color}}'>{{label.name}}</span>
{% endfor%}
</div>
</div>
{% endif %}
{% if issue.timelines %}
<h3>Historique</h3>
<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"%}
<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 == "label" %}
<div class='pl-4'>Affectation au Label <i>{{timeline.label.name}}</i></div>
{% 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 révision <i>#{{timeline.body|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>
{% endif %}
</div>
</div>
{% endfor %}
{% endblock %}

View File

@ -98,7 +98,15 @@
<option value="{{gitealabel.id}}">{{gitealabel.name}}</option>
{% endfor %}
</select>
</div>
</div>
<div style="color:var(--colorftbodydark)" class="mt-5">
{% for giteamilestone in giteamilestones %}
{{giteamilestone.title}} = <span id="total{{giteamilestone.id}}" class="totalweight">0</span><br>
{% endfor %}
Aucun = <span id="total-100" class="totalweight">0</span><br>
</div>
</div>
<div class="pl-3" style="width:100%;">
@ -164,7 +172,7 @@
{% set dataassignees=dataassignees~"dataassignee"~assignee.id~" " %}
{% endfor %}
<div data-id="{{ issue.id }}" data-issue="{{ issue.id }}" data-column="{{column.giteaid}}" data-milestone="{{idmilestone}}" class="card mb-1 issue issue-{{issue.id}} {{datateams}} {{dataprioritys}} {{datalabels}} {{dataassignees}}">
<div id="issu{{ issue.id }}" data-id="{{ issue.id }}" data-issue="{{ issue.id }}" data-column="{{column.giteaid}}" data-milestone="{{idmilestone}}" class="card mb-1 issue issue-{{issue.id}} {{datateams}} {{dataprioritys}} {{datalabels}} {{dataassignees}}">
<div class="card-footer p-1" style="line-height:10px; border-top:none;">
<div class="float-left btn btn-link p-0 m-0 fas fa-arrows-alt" style="cursor:move"></div>
<a target="_blank" class="modcolumn btn btn-link float-right fa fa-file p-0 m-0" href="{{issue.giteajson.html_url}}"></a>
@ -208,6 +216,10 @@
<img src="{{assignee.avatar_url}}" class="assignee" title="{{assignee.username}}">
{% endfor %}
</div>
<div id="modissu{{ issue.id }}" data-issue="{{ issue.id }}" data-giteaid="{{issue.giteanumber}}" data-giteatitle="{{ issue.giteatitle }}" type="button" class="modissu btn btn-link float-right">
<i class="fas fa-weight-hanging"></i> = <span id="issue{{issue.id}}-weight">{{ issue.weight }}</span>
</div>
</small>
</div>
</div>
@ -234,9 +246,36 @@
{% endfor %}
</div>
</div>
<div id="mymodalissue" class="modal" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group ">
<label class="control-label required" for="issu_weight">
Poid
</label>
<input type="hidden" id="modal-issueid" name="modal-issueid" required="required" class=" form-control" value="">
<input type="integer" id="modal-issueweight" name="modal-issueweight" required="required" class=" form-control" value="">
</div>
<button id="issu_update" class="btn btn-success">Enregistrer</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
function showFilters() {
if($("#filters").hasClass("d-flex")) {
toshow=0;
@ -374,9 +413,61 @@
});
}
$("#textfilters").html(textfilters);
$("#textfilters").html(textfilters);
}
function refreshinfo() {
$.ajax({
method: "POST",
url: "{{path("app_scrum_info",{id:scrum.id})}}",
success: function(data) {
$(".totalweight").html("0");
Object.entries(data.weights).forEach(entry => {
const [key, value] = entry;
$("#total"+key).html(value);
});
}
});
}
$(document).on('click','.modissu',function(){
$(".modal-title").html("#"+$(this).data("giteaid")+" - "+$(this).data("giteatitle"));
$("#modal-issueid").val($(this).data("issue"));
$.ajax({
method: "POST",
url: "{{path("app_scrumissue_info")}}",
data: {
id:$("#modal-issueid").val(),
},
success: function(data) {
$("#modal-issueweight").val(data.weight);
$("#mymodalissue").modal('show');
$("#modal-issueweight").focus();
},
});
});
$("#issu_update").click(function(){
$.ajax({
method: "POST",
url: "{{path("app_scrumissue_update")}}",
data: {
id:$("#modal-issueid").val(),
weight:$("#modal-issueweight").val(),
},
success: function(data) {
$("#issue"+$("#modal-issueid").val()+"-weight").html($("#modal-issueweight").val());
refreshinfo();
$("#mymodalissue").modal('hide');
},
error: function (request, status, error) {
$("#mymodalissue").modal('hide');
}
});
});
// Filter Milestones
function filtermilestones() {
$.ajax({
@ -556,6 +647,7 @@
// Appliy filters
showhide();
refreshinfo();
$("#mycontent").show();
lastupdate="{{scrum.updatedate|date("Ymd H:i:s")}}";
@ -589,6 +681,8 @@
$(ui.item).data("column",newcolumn);
$(ui.item).data("milestone",newmilestone);
if(data) lastupdate=data;
refreshinfo();
},
error: function (request, status, error) {
$( ".scrumcolumn" ).sortable('cancel');
@ -604,7 +698,6 @@
}
});
console.log(lstordered);
$.ajax({
method: "POST",
url: "{{path("app_scrumissue_order")}}",
@ -612,8 +705,8 @@
id:{{scrum.id}},
lstordered:lstordered,
}
});
}
});
},
});