first commit
This commit is contained in:
131
templates/base.html.twig
Normal file
131
templates/base.html.twig
Normal file
@ -0,0 +1,131 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{appName}}{% block title %}{% endblock %}</title>
|
||||
<link rel="icon" href="">
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('lib/bootstrap/css/bootstrap.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/bootswatch/bootswatch.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/fontawesome/css/all.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/datatables/datatables.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/select2/select2.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/select2/select2-bootstrap-5-theme.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/dropzone/dropzone.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/dropzone/dropzone-bootstrap.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/imgareaselect/css/imgareaselect-default.css') }}">
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('lib/app/app.css') }}">
|
||||
|
||||
<script src="{{ asset('lib/jquery/jquery.min.js') }}"></script>
|
||||
<script src="{{ asset('lib/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
|
||||
<script src="{{ asset('lib/fontawesome/fontawesome-free.index.js') }}"></script>
|
||||
<script src="{{ asset('lib/datatables/datatables.min.js') }}"></script>
|
||||
<script src="{{ asset('lib/datatables/datatables.init.js') }}"></script>
|
||||
<script src="{{ asset('lib/select2/select2.min.js') }}"></script>
|
||||
<script src="{{ asset('lib/select2/select2.init.js') }}"></script>
|
||||
<script src="{{ asset('lib/dropzone/dropzone.min.js') }}"></script>
|
||||
<script src="{{ asset('lib/imgareaselect/js/jquery.imgareaselect.dev.js') }}"></script>
|
||||
<script src="{{ asset('lib/jqueryui/jquery-ui.min.js') }}"></script>
|
||||
|
||||
<script src="{{ asset('lib/app/app.js') }}"></script>
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
{% block localstyle %}
|
||||
{% endblock %}
|
||||
|
||||
<body>
|
||||
{% if usemenu is defined and usemenu %}
|
||||
<nav class="navbar navbar-expand-lg bg-dark" data-bs-theme="dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="{{ path('app_home') }}">
|
||||
{% if app.session.get('project') %}
|
||||
<img src="{{asset(app.session.get('project').logo)}}"> Projet = {{app.session.get('project').title}}
|
||||
{% else %}
|
||||
<img src="{{asset("medias/logo/logo.png")}}"> {{appName}}
|
||||
{% endif %}
|
||||
</a>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarColor02">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="navbar-nav ms-auto ps-3 d-flex flex-row position-absolute" style="right: 15px; top:15px">
|
||||
{% if app.user %}
|
||||
<div class="nav-link">
|
||||
<select class="select2" name="selectproject" id="selectproject" style="width:200px" data-change="{{path('app_user_selectproject')}}">
|
||||
<option value="" disabled selected>Selectionnez un projet</option>
|
||||
{%for project in app.session.get('projects')%}
|
||||
<option value="{{project.id}}" {{app.session.get('project') and project.id==app.session.get('project').id?"selected":""}}>{{project.title}}</option>
|
||||
{%endfor%}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{% if is_granted('ROLE_ADMIN') %}
|
||||
<a class="nav-link px-2" href="{{path('app_admin')}}"><i class="fa-solid fa-cog fa-2x"></i></a>
|
||||
{% endif %}
|
||||
<a class="nav-link px-2" href="{{path('app_user_profil')}}"><img src="{{asset(app.user.avatar)}}" class="avatar"></a>
|
||||
<a class="nav-link px-2" href="{{path('app_logout')}}"><i class="fa-solid fa-right-from-bracket fa-2x"></i></a>
|
||||
{% else %}
|
||||
<a class="nav-link px-2" href="{{path('app_login')}}"><i class="fa-solid fa-right-to-bracket fa-2x"></i></a>
|
||||
{% endif %}
|
||||
|
||||
<a class="navbar-toggler nav-link px-2" href="#" data-bs-toggle="collapse" data-bs-target="#navbarColor02" aria-controls="navbarColor02" aria-expanded="false" aria-label="Toggle navigation"><i class="fa-solid fa-bars fa-2x"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
<main>
|
||||
{% if usesidebar is defined and usesidebar %}
|
||||
{% if is_granted('ROLE_ADMIN') %}
|
||||
<sidebar>
|
||||
<div>
|
||||
<span>GENERALE</span>
|
||||
|
||||
<a href="{{ path('app_admin_user') }}" title="Utilisateurs">
|
||||
<i class="fas fa-user fa-fw"></i>
|
||||
<span>Utilisateurs</span>
|
||||
</a>
|
||||
|
||||
<a href="{{ path('app_admin_project') }}" title="Projets">
|
||||
<i class="fas fa-building fa-fw"></i>
|
||||
<span>Projets</span>
|
||||
</a>
|
||||
</div>
|
||||
</sidebar>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<content style="margin: 0px auto; {{ (maxwidth is defined ? "max-width:"~maxwidth~"px;":"") }}">
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</content>
|
||||
</main>
|
||||
|
||||
<div id="mymodal" class="modal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">INFORMATION</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<iframe id="framemodal" frameborder=0 width="100%" height="600px"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
{% block localscript %}
|
||||
{% endblock %}
|
||||
</html>
|
1
templates/home/blank.html.twig
Normal file
1
templates/home/blank.html.twig
Normal file
@ -0,0 +1 @@
|
||||
{% extends 'base.html.twig' %}
|
309
templates/home/home.html.twig
Normal file
309
templates/home/home.html.twig
Normal file
@ -0,0 +1,309 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block localstyle %}
|
||||
<style>
|
||||
content {
|
||||
padding:0px;
|
||||
}
|
||||
.containerScrum {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.containerFiltre{
|
||||
display:flex;
|
||||
width:250px;
|
||||
flex-direction:column;
|
||||
background-color: var(--bs-dark);
|
||||
}
|
||||
|
||||
.containerStatus{
|
||||
display:flex;
|
||||
width:10000px;
|
||||
overflow-x:scrool;
|
||||
}
|
||||
|
||||
.colStatus {
|
||||
width:300px;
|
||||
padding: 15px 10px 0px 10px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:18px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
.versionCard {
|
||||
background-color: var(--bs-gray-100);
|
||||
padding: 5px 5px 0px 5px;
|
||||
}
|
||||
|
||||
.versionBody {
|
||||
min-height:60px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
color: var(--bs-primary-text-emphasis);
|
||||
font-size:16px;
|
||||
padding-left:10px;
|
||||
}
|
||||
|
||||
.issueCard {
|
||||
padding:5px;
|
||||
}
|
||||
|
||||
.issueHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.issueId{
|
||||
padding: 0px 5px 0px 2px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.issueSubject{
|
||||
zoom: 70%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class='containerScrum'>
|
||||
<div class='containerFiltre'>
|
||||
<label>Sprints</label>
|
||||
<select id="sprintFilter" class="select2 form-select" multiple="true" tabindex="-1" aria-hidden="true">
|
||||
<option value="None">Aucun</option>
|
||||
{% for sprint in project.redmine.sprints|reverse %}
|
||||
<option value="{{sprint.id}}">{{sprint.name}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label>Versions</label>
|
||||
<select id="versionFilter" class="select2 form-select" multiple="true" tabindex="-1" aria-hidden="true">
|
||||
<option value="None">Aucune</option>
|
||||
{% for version in project.redmine.versions|reverse %}
|
||||
<option value="{{version.id}}">{{version.name}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<button id="toggleIssueBody" class="btn btn-secondary btn-sm mt-3">Afficher Détail</button>
|
||||
</div>
|
||||
|
||||
<div class='containerStatus'>
|
||||
{% for status in project.redmine.issue_statuses %}
|
||||
<div class='colStatus'>
|
||||
<h2>{{ status.name }}</h2>
|
||||
|
||||
{% for sprint in project.redmine.sprints|reverse %}
|
||||
<div class='sprintCard sprintCard{{sprint.id}} card' style='margin-bottom:20px'>
|
||||
<div class='card-header'>
|
||||
Sprint = {{ sprint.name }}
|
||||
</div>
|
||||
|
||||
{% for version in project.redmine.versions|reverse %}
|
||||
<div class='versionCard versionCard{{version.id}} card-body'>
|
||||
<h5>Version = {{ version.name }}</h5>
|
||||
<div class='versionBody' data-id='{{status.id}}-{{sprint.id}}-{{version.name}}'></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class='versionCard versionCardNone card-body'>
|
||||
<h5>Version = Aucune</h5>
|
||||
<div class='versionBody' data-id='{{status.id}}-{{sprint.id}}-'></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class='sprintCard sprintCardNone card'>
|
||||
<div class='card-header'>
|
||||
Sprint Aucun
|
||||
</div>
|
||||
|
||||
{% for version in project.redmine.versions|reverse %}
|
||||
<div class='versionCard versionCard{{version.id}} card-body'>
|
||||
<h5>Version = {{ version.name }}</h5>
|
||||
<div class='versionBody' data-id='{{status.id}}--{{version.name}}'></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class='versionCard versionCardNone card-body'>
|
||||
<h5>Version = Aucune</h5>
|
||||
<div class='versionBody' data-id='{{status.id}}--'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class='viewIssue'>
|
||||
</div>
|
||||
|
||||
{% for issue in project.issues %}
|
||||
<div class="issueCard card" data-status='{{issue.redmine.status.id}}' data-sprint='{{issue.rowsprint}}' data-version='{{issue.rowversion}}'>
|
||||
<div class='issueHeader'>
|
||||
<div class='issueId'>#{{issue.id}}</div>
|
||||
<div class='issueSubject'>{{issue.redmine.subject}}</div>
|
||||
</div>
|
||||
<div class='issueBody'>
|
||||
sprint = {{issue.rowsprint}}<br>
|
||||
version = {{issue.rowversion}}<br>
|
||||
status = {{issue.redmine.status.name}}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
let showIssuebody = false;
|
||||
|
||||
function showhide() {
|
||||
// Sprint
|
||||
selected = $('#sprintFilter').val();
|
||||
if (!selected || selected.length === 0) {
|
||||
$('.sprintCard').show();
|
||||
}
|
||||
else {
|
||||
$('.sprintCard').hide();
|
||||
selected.forEach(function (id) {
|
||||
$('.sprintCard' + id).show();
|
||||
});
|
||||
}
|
||||
|
||||
// Version
|
||||
selected = $('#versionFilter').val();
|
||||
if (!selected || selected.length === 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();
|
||||
$(this).text('Afficher Détail');
|
||||
}
|
||||
showIssuebody=!showIssuebody;
|
||||
}
|
||||
|
||||
$(document).ready(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);}
|
||||
});
|
||||
$('.containerScrum').css('display', 'flex');
|
||||
|
||||
// Filtre
|
||||
$('#sprintFilter').on('change',showhide);
|
||||
$('#versionFilter').on('change',showhide);
|
||||
showhide();
|
||||
|
||||
// issueBody
|
||||
$('#toggleIssueBody').on('click',toogleIssueBody);
|
||||
toogleIssueBody();
|
||||
});
|
||||
|
||||
$(function () {
|
||||
let $sourceContainer = null;
|
||||
let $movedItem = null;
|
||||
let originalIndex = null;
|
||||
|
||||
$('.versionBody').sortable({
|
||||
connectWith: '.versionBody',
|
||||
items: '.issueCard',
|
||||
handle: '.issueId',
|
||||
placeholder: 'issue-placeholder',
|
||||
forcePlaceholderSize: true,
|
||||
|
||||
start: function (event, ui) {
|
||||
$sourceContainer = ui.item.parent();
|
||||
$movedItem = ui.item;
|
||||
originalIndex = ui.item.index();
|
||||
},
|
||||
|
||||
update: function (event, ui) {
|
||||
// ❗ Se déclenche même pour tri dans la même colonne
|
||||
if (!event.originalEvent) return; // ← ignorer les appels indirects
|
||||
const $targetContainer = $(this);
|
||||
|
||||
const sourceId = $sourceContainer.data('id');
|
||||
const targetId = $targetContainer.data('id');
|
||||
|
||||
// Ne pas dupliquer l'appel si c’est un vrai "receive"
|
||||
if (ui.sender) return;
|
||||
|
||||
sendUpdate(sourceId, targetId, $sourceContainer, $targetContainer, $movedItem, originalIndex);
|
||||
},
|
||||
|
||||
receive: function (event, ui) {
|
||||
const $targetContainer = $(this);
|
||||
const sourceId = $sourceContainer.data('id');
|
||||
const targetId = $targetContainer.data('id');
|
||||
|
||||
sendUpdate(sourceId, targetId, $sourceContainer, $targetContainer, $movedItem, originalIndex);
|
||||
}
|
||||
});
|
||||
|
||||
function sendUpdate(sourceId, targetId, $sourceContainer, $targetContainer, $movedItem, originalIndex) {
|
||||
const sourceIssues = $sourceContainer.find('.issueCard').map(function () {
|
||||
return $(this).data('id');
|
||||
}).get();
|
||||
|
||||
const targetIssues = $targetContainer.find('.issueCard').map(function () {
|
||||
return $(this).data('id');
|
||||
}).get();
|
||||
|
||||
$.ajax({
|
||||
url: '/your/route/here', // 🔁 à adapter
|
||||
method: 'POST',
|
||||
data: {
|
||||
sourceVersion: sourceId,
|
||||
targetVersion: targetId,
|
||||
sourceIssues: sourceIssues,
|
||||
targetIssues: targetIssues
|
||||
},
|
||||
success: function (response) {
|
||||
console.log('Déplacement réussi', response);
|
||||
},
|
||||
error: function (xhr) {
|
||||
console.error('Erreur AJAX', xhr);
|
||||
|
||||
// Annuler le déplacement
|
||||
if ($movedItem && $sourceContainer) {
|
||||
const items = $sourceContainer.children();
|
||||
if (originalIndex >= items.length) {
|
||||
$sourceContainer.append($movedItem);
|
||||
} else {
|
||||
$movedItem.insertBefore(items.eq(originalIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
4
templates/home/noproject.html.twig
Normal file
4
templates/home/noproject.html.twig
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{%block body%}
|
||||
<h2>Veuillez selectionner un projet</h2>
|
||||
{%endblock%}
|
13
templates/include/error.html.twig
Normal file
13
templates/include/error.html.twig
Normal file
@ -0,0 +1,13 @@
|
||||
{% for message in app.flashes('error') %}
|
||||
<div class="alert alert-danger mt-3">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if form.vars.errors is not empty %}
|
||||
<div class="alert alert-danger mt-3">
|
||||
{% for error in form.vars.errors %}
|
||||
<li>{{ error.message }}</li>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
51
templates/project/edit.html.twig
Normal file
51
templates/project/edit.html.twig
Normal file
@ -0,0 +1,51 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form.submit) }}
|
||||
<a href="{{ path(routecancel) }}" class="btn btn-secondary ms-1">Annuler</a>
|
||||
{%if mode=="update" %}<a href="{{ path(routedelete,{id:form.vars.value.id}) }}" class="btn btn-danger float-end" onclick="return confirm('Confirmez-vous la suppression de cet enregistrement ?')">Supprimer</a>{%endif%}
|
||||
|
||||
{% include('include/error.html.twig') %}
|
||||
|
||||
<div class="text-center d-flex flex-column align-items-center">
|
||||
<img id="project_logo_img" src="{{asset(form.vars.value.logo)}}" class="bigavatar mb-2">
|
||||
{{ form_row(form.logo) }}
|
||||
<a class="btn btn-info" style="max-width:100%; margin-bottom:15px;" data-bs-toggle="modal" data-bs-target="#mymodal" onClick="ModalLoad('mymodal','Logo','{{ path('app_user_upload_crop01',{endpoint:'logo',reportThumb:'project_logo'}) }}');" title='Ajouter un logo'>Modifier</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mx-auto">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.title) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mx-auto">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Permissions</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.users) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#project_title").focus();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
47
templates/project/list.html.twig
Normal file
47
templates/project/list.html.twig
Normal file
@ -0,0 +1,47 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
<a href="{{ path(routesubmit) }}" class="btn btn-success">Ajouter</a>
|
||||
|
||||
<div class="dataTable_wrapper">
|
||||
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="100px" class="no-sort">Action</th>
|
||||
<th width="70px">Logo</th>
|
||||
<th width="70px">Modifier</th>
|
||||
<th>Nom</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for project in projects %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ path(routeupdate,{id:project.id}) }}" class="me-2"><i class="fas fa-file fa-2x"></i></a>
|
||||
<a href="{{ path('app_admin_project_reclone',{id:project.id}) }}" onclick="return confirm('Es-tu sûr de vouloir reinitialiser et reindexer le projet ?');"><i class="fas fa-rotate-right fa-2x"></i></a>
|
||||
</td>
|
||||
<td><img class="avatar" src="{{ asset(project.logo)}}"></td>
|
||||
<td>{{project.title}}</td>
|
||||
<td>{{project.redmine.updated_on}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#dataTables').DataTable({
|
||||
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
|
||||
responsive: true,
|
||||
iDisplayLength: 100,
|
||||
order: [[ 2, "asc" ]]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
43
templates/security/login.html.twig
Normal file
43
templates/security/login.html.twig
Normal file
@ -0,0 +1,43 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<form method="post">
|
||||
<img src="{{asset("/medias/logo/logo.png")}}" style="margin: 15px auto 15px auto; width:100px; display:block;">
|
||||
<center style="font-size:200%;margin-bottom:30px;">{{appName}}</center>
|
||||
<div class="card card-body m-auto" style="width:300px">
|
||||
{% if error %}
|
||||
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if app.user %}
|
||||
<div class="mb-3">
|
||||
Vous êtes déjà connecté avec le login {{ app.user.userIdentifier }} = <a href="{{ path('app_logout') }}">Logout</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username">Login</label>
|
||||
<input class="form-control" type="text" value="{{ last_username }}" name="_username" id="username" class="form-control" autocomplete="username" required autofocus>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input class="form-control" type="password" name="_password" id="password" class="form-control" autocomplete="current-password" required>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
||||
|
||||
<button class="btn btn-lg btn-primary" type="submit">
|
||||
Valider
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$("#username").focus();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
48
templates/upload/crop01.html.twig
Normal file
48
templates/upload/crop01.html.twig
Normal file
@ -0,0 +1,48 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block localstyle %}
|
||||
<style>
|
||||
body {
|
||||
background-color: transparent;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<a class="btn btn-secondary" onClick="closeModal();">Annuler</a>
|
||||
<form action="{{ oneup_uploader_endpoint(endpoint) }}" class="dropzone" id="myDropzone" style="margin-top:10px">
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
Dropzone.options.myDropzone = {
|
||||
maxFiles: 1,
|
||||
acceptedMimeTypes: 'image/*',
|
||||
success: function(file, response){
|
||||
// Construction de l'url de retour
|
||||
url="{{ path('app_user_upload_crop02',{reportThumb: reportThumb, path:'xxx', file:'yyy'})|escape('js') }}";
|
||||
url=url.replace("xxx",response["path"]);
|
||||
url=url.replace("yyy",response["file"]);
|
||||
|
||||
// Navigation sur l'url de retour
|
||||
$(location).attr('href',url);
|
||||
},
|
||||
|
||||
|
||||
dictDefaultMessage: "Déposez vos fichiers ici pour les téléverser",
|
||||
dictFallbackMessage: "Votre navigateur ne supporte pas le téléversement de fichiers par glisser-déposer.",
|
||||
dictFallbackText: "Veuillez utiliser le formulaire ci-dessous pour téléverser vos fichiers.",
|
||||
dictFileTooBig: "Le fichier est trop volumineux .",
|
||||
dictInvalidFileType: "Vous ne pouvez pas téléverser des fichiers de ce type.",
|
||||
dictCancelUpload: "Annuler le téléversement",
|
||||
dictCancelUploadConfirmation: "Êtes-vous sûr de vouloir annuler ce téléversement ?",
|
||||
dictRemoveFile: "Supprimer le fichier",
|
||||
dictMaxFilesExceeded: "Vous ne pouvez pas téléverser plus de fichiers."
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
window.parent.$("#mymodal").modal('hide');
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
83
templates/upload/crop02.html.twig
Normal file
83
templates/upload/crop02.html.twig
Normal file
@ -0,0 +1,83 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block localstyle %}
|
||||
<style>
|
||||
body {
|
||||
background-color: transparent;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form.submit) }} <a class="btn btn-secondary" onClick="closeModal();">Annuler</a>
|
||||
|
||||
<div id='preview' style='overflow:hidden; width:90px; height:90px; position: absolute; top: 0px; right: 10px;'>
|
||||
<img src="{{ asset(image) }}" style='position: relative;' alt='Thumbnail Preview' />
|
||||
</div>
|
||||
|
||||
<div style="margin-top:50px;">
|
||||
<img id="largeimg" src="{{ asset(image) }}">
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
function preview(img, selection) {
|
||||
var scaleX = 90 / selection.width;
|
||||
var scaleY = 90 / selection.height;
|
||||
|
||||
$('#preview img').css({
|
||||
width: Math.round(scaleX * $('#largeimg').width()) + 'px',
|
||||
height: Math.round(scaleY * $('#largeimg').height()) + 'px',
|
||||
marginLeft: '-' + Math.round(scaleX * selection.x1) + 'px',
|
||||
marginTop: '-' + Math.round(scaleY * selection.y1) + 'px'
|
||||
});
|
||||
$('#form_x1').val(selection.x1);
|
||||
$('#form_y1').val(selection.y1);
|
||||
$('#form_x2').val(selection.x2);
|
||||
$('#form_y2').val(selection.y2);
|
||||
$('#form_w').val(selection.width);
|
||||
$('#form_h').val(selection.height);
|
||||
}
|
||||
|
||||
function reportThumb() {
|
||||
window.parent.$("#{{reportThumb}}").val("{{thumb}}");
|
||||
url="{{ asset(thumb) }}";
|
||||
window.parent.$("#{{reportThumb}}_img").attr("src",url);
|
||||
closeModal();
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
window.parent.$("#mymodal").modal('hide');
|
||||
}
|
||||
|
||||
$(window).on("load",function () {
|
||||
{% if toReport %}
|
||||
reportThumb();
|
||||
{% endif %}
|
||||
$('#largeimg').imgAreaSelect({ aspectRatio: '1:1', onSelectChange: preview });
|
||||
|
||||
|
||||
var selection = new Object();
|
||||
if($('#largeimg').height()<$('#largeimg').width()) {
|
||||
selection.width = $('#largeimg').height();
|
||||
selection.height = $('#largeimg').height();
|
||||
}
|
||||
else {
|
||||
selection.width = $('#largeimg').width();
|
||||
selection.height = $('#largeimg').width();
|
||||
}
|
||||
|
||||
selection.x1=0;
|
||||
selection.x2=0;
|
||||
selection.y1=0;
|
||||
selection.y2=0;
|
||||
|
||||
preview($('#largeimg'),selection);
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
65
templates/user/edit.html.twig
Normal file
65
templates/user/edit.html.twig
Normal file
@ -0,0 +1,65 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form.submit) }}
|
||||
<a href="{{ path(routecancel) }}" class="btn btn-secondary ms-1">Annuler</a>
|
||||
{%if mode=="update" %}<a href="{{ path(routedelete,{id:form.vars.value.id}) }}" class="btn btn-danger float-end" onclick="return confirm('Confirmez-vous la suppression de cet enregistrement ?')">Supprimer</a>{%endif%}
|
||||
|
||||
{% include('include/error.html.twig') %}
|
||||
|
||||
<div class="text-center d-flex flex-column align-items-center">
|
||||
<img id="user_avatar_img" src="{{asset(form.vars.value.avatar)}}" class="bigavatar mb-2">
|
||||
{{ form_row(form.avatar) }}
|
||||
<a class="btn btn-info" style="max-width:100%; margin-bottom:15px;" data-bs-toggle="modal" data-bs-target="#mymodal" onClick="ModalLoad('mymodal','Avatar','{{ path('app_user_upload_crop01',{endpoint:'avatar',reportThumb:'user_avatar'}) }}');" title='Ajouter un avatar'>Modifier</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mx-auto">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.username) }}
|
||||
{%if form.password is defined%}
|
||||
{{ form_row(form.password) }}
|
||||
{% endif %}
|
||||
{{ form_row(form.email) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Redmine</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.apikey) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{%if form.roles is defined%}
|
||||
<div class="col-md-6">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Permissions</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.roles) }}
|
||||
{{ form_row(form.projects) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{%endif%}
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#user_username").focus();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
54
templates/user/list.html.twig
Normal file
54
templates/user/list.html.twig
Normal file
@ -0,0 +1,54 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
<a href="{{ path(routesubmit) }}" class="btn btn-success">Ajouter</a>
|
||||
|
||||
<div class="dataTable_wrapper">
|
||||
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="70px" class="no-sort">Action</th>
|
||||
<th width="70px" class="no-sort">Avatar</th>
|
||||
<th>Login</th>
|
||||
<th>Rôles</th>
|
||||
<th>Compagnies</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td><a href="{{ path(routeupdate,{id:user.id}) }}"><i class="fas fa-file fa-2x"></i></a></td>
|
||||
<td><img class="avatar" src="{{ asset(user.avatar)}}"></td>
|
||||
<td>{{user.username}}</td>
|
||||
<td>
|
||||
{% for role in user.roles %}
|
||||
{{role}}<br>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{% for project in user.projects %}
|
||||
{{project.title}}<br>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#dataTables').DataTable({
|
||||
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
|
||||
responsive: true,
|
||||
iDisplayLength: 100,
|
||||
order: [[ 2, "asc" ]]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user