236 lines
8.6 KiB
JavaScript
236 lines
8.6 KiB
JavaScript
import {Controller} from '@hotwired/stimulus';
|
|
import { Modal } from "bootstrap";
|
|
import {TabulatorFull as Tabulator} from 'tabulator-tables';
|
|
import {eyeIconLink, pencilIcon, TABULATOR_FR_LANG, trashIcon} from "../js/global.js";
|
|
import base_controller from "./base_controller.js";
|
|
|
|
|
|
export default class extends base_controller {
|
|
static values = {
|
|
listProject : Boolean,
|
|
orgId: Number,
|
|
admin: Boolean
|
|
}
|
|
static targets = ["modal", "appList", "nameInput", "formTitle"];
|
|
connect(){
|
|
if(this.listProjectValue){
|
|
this.table();
|
|
}
|
|
this.modal = new Modal(this.modalTarget);
|
|
}
|
|
|
|
table(){
|
|
const columns = [
|
|
{title: "<b>ID</b> ", field: "id", visible: false},
|
|
{title: "<b>Nom du projet</b> ", field: "name", headerFilter: "input", widthGrow: 2, vertAlign: "middle"},
|
|
{
|
|
title: "Applications",
|
|
field: "applications",
|
|
headerSort: false,
|
|
hozAlign: "left",
|
|
formatter: (cell) => {
|
|
const apps = cell.getValue();
|
|
if (!apps || apps.length === 0) {
|
|
return "<span class='text-muted' style='font-size: 0.8rem;'>Aucune</span>";
|
|
}
|
|
|
|
// Wrap everything in a flex container to keep them on one line
|
|
const content = apps.map(app => `
|
|
<div class="me-1" title="${app.name}">
|
|
<img src="${app.logoMiniUrl}"
|
|
alt="${app.name}"
|
|
style="height: 35px; width: 35px; object-fit: contain; border-radius: 4px;">
|
|
</div>
|
|
`).join('');
|
|
|
|
return `<div class="d-flex flex-wrap align-items-center">${content}</div>`;
|
|
}
|
|
}
|
|
];
|
|
// 2. Add the conditional column if admin value is true
|
|
if (this.adminValue) {
|
|
columns.push({
|
|
title: "<b>Base de données</b>",
|
|
field: "bddName",
|
|
hozAlign: "left",
|
|
},
|
|
{
|
|
title: "<b>Actions</b>",
|
|
field: "id",
|
|
width: 120,
|
|
hozAlign: "center",
|
|
headerSort: false,
|
|
formatter: (cell) => {
|
|
const id = cell.getValue();
|
|
// Return a button that Stimulus can listen to
|
|
return `<div class="d-flex gap-2 align-content-center">
|
|
<button class="btn btn-link p-0 border-0" data-action="click->project#openEditModal"
|
|
data-id="${id}">
|
|
${pencilIcon()}</button>
|
|
<button class="btn btn-link p-0 border-0" data-action="click->project#deleteProject"
|
|
data-id="${id}"> ${trashIcon()} </button>
|
|
</div>`;
|
|
}
|
|
});
|
|
}
|
|
|
|
const tabulator = new Tabulator("#tabulator-projectListOrganization", {
|
|
langs: TABULATOR_FR_LANG,
|
|
locale: "fr",
|
|
ajaxURL: `/project/organization/data`,
|
|
ajaxConfig: "GET",
|
|
pagination: true,
|
|
paginationMode: "remote",
|
|
paginationSize: 15,
|
|
|
|
ajaxParams: {orgId: this.orgIdValue},
|
|
ajaxResponse: (url, params, response) => response,
|
|
paginationDataSent: {page: "page", size: "size"},
|
|
paginationDataReceived: {last_page: "last_page"},
|
|
|
|
ajaxSorting: true,
|
|
ajaxFiltering: true,
|
|
filterMode: "remote",
|
|
|
|
ajaxURLGenerator: function(url, config, params) {
|
|
let queryParams = new URLSearchParams();
|
|
queryParams.append('orgId', params.orgId);
|
|
queryParams.append('page', params.page || 1);
|
|
queryParams.append('size', params.size || 15);
|
|
|
|
// Add filters
|
|
if (params.filter) {
|
|
params.filter.forEach(filter => {
|
|
queryParams.append(`filter[${filter.field}]`, filter.value);
|
|
});
|
|
}
|
|
|
|
return `${url}?${queryParams.toString()}`;
|
|
},
|
|
rowHeight: 60,
|
|
layout: "fitColumns", // activate French
|
|
|
|
columns
|
|
})
|
|
}
|
|
|
|
|
|
async loadApplications() {
|
|
try {
|
|
const response = await fetch('/application/data/all');
|
|
const apps = await response.json();
|
|
|
|
this.appListTarget.innerHTML = apps.map(app => `
|
|
<div class="col-md-4 mb-3">
|
|
<div class="form-check border p-2 rounded d-flex align-items-center gap-2">
|
|
<input class="form-check-input ms-1" type="checkbox" name="applications[]" value="${app.id}" id="app_${app.id}">
|
|
<label class="form-check-label d-flex align-items-center gap-2" for="app_${app.id}">
|
|
<img src="${app.logoMiniUrl}" alt="${app.name}" style="height: 20px; width: 20px; object-fit: contain;">
|
|
${app.name}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
} catch (error) {
|
|
this.appListTarget.innerHTML = '<div class="text-danger">Erreur de chargement.</div>';
|
|
}
|
|
}
|
|
|
|
async submitForm(event) {
|
|
event.preventDefault();
|
|
const formData = new FormData(event.target);
|
|
|
|
const payload = {
|
|
organizationId: this.orgIdValue,
|
|
applications: formData.getAll('applications[]')
|
|
};
|
|
|
|
// Only include name if it wasn't disabled (new projects)
|
|
if (!this.nameInputTarget.disabled) {
|
|
payload.name = formData.get('name');
|
|
}
|
|
|
|
const url = this.currentProjectId
|
|
? `/project/edit/${this.currentProjectId}/ajax`
|
|
: `/project/new/ajax`;
|
|
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload)
|
|
});
|
|
|
|
if (response.ok) {
|
|
this.modal.hide();
|
|
// Use Tabulator's setData() instead of reload() for better UX if possible
|
|
location.reload();
|
|
} else {
|
|
if (response.status === 409) {
|
|
alert("Un projet avec ce nom existe déjà. Veuillez choisir un nom différent.");
|
|
}
|
|
}
|
|
}
|
|
|
|
async openEditModal(event) {
|
|
const projectId = event.currentTarget.dataset.id;
|
|
this.currentProjectId = projectId;
|
|
|
|
this.modal.show();
|
|
|
|
this.nameInputTarget.disabled = true;
|
|
this.formTitleTarget.textContent = "Modifier le projet";
|
|
|
|
try {
|
|
// 1. Ensure checkboxes are loaded first
|
|
const apps = await this.fetchAndRenderApplications(this.appListTarget);
|
|
// 2. Fetch the project data
|
|
const response = await fetch(`/project/data/${projectId}`);
|
|
const project = await response.json();
|
|
|
|
// 3. Set the name
|
|
this.nameInputTarget.value = project.name;
|
|
|
|
// 4. Check the boxes
|
|
// We look for all checkboxes inside our appList target
|
|
const checkboxes = this.appListTarget.querySelectorAll('input[type="checkbox"]');
|
|
|
|
checkboxes.forEach(cb => {
|
|
cb.checked = project.applications.includes(cb.value);
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error("Error loading project data", error);
|
|
alert("Erreur lors de la récupération des données du projet.");
|
|
}
|
|
}
|
|
// Update your openCreateModal to reset the state
|
|
async openCreateModal() {
|
|
this.currentProjectId = null;
|
|
this.modal.show();
|
|
this.nameInputTarget.disabled = false;
|
|
this.nameInputTarget.value = "";
|
|
this.formTitleTarget.textContent = "Nouveau Projet";
|
|
await this.fetchAndRenderApplications();
|
|
}
|
|
|
|
async deleteProject(event) {
|
|
const projectId = event.currentTarget.dataset.id;
|
|
if (!confirm("Êtes-vous sûr de vouloir supprimer ce projet ?")) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/project/delete/${projectId}/ajax`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
|
|
if (response.ok) {
|
|
location.reload();
|
|
}
|
|
}catch (error) {
|
|
console.error("Error deleting project", error);
|
|
alert("Erreur lors de la suppression du projet.");
|
|
}
|
|
}
|
|
} |