svg
This commit is contained in:
@ -69,13 +69,21 @@ class IssueController extends AbstractController
|
|||||||
return new JsonResponse(['message' => 'Erreur Redmine : Déplacement Interdit'], 400);
|
return new JsonResponse(['message' => 'Erreur Redmine : Déplacement Interdit'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$payload = [
|
$payload = [
|
||||||
'fixed_version_id' => $targetVersion,
|
'fixed_version_id' => $targetVersion,
|
||||||
'agile_data_attributes' => ['agile_sprint_id' => $targetSprint],
|
'agile_data_attributes' => ['agile_sprint_id' => $targetSprint],
|
||||||
'status_id' => $targetStatus,
|
'status_id' => $targetStatus,
|
||||||
];
|
];
|
||||||
$this->redmineService->updateIssue($id, $payload, $this->getParameter('redmineApikey'));
|
$this->redmineService->updateIssue($id, $payload, $this->getUser()->getApikey());
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
// Récupère le message de l'exception
|
||||||
|
$errorMessage = $e->getMessage();
|
||||||
|
dump($e->getMessage());
|
||||||
|
|
||||||
|
// Par exemple, retour JSON d'erreur :
|
||||||
|
return new JsonResponse(['message' => $errorMessage], 400);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
$payload =
|
$payload =
|
||||||
[
|
[
|
||||||
|
@ -299,7 +299,7 @@ class RedmineService
|
|||||||
public function getIssue(int $issueId, string $apiKey): array
|
public function getIssue(int $issueId, string $apiKey): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$url = "{$this->baseUrl}/issues/{$issueId}.json?include=allowed_statuses";
|
$url = "{$this->baseUrl}/issues/{$issueId}.json?include=allowed_statuses,journals";
|
||||||
|
|
||||||
$response = $this->client->request('GET', $url, [
|
$response = $this->client->request('GET', $url, [
|
||||||
'headers' => [
|
'headers' => [
|
||||||
@ -345,7 +345,7 @@ class RedmineService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateIssue(int $id, array $data, string $apiKey): array
|
public function updateIssue(int $id, array $data, ?string $apiKey): array
|
||||||
{
|
{
|
||||||
$url = $this->baseUrl.'/issues/'.$id.'.json';
|
$url = $this->baseUrl.'/issues/'.$id.'.json';
|
||||||
|
|
||||||
@ -358,25 +358,15 @@ class RedmineService
|
|||||||
'json' => ['issue' => $data],
|
'json' => ['issue' => $data],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$statusCode = $response->getStatusCode();
|
if (200 !== $response->getStatusCode()) {
|
||||||
$content = trim($response->getContent(false));
|
if (401 === $response->getStatusCode()) {
|
||||||
|
throw new \RuntimeException('Erreur Redmine ('.$response->getStatusCode().') : Opération non autorisée, avez-vous placé votre apikey redmine sur votre profil');
|
||||||
// Si vide et code 200, c’est peut-être une réussite silencieuse
|
|
||||||
if ('' === $content) {
|
|
||||||
return ['success' => true, 'message' => 'OK, mais pas de contenu'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$decoded = json_decode($content, true);
|
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
|
||||||
|
|
||||||
if (isset($decoded['errors']) && is_array($decoded['errors']) && count($decoded['errors']) > 0) {
|
|
||||||
throw new \RuntimeException('Erreur Redmine : '.implode(', ', $decoded['errors']));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $decoded;
|
return $response->toArray();
|
||||||
} catch (ClientExceptionInterface|ServerExceptionInterface $e) {
|
|
||||||
// Erreur HTTP (4xx ou 5xx)
|
|
||||||
$errorBody = $e->getResponse()->getContent(false);
|
|
||||||
throw new \RuntimeException('Erreur Redmine: '.$errorBody, $e->getCode(), $e);
|
|
||||||
} catch (TransportExceptionInterface $e) {
|
} catch (TransportExceptionInterface $e) {
|
||||||
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
|
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,15 @@
|
|||||||
<div class="btn btn-secondary" onClick="hideIssue()"><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>
|
|
||||||
|
<div class="d-flex">
|
||||||
|
<small class="text-muted" style="flex-grow:1">Projet : {{ issue.redmine.project.name }} • Tracker : {{ issue.redmine.tracker.name }}</small>
|
||||||
|
{% for field in issue.redmine.custom_fields %}
|
||||||
|
{% if field.id==11 and field.value!="" %}
|
||||||
|
<small class="text-muted"><strong>{{ field.name }} =</strong> <a href="{{field.value}}" target="_blank">{{field.value|split('/')|last}}</a></small>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="issueDescription card-body" style="height:500px;overflow-y:auto">
|
<div class="issueDescription card-body" style="height:500px;overflow-y:auto">
|
||||||
@ -44,36 +52,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{% for field in issue.redmine.custom_fields %}
|
||||||
|
{% if field.id==32 %}
|
||||||
|
<hr>
|
||||||
|
<strong>{{ field.name }} </strong><br>
|
||||||
|
{{ field.value|textile_to_html|raw }}<br>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if issue.redmine.description %}
|
{% if issue.redmine.description %}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<hr>
|
<hr>
|
||||||
<strong>Description :</strong>
|
<strong>Description :</strong>
|
||||||
<p>{{ issue.redmine.description|textile_to_html|raw }}</p>
|
<p>{{ issue.redmine.description|textile_to_html|raw }}</p>
|
||||||
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if issue.redmine.custom_fields|length %}
|
{% for journal in issue.redmine.journals %}
|
||||||
<div class="mb-3">
|
{% if journal.notes != "" %}
|
||||||
<hr>
|
<div class="card">
|
||||||
<strong>Champs personnalisés :</strong>
|
<div class="card-header">
|
||||||
<ul class="list-group">
|
<strong>Auteur =</strong> {{journal.user.name}}</strong><br>
|
||||||
{% for field in issue.redmine.custom_fields %}
|
<small class="text-muted">Créé le =</strong>{{ journal.created_on|date('d/m/Y H:i') }}</small>
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
</div>
|
||||||
{{ field.name }}
|
<div class="card-body">
|
||||||
<span class="text-muted">
|
{{ journal.notes |textile_to_html|raw }}
|
||||||
{% if field.multiple is defined and field.multiple and field.value is iterable %}
|
</div>
|
||||||
{{ field.value|join(', ') }}
|
|
||||||
{% elseif field.value %}
|
|
||||||
{{ field.value }}
|
|
||||||
{% else %}
|
|
||||||
<em>—</em>
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<hr>
|
||||||
|
|
||||||
{{dump(issue)}}
|
{{dump(issue)}}
|
||||||
<br><br>
|
<br><br>
|
||||||
|
@ -192,8 +192,9 @@
|
|||||||
<div class='filtreContainer'>
|
<div class='filtreContainer'>
|
||||||
<label>Issue</label>
|
<label>Issue</label>
|
||||||
<input type="number" id="issueSearchInput" class="form-control" placeholder="Rechercher une issue" />
|
<input type="number" id="issueSearchInput" class="form-control" placeholder="Rechercher une issue" />
|
||||||
|
<a href="{{redmineUrl}}/projects/{{project.id}}/issues/new" target="_blank" class="btn btn-primary btn-sm"><i class="fas fa-file"></i> Nouvelle Demande</a>
|
||||||
|
|
||||||
<label>Statut</label>
|
<label style="margin-top:30px">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 %}
|
||||||
{% if statut.id not in project.hiddenstatuses %}
|
{% if statut.id not in project.hiddenstatuses %}
|
||||||
@ -381,9 +382,10 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Scroll horizontal (retourne une promesse)
|
// Scroll horizontal (retourne une promesse)
|
||||||
|
let paddingLeft = parseInt($('.scrumContainer').css('padding-left'), 315);
|
||||||
const scrollLeftPromise = new Promise(resolve => {
|
const scrollLeftPromise = new Promise(resolve => {
|
||||||
$('html, body').animate({
|
$('html, body').animate({
|
||||||
scrollLeft: $element.offset().left - 315
|
scrollLeft: $element.offset().left - paddingLeft
|
||||||
}, 500, resolve);
|
}, 500, resolve);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -530,7 +532,7 @@
|
|||||||
localStorage.removeItem(viewedIssueKey);
|
localStorage.removeItem(viewedIssueKey);
|
||||||
|
|
||||||
$('.issueContainer').hide();
|
$('.issueContainer').hide();
|
||||||
$('.scrumContainer').css('padding-left','0px');
|
$('.scrumContainer').css('padding-left','300px');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filtre sur les issues et backup des filtres en localstorage
|
// Filtre sur les issues et backup des filtres en localstorage
|
||||||
|
Reference in New Issue
Block a user