refactor(home, process): standardize import statements, enhance code readability, and improve error handling in Home and ProcessList components
This commit is contained in:
parent
d45cf7c530
commit
e1d220596e
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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">×</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 = "×";
|
||||||
|
|
||||||
|
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);
|
||||||
|
|||||||
@ -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';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user