refactor(home, process): standardize import statements, enhance code readability, and improve error handling in Home and ProcessList components

This commit is contained in:
NicolasCantu 2025-11-28 00:13:14 +01:00
parent d45cf7c530
commit e1d220596e
3 changed files with 237 additions and 287 deletions

View File

@ -1,14 +1,19 @@
// src/pages/process/Home.ts // src/pages/process/Home.ts
import Services from '../../services/service'; import Services from "../../services/service";
import globalCss from '../../assets/styles/style.css?inline'; import globalCss from "../../assets/styles/style.css?inline";
import homeHtml from './home.html?raw'; import homeHtml from "./home.html?raw";
import { displayEmojis, generateCreateBtn, prepareAndSendPairingTx, addressToEmoji } from '../../utils/sp-address.utils'; import {
import { Router } from '../../router/index'; displayEmojis,
generateCreateBtn,
prepareAndSendPairingTx,
addressToEmoji,
} from "../../utils/sp-address.utils";
import { Router } from "../../router/index";
export class HomePage extends HTMLElement { export class HomePage extends HTMLElement {
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: 'open' }); this.attachShadow({ mode: "open" });
} }
connectedCallback() { connectedCallback() {
@ -120,26 +125,36 @@ export class HomePage extends HTMLElement {
const container = this.shadowRoot; const container = this.shadowRoot;
if (!container) return; if (!container) return;
(window as any).__PAIRING_READY = false; const loaderDiv = container.querySelector(
const loaderDiv = container.querySelector('#iframe-loader') as HTMLDivElement; "#iframe-loader"
const mainContentDiv = container.querySelector('#main-content') as HTMLDivElement; ) as HTMLDivElement;
const tabs = container.querySelectorAll('.tab'); const mainContentDiv = container.querySelector(
"#main-content"
) as HTMLDivElement;
const tabs = container.querySelectorAll(".tab");
tabs.forEach((tab) => { tabs.forEach((tab) => {
tab.addEventListener('click', () => { tab.addEventListener("click", () => {
// Remplacement de addSubscription pour simplifier ici // Remplacement de addSubscription pour simplifier ici
container.querySelectorAll('.tab').forEach((t) => t.classList.remove('active')); container
tab.classList.add('active'); .querySelectorAll(".tab")
container.querySelectorAll('.tab-content').forEach((content) => content.classList.remove('active')); .forEach((t) => t.classList.remove("active"));
container.querySelector(`#${tab.getAttribute('data-tab') as string}`)?.classList.add('active'); tab.classList.add("active");
container
.querySelectorAll(".tab-content")
.forEach((content) => content.classList.remove("active"));
container
.querySelector(`#${tab.getAttribute("data-tab") as string}`)
?.classList.add("active");
}); });
}); });
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const delay = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
try { try {
await delay(500); await delay(500);
this.addLoaderStep('Initialisation des services...'); this.addLoaderStep("Initialisation des services...");
const service = await Services.getInstance(); const service = await Services.getInstance();
await delay(700); await delay(700);
@ -149,42 +164,51 @@ export class HomePage extends HTMLElement {
if (pairingId) { if (pairingId) {
await delay(300); await delay(300);
this.addLoaderStep('Appairage existant trouvé.'); this.addLoaderStep("Appairage existant trouvé.");
service.setProcessId(pairingId); service.setProcessId(pairingId);
} else { } else {
await delay(300); await delay(300);
this.addLoaderStep("Création d'un appairage sécurisé..."); this.addLoaderStep("Création d'un appairage sécurisé...");
await prepareAndSendPairingTx(); await prepareAndSendPairingTx();
this.addLoaderStep('Appairage créé avec succès.'); this.addLoaderStep("Appairage créé avec succès.");
} }
// --- SUCCÈS --- // --- SUCCÈS ---
(window as any).__PAIRING_READY = true; console.log("[Home] Auto-pairing terminé avec succès.");
console.log('[Home] Auto-pairing terminé avec succès.'); document.dispatchEvent(
new CustomEvent("app:pairing-ready", {
detail: { success: true },
})
);
if (window.self !== window.top) { if (window.self !== window.top) {
// CAS IFRAME : On ne bouge pas ! // CAS IFRAME : On ne bouge pas !
// On affiche juste un état "Prêt" dans le loader pour le debug visuel // On affiche juste un état "Prêt" dans le loader pour le debug visuel
this.addLoaderStep("Prêt. En attente de l'application parente..."); this.addLoaderStep("Prêt. En attente de l'application parente...");
console.log('[Home] 📡 Mode Iframe : Pas de redirection. Attente des messages API.'); console.log(
"[Home] 📡 Mode Iframe : Pas de redirection. Attente des messages API."
);
} else { } else {
// CAS STANDALONE : On redirige // CAS STANDALONE : On redirige
console.log('[Home] 🚀 Mode Standalone : Redirection vers /process...'); console.log("[Home] 🚀 Mode Standalone : Redirection vers /process...");
await delay(500); await delay(500);
// On nettoie l'UI avant de partir // On nettoie l'UI avant de partir
if (loaderDiv) loaderDiv.style.display = 'none'; if (loaderDiv) loaderDiv.style.display = "none";
if (mainContentDiv) mainContentDiv.style.display = 'block'; if (mainContentDiv) mainContentDiv.style.display = "block";
// Hop, on navigue // Hop, on navigue
Router.navigate('process'); Router.navigate("process");
} }
container.querySelectorAll('.tab').forEach((t) => t.classList.remove('active')); container
container.querySelector('[data-tab="tab2"]')?.classList.add('active'); .querySelectorAll(".tab")
container.querySelectorAll('.tab-content').forEach((content) => content.classList.remove('active')); .forEach((t) => t.classList.remove("active"));
container.querySelector('#tab2')?.classList.add('active'); container.querySelector('[data-tab="tab2"]')?.classList.add("active");
container
.querySelectorAll(".tab-content")
.forEach((content) => content.classList.remove("active"));
container.querySelector("#tab2")?.classList.add("active");
const spAddress = await service.getDeviceAddress(); const spAddress = await service.getDeviceAddress();
generateCreateBtn(); generateCreateBtn();
@ -193,28 +217,35 @@ export class HomePage extends HTMLElement {
await delay(1000); await delay(1000);
if (loaderDiv) loaderDiv.style.display = 'none'; if (loaderDiv) loaderDiv.style.display = "none";
if (mainContentDiv) mainContentDiv.style.display = 'block'; if (mainContentDiv) mainContentDiv.style.display = "block";
console.log('[Home] Init terminée.'); console.log("[Home] Init terminée.");
(window as any).__PAIRING_READY = true;
} catch (e: any) { } catch (e: any) {
console.error('[Home] Erreur:', e); console.error("[Home] Erreur:", e);
this.addLoaderStep(`Erreur: ${e.message}`); this.addLoaderStep(`Erreur: ${e.message}`);
(window as any).__PAIRING_READY = 'error'; document.dispatchEvent(
new CustomEvent("app:pairing-ready", {
detail: { success: false, error: e.message },
})
);
} }
} }
addLoaderStep(text: string) { addLoaderStep(text: string) {
const container = this.shadowRoot; const container = this.shadowRoot;
if (!container) return; if (!container) return;
const currentStep = container.querySelector('.loader-step.active') as HTMLParagraphElement; const currentStep = container.querySelector(
if (currentStep) currentStep.classList.remove('active'); ".loader-step.active"
) as HTMLParagraphElement;
if (currentStep) currentStep.classList.remove("active");
const stepsContainer = container.querySelector('#loader-steps-container') as HTMLDivElement; const stepsContainer = container.querySelector(
"#loader-steps-container"
) as HTMLDivElement;
if (stepsContainer) { if (stepsContainer) {
const newStep = document.createElement('p'); const newStep = document.createElement("p");
newStep.className = 'loader-step active'; newStep.className = "loader-step active";
newStep.textContent = text; newStep.textContent = text;
stepsContainer.appendChild(newStep); stepsContainer.appendChild(newStep);
} }
@ -223,7 +254,9 @@ export class HomePage extends HTMLElement {
async populateMemberSelect() { async populateMemberSelect() {
const container = this.shadowRoot; const container = this.shadowRoot;
if (!container) return; if (!container) return;
const memberSelect = container.querySelector('#memberSelect') as HTMLSelectElement; const memberSelect = container.querySelector(
"#memberSelect"
) as HTMLSelectElement;
if (!memberSelect) return; if (!memberSelect) return;
const service = await Services.getInstance(); const service = await Services.getInstance();
@ -231,7 +264,7 @@ export class HomePage extends HTMLElement {
for (const [processId, member] of Object.entries(members)) { for (const [processId, member] of Object.entries(members)) {
const emojis = await addressToEmoji(processId); const emojis = await addressToEmoji(processId);
const option = document.createElement('option'); const option = document.createElement("option");
option.value = processId; option.value = processId;
option.textContent = `Member (${emojis})`; option.textContent = `Member (${emojis})`;
memberSelect.appendChild(option); memberSelect.appendChild(option);
@ -239,5 +272,4 @@ export class HomePage extends HTMLElement {
} }
} }
customElements.define('home-page', HomePage); customElements.define("home-page", HomePage);

View File

@ -1,7 +1,8 @@
import processHtml from './process.html?raw'; // src/pages/process/ProcessList.ts
import globalCss from '../../assets/styles/style.css?inline';
import Services from '../../services/service'; import processHtml from "./process.html?raw";
import { Router } from '../../router'; import globalCss from "../../assets/styles/style.css?inline";
import Services from "../../services/service";
export class ProcessListPage extends HTMLElement { export class ProcessListPage extends HTMLElement {
private services!: Services; private services!: Services;
@ -16,187 +17,54 @@ export class ProcessListPage extends HTMLElement {
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: 'open' }); this.attachShadow({ mode: "open" });
} }
async connectedCallback() { async connectedCallback() {
this.services = await Services.getInstance(); this.services = await Services.getInstance();
this.render(); this.render();
// Petit délai pour s'assurer que le DOM est prêt
setTimeout(() => this.initLogic(), 0); setTimeout(() => this.initLogic(), 0);
} }
render() { render() {
if (this.shadowRoot) { if (this.shadowRoot) {
// Le CSS et le HTML de base sont statiques, donc innerHTML est OK ici.
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
${globalCss} ${globalCss}
/* ... (styles identiques à ton fichier d'origine, je ne les répète pas pour abréger) ... */
:host { :host { display: block; width: 100%; }
display: block; .process-layout { padding: 2rem; display: flex; justify-content: center; }
width: 100%; .dashboard-container { width: 100%; max-width: 800px; display: flex; flex-direction: column; gap: 1.5rem; max-height: 85vh; overflow-y: auto; }
}
.process-layout {
padding: 2rem;
display: flex;
justify-content: center;
}
.dashboard-container {
width: 100%;
max-width: 800px;
display: flex;
flex-direction: column;
gap: 1.5rem;
max-height: 85vh; /* Pour scroller dedans si besoin */
overflow-y: auto;
}
.dashboard-header { text-align: center; } .dashboard-header { text-align: center; }
.subtitle { color: var(--text-muted); margin-top: -0.5rem; } .subtitle { color: var(--text-muted); margin-top: -0.5rem; }
.search-input-container { position: relative; display: flex; align-items: center; }
/* Search Styles */ .search-input-container input { padding-right: 40px; background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); transition: all 0.3s; }
.search-input-container { .search-input-container input:focus { background: rgba(255,255,255,0.1); border-color: var(--primary); }
position: relative; .search-icon { position: absolute; right: 12px; opacity: 0.5; }
display: flex; .autocomplete-dropdown { list-style: none; margin-top: 5px; padding: 0; background: #1e293b; border: 1px solid var(--glass-border); border-radius: var(--radius-sm); max-height: 200px; overflow-y: auto; display: none; position: absolute; width: 100%; z-index: 10; box-shadow: 0 10px 25px rgba(0,0,0,0.5); }
align-items: center;
}
.search-input-container input {
padding-right: 40px; /* Place pour l'icone */
background: rgba(255,255,255,0.05);
border: 1px solid var(--glass-border);
transition: all 0.3s;
}
.search-input-container input:focus {
background: rgba(255,255,255,0.1);
border-color: var(--primary);
}
.search-icon {
position: absolute;
right: 12px;
opacity: 0.5;
}
/* Autocomplete List */
.autocomplete-dropdown {
list-style: none;
margin-top: 5px;
padding: 0;
background: #1e293b; /* Fond opaque pour lisibilité */
border: 1px solid var(--glass-border);
border-radius: var(--radius-sm);
max-height: 200px;
overflow-y: auto;
display: none; /* Caché par défaut */
position: absolute;
width: 100%;
z-index: 10;
box-shadow: 0 10px 25px rgba(0,0,0,0.5);
}
/* Position relative pour que le dropdown s'aligne */
.custom-select-wrapper { position: relative; } .custom-select-wrapper { position: relative; }
.autocomplete-dropdown li { padding: 10px 15px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.05); transition: background 0.2s; color: var(--text-main); }
.autocomplete-dropdown li { .autocomplete-dropdown li:hover { background: var(--primary); color: white; }
padding: 10px 15px; .autocomplete-dropdown li.my-process { border-left: 3px solid var(--accent); }
cursor: pointer; .tags-container { display: flex; flex-wrap: wrap; gap: 8px; min-height: 30px; }
border-bottom: 1px solid rgba(255,255,255,0.05); .tag { background: rgba(var(--primary-hue), 50, 50, 0.3); border: 1px solid var(--primary); color: white; padding: 4px 10px; border-radius: 20px; font-size: 0.85rem; display: flex; align-items: center; gap: 8px; animation: popIn 0.2s ease-out; }
transition: background 0.2s; .tag-close { cursor: pointer; opacity: 0.7; font-weight: bold; }
color: var(--text-main);
}
.autocomplete-dropdown li:hover {
background: var(--primary);
color: white;
}
.autocomplete-dropdown li.my-process {
border-left: 3px solid var(--accent);
}
/* Tags */
.tags-container {
display: flex;
flex-wrap: wrap;
gap: 8px;
min-height: 30px;
}
.tag {
background: rgba(var(--primary-hue), 50, 50, 0.3);
border: 1px solid var(--primary);
color: white;
padding: 4px 10px;
border-radius: 20px;
font-size: 0.85rem;
display: flex;
align-items: center;
gap: 8px;
animation: popIn 0.2s ease-out;
}
.tag-close {
cursor: pointer;
opacity: 0.7;
font-weight: bold;
}
.tag-close:hover { opacity: 1; } .tag-close:hover { opacity: 1; }
@keyframes popIn { from { transform: scale(0.8); opacity: 0; } to { transform: scale(1); opacity: 1; } } @keyframes popIn { from { transform: scale(0.8); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.divider { height: 1px; background: var(--glass-border); margin: 0.5rem 0; } .divider { height: 1px; background: var(--glass-border); margin: 0.5rem 0; }
.details-content { background: rgba(0,0,0,0.2); border-radius: var(--radius-sm); padding: 1rem; min-height: 100px; }
/* Process Details */
.details-content {
background: rgba(0,0,0,0.2);
border-radius: var(--radius-sm);
padding: 1rem;
min-height: 100px;
}
.empty-state { color: var(--text-muted); font-style: italic; text-align: center; padding: 2rem; } .empty-state { color: var(--text-muted); font-style: italic; text-align: center; padding: 2rem; }
.process-item { margin-bottom: 1rem; border-bottom: 1px solid var(--glass-border); padding-bottom: 1rem; }
.process-item { .process-title-display { font-size: 1.1rem; font-weight: bold; color: var(--accent); margin-bottom: 0.5rem; }
margin-bottom: 1rem; .state-element { background: rgba(255,255,255,0.05); padding: 8px 12px; margin-top: 5px; border-radius: 4px; cursor: pointer; transition: background 0.2s; border: 1px solid transparent; font-family: monospace; font-size: 0.9rem; }
border-bottom: 1px solid var(--glass-border);
padding-bottom: 1rem;
}
.process-title-display {
font-size: 1.1rem;
font-weight: bold;
color: var(--accent);
margin-bottom: 0.5rem;
}
.state-element {
background: rgba(255,255,255,0.05);
padding: 8px 12px;
margin-top: 5px;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
border: 1px solid transparent;
font-family: monospace;
font-size: 0.9rem;
}
.state-element:hover { background: rgba(255,255,255,0.1); } .state-element:hover { background: rgba(255,255,255,0.1); }
.state-element.selected { background: rgba(var(--success), 0.2); border-color: var(--success); }
.state-element.selected { .dashboard-footer { display: flex; justify-content: flex-end; }
background: rgba(var(--success), 0.2);
border-color: var(--success);
}
.dashboard-footer {
display: flex;
justify-content: flex-end;
}
/* Scrollbar custom */
::-webkit-scrollbar { width: 6px; } ::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.2); border-radius: 3px; } ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.2); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.4); } ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.4); }
</style> </style>
${processHtml} ${processHtml}
`; `;
@ -207,47 +75,50 @@ export class ProcessListPage extends HTMLElement {
const root = this.shadowRoot; const root = this.shadowRoot;
if (!root) return; if (!root) return;
// Récupération des éléments this.wrapper = root.querySelector("#autocomplete-wrapper") as HTMLElement;
this.wrapper = root.querySelector('#autocomplete-wrapper') as HTMLElement; this.inputInput = root.querySelector("#process-input") as HTMLInputElement;
this.inputInput = root.querySelector('#process-input') as HTMLInputElement; this.autocompleteList = root.querySelector(
this.autocompleteList = root.querySelector('#autocomplete-list') as HTMLUListElement; "#autocomplete-list"
this.tagsContainer = root.querySelector('#selected-tags-container') as HTMLElement; ) as HTMLUListElement;
this.detailsContainer = root.querySelector('#process-details') as HTMLElement; this.tagsContainer = root.querySelector(
this.okButton = root.querySelector('#go-to-process-btn') as HTMLButtonElement; "#selected-tags-container"
) as HTMLElement;
this.detailsContainer = root.querySelector(
"#process-details"
) as HTMLElement;
this.okButton = root.querySelector(
"#go-to-process-btn"
) as HTMLButtonElement;
// Listeners this.inputInput.addEventListener("keyup", () => this.handleInput());
this.inputInput.addEventListener('keyup', () => this.handleInput()); this.inputInput.addEventListener("click", () => this.openDropdown());
this.inputInput.addEventListener('click', () => this.openDropdown());
// Fermeture du dropdown au clic extérieur document.addEventListener("click", (e) => {
document.addEventListener('click', (e) => {
const path = e.composedPath(); const path = e.composedPath();
if (!path.includes(this.wrapper)) { if (!path.includes(this.wrapper)) {
this.closeDropdown(); this.closeDropdown();
} }
}); });
this.okButton.addEventListener('click', () => this.goToProcess()); this.okButton.addEventListener("click", () => this.goToProcess());
// Écoute des mises à jour du service document.addEventListener("processes-updated", async () => {
document.addEventListener('processes-updated', async () => {
await this.populateList(this.inputInput.value); await this.populateList(this.inputInput.value);
}); });
// Chargement initial await this.populateList("");
await this.populateList('');
} }
// --- Logique Autocomplete --- // --- Logique Autocomplete Sécurisée ---
async populateList(query: string) { async populateList(query: string) {
this.autocompleteList.innerHTML = ''; this.autocompleteList.innerHTML = ""; // Vide la liste proprement
const mineArray = (await this.services.getMyProcesses()) ?? []; const mineArray = (await this.services.getMyProcesses()) ?? [];
const allProcesses = await this.services.getProcesses(); const allProcesses = await this.services.getProcesses();
const otherProcesses = Object.keys(allProcesses).filter(
// On combine tout, en mettant les miens d'abord (id) => !mineArray.includes(id)
const otherProcesses = Object.keys(allProcesses).filter((id) => !mineArray.includes(id)); );
const listToShow = [...mineArray, ...otherProcesses]; const listToShow = [...mineArray, ...otherProcesses];
let count = 0; let count = 0;
@ -258,22 +129,33 @@ export class ProcessListPage extends HTMLElement {
const name = this.services.getProcessName(process) || pid; const name = this.services.getProcessName(process) || pid;
// Filtre if (
if (query && !name.toLowerCase().includes(query.toLowerCase()) && !pid.includes(query)) { query &&
!name.toLowerCase().includes(query.toLowerCase()) &&
!pid.includes(query)
) {
continue; continue;
} }
count++; count++;
const li = document.createElement('li'); const li = document.createElement("li");
li.textContent = name;
const nameSpan = document.createElement("span");
nameSpan.textContent = name;
li.appendChild(nameSpan);
if (mineArray.includes(pid)) { if (mineArray.includes(pid)) {
li.classList.add('my-process'); li.classList.add("my-process");
li.innerHTML += ' <small style="opacity:0.6">(Mien)</small>'; const small = document.createElement("small");
small.style.opacity = "0.6";
small.style.marginLeft = "8px";
small.textContent = "(Mien)"; // Texte statique sûr
li.appendChild(small);
} }
li.addEventListener('click', () => { li.addEventListener("click", () => {
this.addTag(pid, name); this.addTag(pid, name);
this.inputInput.value = ''; this.inputInput.value = "";
this.showProcessDetails(pid); this.showProcessDetails(pid);
this.closeDropdown(); this.closeDropdown();
}); });
@ -282,10 +164,10 @@ export class ProcessListPage extends HTMLElement {
} }
if (count === 0) { if (count === 0) {
const empty = document.createElement('li'); const empty = document.createElement("li");
empty.textContent = 'Aucun résultat'; empty.textContent = "Aucun résultat";
empty.style.cursor = 'default'; empty.style.cursor = "default";
empty.style.opacity = '0.5'; empty.style.opacity = "0.5";
this.autocompleteList.appendChild(empty); this.autocompleteList.appendChild(empty);
} }
} }
@ -296,84 +178,121 @@ export class ProcessListPage extends HTMLElement {
} }
openDropdown() { openDropdown() {
this.autocompleteList.style.display = 'block'; this.autocompleteList.style.display = "block";
} }
closeDropdown() { closeDropdown() {
this.autocompleteList.style.display = 'none'; this.autocompleteList.style.display = "none";
} }
// --- Gestion des Tags --- // --- Gestion des Tags Sécurisée ---
addTag(pid: string, name: string) { addTag(pid: string, name: string) {
// On nettoie les anciens tags (mode single select pour l'instant, ou multi si tu veux) this.tagsContainer.innerHTML = "";
this.tagsContainer.innerHTML = '';
const tag = document.createElement('div'); const tag = document.createElement("div");
tag.className = 'tag'; tag.className = "tag";
tag.innerHTML = `
<span>${name}</span>
<span class="tag-close">&times;</span>
`;
tag.querySelector('.tag-close')?.addEventListener('click', (e) => { const spanName = document.createElement("span");
spanName.textContent = name;
tag.appendChild(spanName);
const closeBtn = document.createElement("span");
closeBtn.className = "tag-close";
closeBtn.innerHTML = "&times;";
closeBtn.addEventListener("click", (e) => {
e.stopPropagation(); e.stopPropagation();
this.removeTag(); this.removeTag();
}); });
tag.appendChild(closeBtn);
this.tagsContainer.appendChild(tag); this.tagsContainer.appendChild(tag);
} }
removeTag() { removeTag() {
this.tagsContainer.innerHTML = ''; this.tagsContainer.innerHTML = "";
this.detailsContainer.innerHTML = '<div class="empty-state"><p>Aucun processus sélectionné.</p></div>';
this.detailsContainer.innerHTML = "";
const emptyState = document.createElement("div");
emptyState.className = "empty-state";
const p = document.createElement("p");
p.textContent = "Aucun processus sélectionné.";
emptyState.appendChild(p);
this.detailsContainer.appendChild(emptyState);
this.okButton.disabled = true; this.okButton.disabled = true;
this.okButton.classList.add('disabled'); this.okButton.classList.add("disabled");
} }
// --- Détails du processus --- // --- Détails du processus Sécurisés ---
async showProcessDetails(pid: string) { async showProcessDetails(pid: string) {
this.detailsContainer.innerHTML = '<p style="text-align:center">Chargement...</p>'; this.detailsContainer.textContent = "Chargement..."; // Safe loader
const process = await this.services.getProcess(pid); const process = await this.services.getProcess(pid);
if (!process) return; if (!process) return;
this.detailsContainer.innerHTML = ''; // Clear this.detailsContainer.innerHTML = "";
const name = this.services.getProcessName(process) || 'Sans nom'; const name = this.services.getProcessName(process) || "Sans nom";
// Description // Description
let description = 'Pas de description'; let description = "Pas de description";
const lastState = this.services.getLastCommitedState(process); const lastState = this.services.getLastCommitedState(process);
if (lastState?.pcd_commitment['description']) { if (lastState?.pcd_commitment["description"]) {
const diff = await this.services.getDiffByValue(lastState.pcd_commitment['description']); const diff = await this.services.getDiffByValue(
lastState.pcd_commitment["description"]
);
if (diff) description = diff.value_commitment; if (diff) description = diff.value_commitment;
} }
const containerDiv = document.createElement('div'); const containerDiv = document.createElement("div");
containerDiv.className = 'process-item'; containerDiv.className = "process-item";
containerDiv.innerHTML = `
<div class="process-title-display">${name}</div> // Titre
<div style="font-size:0.9rem; margin-bottom:10px">${description}</div> const titleDiv = document.createElement("div");
<div style="font-size:0.8rem; opacity:0.7; margin-bottom:10px">ID: ${pid}</div> titleDiv.className = "process-title-display";
<div style="font-weight:bold; margin-top:15px">États en attente :</div> titleDiv.textContent = name; // Safe
`; containerDiv.appendChild(titleDiv);
// Description
const descDiv = document.createElement("div");
descDiv.style.fontSize = "0.9rem";
descDiv.style.marginBottom = "10px";
descDiv.textContent = description; // Safe
containerDiv.appendChild(descDiv);
// ID
const idDiv = document.createElement("div");
idDiv.style.fontSize = "0.8rem";
idDiv.style.opacity = "0.7";
idDiv.style.marginBottom = "10px";
idDiv.textContent = `ID: ${pid}`; // Safe
containerDiv.appendChild(idDiv);
// Label "États en attente"
const labelDiv = document.createElement("div");
labelDiv.style.fontWeight = "bold";
labelDiv.style.marginTop = "15px";
labelDiv.textContent = "États en attente :";
containerDiv.appendChild(labelDiv);
const uncommitted = this.services.getUncommitedStates(process); const uncommitted = this.services.getUncommitedStates(process);
if (uncommitted.length > 0) { if (uncommitted.length > 0) {
uncommitted.forEach((state) => { uncommitted.forEach((state) => {
const el = document.createElement('div'); const el = document.createElement("div");
el.className = 'state-element'; el.className = "state-element";
// textContent ici aussi, même si state_id est technique
el.textContent = `État: ${state.state_id.substring(0, 16)}...`; el.textContent = `État: ${state.state_id.substring(0, 16)}...`;
el.addEventListener('click', () => { el.addEventListener("click", () => {
// Gestion de la sélection this.shadowRoot
this.shadowRoot?.querySelectorAll('.state-element').forEach((x) => x.classList.remove('selected')); ?.querySelectorAll(".state-element")
el.classList.add('selected'); .forEach((x) => x.classList.remove("selected"));
el.classList.add("selected");
// Activation du bouton
this.okButton.disabled = false; this.okButton.disabled = false;
this.okButton.dataset.target = `${pid}/${state.state_id}`; this.okButton.dataset.target = `${pid}/${state.state_id}`;
}); });
@ -381,10 +300,10 @@ export class ProcessListPage extends HTMLElement {
containerDiv.appendChild(el); containerDiv.appendChild(el);
}); });
} else { } else {
const empty = document.createElement('div'); const empty = document.createElement("div");
empty.style.padding = '10px'; empty.style.padding = "10px";
empty.style.opacity = '0.6'; empty.style.opacity = "0.6";
empty.textContent = 'Aucun état en attente de validation.'; empty.textContent = "Aucun état en attente de validation.";
containerDiv.appendChild(empty); containerDiv.appendChild(empty);
} }
@ -394,11 +313,10 @@ export class ProcessListPage extends HTMLElement {
goToProcess() { goToProcess() {
const target = this.okButton.dataset.target; const target = this.okButton.dataset.target;
if (target) { if (target) {
console.log('Navigation vers', target); console.log("Navigation vers", target);
alert('Navigation vers la page de détail du processus (à implémenter): ' + target); alert("Navigation vers : " + target);
// Router.navigate(`process-detail/${target}`);
} }
} }
} }
customElements.define('process-list-page', ProcessListPage); customElements.define("process-list-page", ProcessListPage);

View File

@ -116,14 +116,14 @@ export function initAddressInput() {
if (address) { if (address) {
const emojis = await addressToEmoji(address); const emojis = await addressToEmoji(address);
if (emojiDisplay) { if (emojiDisplay) {
emojiDisplay.innerHTML = emojis; emojiDisplay.textContent = emojis;
} }
if (okButton) { if (okButton) {
okButton.style.display = 'inline-block'; okButton.style.display = 'inline-block';
} }
} else { } else {
if (emojiDisplay) { if (emojiDisplay) {
emojiDisplay.innerHTML = ''; emojiDisplay.textContent = '';
} }
if (okButton) { if (okButton) {
okButton.style.display = 'none'; okButton.style.display = 'none';