feat: add "concepts" help guide and introduce expandable help panel view

This commit is contained in:
kdeterme 2026-08-08 15:46:33 +02:00
parent 757f19ecce
commit bd1f084862
9 changed files with 533 additions and 189 deletions

View file

@ -0,0 +1,79 @@
# Concepts clés de StreetUp
StreetUp organise la gestion du patrimoine et des opérations terrain autour de plusieurs notions fondamentales. Comprendre leurs rôles et leurs distinctions permet d'optimiser l'utilisation de la plateforme.
---
## 1. Vue d'ensemble du cycle de vie
L'écosystème StreetUp s'articule autour du cycle suivant :
1. **Patrimoine** (`Asset`) : Les équipements physiques présents sur le terrain.
2. **Constat & Diagnostic** (`Observation` / `Inspection`) : Ce que l'on signale à chaud ou ce que l'on contrôle de manière formelle.
3. **Travaux & Maintenance** (`Intervention` / `Projet`) : L'action corrective ou préventive menée sur le terrain.
4. **Recette & Conformité** (`Contrôle`) : La vérification formelle de la bonne réalisation des travaux.
5. **Cadre financier & Logistique** (`Commande` / `Stock` / `Équipe`) : Les marchés, pièces et ressources mobilisés.
---
## 2. Définitions et distinctions des éléments clés
### 📍 Asset (Équipement / Patrimoine)
- **Définition** : Élément physique géolocalisé du domaine public (ex: panneau de signalisation, candélabre, potelet, ouvrage GIEP, emplacement vélo).
- **Rôle** : Servir de référence centrale pour l'historique de tous les constats, interventions et contrôles associés.
### 👁️ Observation (Signalement spontané)
- **Définition** : Constat rapide "à chaud" ou alerte spontanée sur le terrain.
- **Acteurs** : Agents de voirie, observateurs, citoyens.
- **Exemple** : *"Signalement d'un dépôt sauvage ou d'un potelet plié dans une rue."*
- **Distinction** : Une observation est un événement ponctuel et spontané, contrairement à une inspection qui est formalisée.
### 🔍 Inspection (Évaluation de conformité / Diagnostic)
- **Définition** : Évaluation structurée de l'état ou de la conformité d'une cible (Asset, Localisation ou Intervention) à un instant T.
- **Acteurs** : Observers, prestataires techniques, experts.
- **Exemple** : *"Contrôle visuel de l'état d'un ouvrage de drainage ou mesure électrique d'un candélabre."*
- **Distinction** : Une inspection ne modifie pas directement l'équipement sur le terrain ; elle produit un diagnostic (conforme / non conforme / endommagé) qui peut déclencher une intervention.
### 🛠️ Intervention (Action de travaux / Maintenance)
- **Définition** : Action de terrain corrective ou préventive visant à réparer, entretenir ou remplacer un équipement.
- **Acteurs** : Régie interne, prestataires de travaux.
- **Exemple** : *"Réparation d'un nid de poule", "Remplacement d'une lanterne de signalisation".*
- **Distinction** : L'intervention est l'action physique de travaux, alors que l'inspection est le diagnostic et le contrôle est la vérification.
### ✅ Contrôle (Réception & Recette des travaux)
- **Définition** : Vérification formelle de l'exécution des travaux visant à valider la qualité et à prononcer la réception d'un chantier.
- **Acteurs** : Contrôleurs travaux, gestionnaires de contrats.
- **Exemple** : *"Procès-verbal de réception des réfections de chaussée d'un marché."*
- **Distinction** : Le contrôle intervient **après** la réalisation des travaux pour valider leur conformité contractuelle et autoriser la facturation.
### 📁 Projet (Chantier d'envergure / Regroupement)
- **Définition** : Regroupement thématique, géographique ou temporel de plusieurs interventions.
- **Exemple** : *"Réaménagement de l'avenue de la Gare (comprenant 15 interventions de voirie, signalisation et éclairage)".*
### 💶 Commande (Cadre budgétaire & Marché)
- **Définition** : Ordre de service ou bon de commande rattaché à un marché/contrat qui encadre financièrement les travaux.
---
## 3. Tableau comparatif synthétique
| Concept | Nature | Déclencheur | Objectif principal |
| :--- | :--- | :--- | :--- |
| **Asset** | Patrimoine physique | Création / Inventaire | Identifier l'équipement géolocalisé |
| **Observation** | Signalement à chaud | Spontané | Alerter sur un dysfonctionnement ou une anomalie |
| **Inspection** | Diagnostic formalisé | Planifié ou terrain | Évaluer l'état de conformité d'une cible à un instant T |
| **Intervention** | Action de travaux | Suite à alerte / programme | Réparer, remplacer ou entretenir l'équipement |
| **Contrôle** | Vérification qualité | Post-travaux | Valider la conformité de l'intervention et procéder à la réception |
| **Projet** | Regroupement de travaux | Cadrage opérationnel | Piloter un chantier comportant plusieurs interventions |
| **Commande** | Cadrage financier | Cadrage contractuel | Gérer les bons de commande et budgets des marchés |
---
## 4. Relations particulières : Inspection vs Intervention vs Contrôle
### Dualité entre `Inspection` et `Intervention`
1. **L'Inspection d'une Intervention (Suivi qualité)** : Une inspection peut cibler une intervention réalisée (ex: vérification à J+30 de la tenue d'une réparation).
2. **L'Intervention comme Cadre de Mission d'Inspections** : Une intervention de type *"mission d'inspection"* sert de conteneur administratif et financier (bon de commande, prestataire assigné) pour réaliser une campagne de $N$ inspections sur le terrain (ex: campagne annuelle de contrôle des ouvrages GIEP).
### Différence entre `Inspection` et `Contrôle`
- **L'Inspection** évalue la conformité d'un **équipement (Asset)** ou d'une **zone (Location)**, ou assure un suivi technique.
- **Le Contrôle** évalue la réalisation de la **prestation de travaux (Intervention)** en vue de sa validation administrative et financière par le gestionnaire.

View file

@ -1,27 +1,40 @@
# Prise en main de StreetUp
# <span style="color: #0d6efd;">Prise en main de StreetUp</span>
Bienvenue dans StreetUp ! Ce guide rapide va vous présenter les bases de la navigation et de l'utilisation de l'application.
## 1. La barre de navigation principale (Header)
## <span style="color: #0d6efd;">1. La barre de navigation principale (Header)</span>
En haut de votre écran, vous trouverez la barre d'outils contenant :
- L'accès à vos informations de compte.
- Un sélecteur de vue (si vous avez accès à plusieurs portails).
- Le centre de notifications (<i class="bi bi-bell"></i>) pour suivre les discussions et alertes.
- Le sélecteur de langue (<i class="bi bi-translate"></i>) pour basculer entre le français et le néerlandais.
- Le bouton d'aide (<i class="bi bi-question-circle"></i>) qui ouvre ce panneau.
- Le centre de notifications (<i class="bi bi-bell text-primary"></i>) pour suivre les discussions et alertes.
- Le sélecteur de langue (<i class="bi bi-translate text-primary"></i>) pour basculer entre le français et le néerlandais.
- Le bouton d'aide (<i class="bi bi-question-circle text-primary"></i>) qui ouvre ce panneau.
## 2. Le menu latéral (Sidebar)
À gauche de l'écran (ou via le menu repliable sur mobile), vous pouvez naviguer vers :
- **Accueil** : Votre tableau de bord personnalisé avec vos compteurs d'interventions et de signalements.
- **Assets** : L'inventaire de vos équipements de voirie sur carte et en tableau.
- **Observations** : Vos constats et inspections sur le terrain.
- **Interventions** : Le suivi des chantiers et travaux de maintenance corrective ou préventive.
- **Projets** : La planification des travaux d'envergure.
## <span style="color: #0d6efd;">2. Le menu latéral (Sidebar)</span>
À gauche de l'écran (ou via le menu repliable sur mobile), le menu principal est structuré en 5 blocs thématiques pour suivre le cycle de vie de votre patrimoine et de vos opérations :
## 3. Dispositions d'affichage
- <i class="bi bi-house-fill text-primary me-1"></i> <strong style="color: #0f5132;">Accueil</strong> : Votre tableau de bord personnalisé et vos synthèses d'activité.
- <strong style="color: #0f5132;">Patrimoine & Diagnostics</strong> :
- <i class="bi bi-layers text-primary me-1"></i> <strong style="color: #495057;">Assets</strong> : Inventaire cartographique et tabulaire de tous vos équipements.
- <i class="bi bi-eye text-primary me-1"></i> <strong style="color: #495057;">Observations</strong> : Signalements et constats rapides sur le terrain.
- <i class="bi bi-search text-primary me-1"></i> <strong style="color: #495057;">Inspections</strong> : Visites de contrôle structurées et diagnostics de l'état des équipements.
- <strong style="color: #0f5132;">Gestion & Exécution des travaux</strong> :
- <i class="bi bi-currency-euro text-primary me-1"></i> <strong style="color: #495057;">Commandes</strong> : Gestion des marchés, ordres de service et cadrages budgétaires.
- <i class="bi bi-wrench-adjustable text-primary me-1"></i> <strong style="color: #495057;">Projets</strong> : Planification et regroupement des travaux d'envergure.
- <i class="bi bi-wrench text-primary me-1"></i> <strong style="color: #495057;">Interventions</strong> : Suivi des travaux de maintenance corrective ou préventive.
- <i class="bi bi-ui-checks text-primary me-1"></i> <strong style="color: #495057;">Contrôles</strong> : Vérification qualité et recette des travaux réalisés.
- <strong style="color: #0f5132;">Planification & Ressources</strong> :
- <i class="bi bi-calendar2-week text-primary me-1"></i> <strong style="color: #495057;">Calendrier</strong> : Vue temporelle et agenda des interventions et chantiers.
- <i class="bi bi-people text-primary me-1"></i> <strong style="color: #495057;">Équipes</strong> : Organisation et affectation des équipes d'intervention.
- <strong style="color: #0f5132;">Logistique & Matériel</strong> :
- <i class="bi bi-buildings text-primary me-1"></i> <strong style="color: #495057;">Entrepôts</strong> : Gestion de vos lieux de stockage de matériel.
- <i class="bi bi-arrow-repeat text-primary me-1"></i> <strong style="color: #495057;">Flux de stock</strong> : Mouvements, entrées/sorties et traçabilité des pièces.
- <i class="bi bi-cart text-primary me-1"></i> <strong style="color: #495057;">Achats</strong> : Demandes et commandes de matériel et fournitures.
## <span style="color: #0d6efd;">3. Dispositions d'affichage</span>
Sur la plupart des pages (Assets, Interventions), vous pouvez choisir d'afficher :
- La **carte** seule (<i class="bi bi-globe-europe-africa"></i>).
- Le **tableau** des données seul (<i class="bi bi-table"></i>).
- Les **deux** côte à côte (<i class="bi bi-layout-split"></i>, par défaut).
- La **carte** seule (<i class="bi bi-globe-europe-africa text-primary"></i>).
- Le **tableau** des données seul (<i class="bi bi-table text-primary"></i>).
- Les **deux** côte à côte (<i class="bi bi-layout-split text-primary"></i>, par défaut).
Ces boutons (situés en haut à droite des pages concernées) vous permettent de masquer la carte ou le tableau pour maximiser votre espace de travail. Vos choix de disposition sont automatiquement sauvegardés pour vos prochaines visites.

View file

@ -0,0 +1,79 @@
# Sleutelbegrippen in StreetUp
StreetUp organiseert het beheer van de openbare ruimte en terreinoperaties rond verschillende fundamentele begrippen. Het begrijpen van hun rol en onderlinge verschillen helpt om het platform optimaal te gebruiken.
---
## 1. Overzicht van de levenscyclus
Het StreetUp-ecosysteem is opgebouwd rond de volgende cyclus:
1. **Patrimonium** (`Asset`): Fysieke uitrustingen op het terrein.
2. **Vaststelling & Diagnose** (`Observatie` / `Inspectie`): Meldingen ter plaatse of formele controles.
3. **Werken & Onderhoud** (`Interventie` / `Project`): Correctieve of preventieve acties op het terrein.
4. **Oplevering & Conformiteit** (`Controle`): Formele verificatie van de correcte uitvoering van de werken.
5. **Financieel & Logistiek kader** (`Bestelling` / `Voorraad` / `Team`): Opdrachten, wisselstukken en ingezette middelen.
---
## 2. Definities en verschillen tussen sleutelelementen
### 📍 Asset (Uitrusting / Patrimonium)
- **Definitie**: Geolokaliseerd fysiek element van het openbaar domein (bv. verkeersbord, verlichtingspaal, fietsenstalling).
- **Rol**: Centraal referentiepunt voor de geschiedenis van alle geassocieerde vaststellingen, interventies en controles.
### 👁️ Observatie (Snelle melding)
- **Definitie**: Snelle vaststelling of spontane melding op het terrein.
- **Actoren**: Wegopzichters, waarnemers, burgers.
- **Voorbeeld**: *"Melding van sluikstort of een gebogen paaltje in een straat."*
- **Verschil**: Een observatie is spontaan en eenmalig, in tegenstelling tot een gestructureerde inspectie.
### 🔍 Inspectie (Conformiteitsdiagnose)
- **Definitie**: Gestructureerde evaluatie van de staat of conformiteit van een doel (Asset, Locatie of Interventie) op een tijdstip T.
- **Actoren**: Inspecteurs, technische dienstverleners, experts.
- **Voorbeeld**: *"Visuele controle van de staat van een drainagewerk of elektrische meting van een verlichtingspaal."*
- **Verschil**: Een inspectie wijzigt de uitrusting niet rechtstreeks, maar levert een diagnose op (conform / niet conform / beschadigd) die een interventie kan uitlokken.
### 🛠️ Interventie (Werken / Onderhoud)
- **Definitie**: Actie op het terrein om uitrustingen te herstellen, te onderhouden of te vervangen.
- **Actoren**: Interne regie, aannemers.
- **Voorbeeld**: *"Herstelling van een put in het wegdek", "Vervanging van een seinlamp".*
- **Verschil**: De interventie is de fysieke uitvoering van de werken, terwijl de inspectie de diagnose is en de controle de verificatie achteraf.
### ✅ Controle (Oplevering van werken)
- **Definitie**: Formele verificatie van de uitvoering van de werken om de kwaliteit te valideren en de oplevering van een werf te bevestigen.
- **Actoren**: Werfcontrollers, contractmanagers.
- **Voorbeeld**: *"Proces-verbaal van oplevering van de wegeniswerken van een opdracht."*
- **Verschil**: De controle vindt plaats **na** de uitvoering van de werken om hun contractuele conformiteit te valideren.
### 📁 Project (Grote werf / Groepering)
- **Definitie**: Thematische, geografische of temporele groepering van meerdere interventies.
- **Voorbeeld**: *"Heraanleg van de Stationslaan (bestaande uit 15 interventies voor wegenis, signalisatie en verlichting)".*
### 💶 Bestelling (Budgettair kader & Opdracht)
- **Definitie**: Dienstorder of bestelbon gekoppeld aan een contract/opdracht die de werken financieel omkaderd.
---
## 3. Vergelijkende samenvattingstabel
| Begrip | Aard | Triggermoment | Hoofddoel |
| :--- | :--- | :--- | :--- |
| **Asset** | Fysiek patrimonium | Aanmaak / Inventaris | Geolokaliseerde uitrusting identificeren |
| **Observatie** | Snelle melding | Spontaan | Waarschuwen voor een defect of anomalie |
| **Inspectie** | Formele diagnose | Gepland of terrein | Conformiteitsstaat evalueren op tijdstip T |
| **Interventie** | Uitvoering van werken | Na melding / programma | Herstellen, vervangen of onderhouden |
| **Controle** | Kwaliteitsverificatie | Na de werken | Conformiteit van de interventie valideren en opleveren |
| **Project** | Werfgroepering | Operationeel kader | Werf beheren met meerdere interventies |
| **Bestelling** | Financieel kader | Contractueel kader | Bestelbonnen en budgetten van opdrachten beheren |
---
## 4. Bijzondere relaties: Inspectie vs Interventie vs Controle
### Dualiteit tussen `Inspectie` en `Interventie`
1. **De Inspectie van een Interventie (Kwaliteitsopvolging)**: Een inspectie kan gericht zijn op een uitgevoerde interventie (bv. controle na 30 dagen van de herstelling).
2. **De Interventie als Kader voor Inspectieopdrachten**: Een interventie van het type *"inspectieopdracht"* dient als administratieve en financiële container voor een inspectiecampagne op het terrein.
### Verschil tussen `Inspectie` en `Controle`
- **De Inspectie** evalueert de conformiteit van een **uitrusting (Asset)** of **zone (Locatie)**.
- **De Controle** evalueert de uitvoering van de **geleverde werken (Interventie)** met het oog op de administratieve en financiële goedkeuring door de beheerder.

View file

@ -1,27 +1,40 @@
# Aan de slag met StreetUp
# <span style="color: #0d6efd;">Aan de slag met StreetUp</span>
Welkom bij StreetUp! Deze snelle handleiding toont u de basisprincipes van navigatie en gebruik van de applicatie.
## 1. De hoofdnavigatiebalk (Header)
## <span style="color: #0d6efd;">1. De hoofdnavigatiebalk (Header)</span>
Bovenaan uw scherm vindt u de knoppenbalk met:
- Toegang tot uw accountgegevens.
- Een weergaveschakelaar (als u toegang heeft tot meerdere portalen).
- Het notificatiecentrum (<i class="bi bi-bell"></i>) om discussies en waarschuwingen te volgen.
- De taalkeuze (<i class="bi bi-translate"></i>) om te schakelen tussen Frans en Nederlands.
- De helpknop (<i class="bi bi-question-circle"></i>) die dit paneel opent.
- Het notificatiecentrum (<i class="bi bi-bell text-primary"></i>) om discussies en waarschuwingen te volgen.
- De taalkeuze (<i class="bi bi-translate text-primary"></i>) om te schakelen tussen Frans en Nederlands.
- De helpknop (<i class="bi bi-question-circle text-primary"></i>) die dit paneel opent.
## 2. Het zijmenu (Sidebar)
Aan de linkerkant van het scherm (of via het inklapbare menu op mobiel) kunt u navigeren naar:
- **Home**: Uw gepersonaliseerde dashboard met tellers voor interventies en meldingen.
- **Assets**: De inventaris van uw weginfrastructuur op kaart en in tabelvorm.
- **Observaties**: Uw vaststellingen en inspecties op het terrein.
- **Interventies**: De opvolging van werven en onderhoudswerken (correctief of preventief).
- **Projecten**: De planning van grotere werken.
## <span style="color: #0d6efd;">2. Het zijmenu (Sidebar)</span>
Aan de linkerkant van het scherm (of via het inklapbare menu op mobiel) is het hoofdmenu gestructureerd in 5 thematische blokken die de levenscyclus van uw patrimonium en uw operaties volgen:
## 3. Weergave-indelingen
- <i class="bi bi-house-fill text-primary me-1"></i> <strong style="color: #0f5132;">Home</strong>: Uw gepersonaliseerde dashboard en activiteitsoverzichten.
- <strong style="color: #0f5132;">Patrimonium & Diagnoses</strong>:
- <i class="bi bi-layers text-primary me-1"></i> <strong style="color: #495057;">Assets</strong>: Inventaris op kaart en in tabelvorm van al uw uitrustingen.
- <i class="bi bi-eye text-primary me-1"></i> <strong style="color: #495057;">Observaties</strong>: Snelle meldingen en vaststellingen op het terrein.
- <i class="bi bi-search text-primary me-1"></i> <strong style="color: #495057;">Inspecties</strong>: Gestructureerde controlebezoeken en diagnoses van de staat van de uitrustingen.
- <strong style="color: #0f5132;">Beheer & Uitvoering van de werken</strong>:
- <i class="bi bi-currency-euro text-primary me-1"></i> <strong style="color: #495057;">Bestellingen</strong>: Beheer van opdrachten, dienstorders en budgettair kader.
- <i class="bi bi-wrench-adjustable text-primary me-1"></i> <strong style="color: #495057;">Projecten</strong>: Planning en groepering van grotere werken.
- <i class="bi bi-wrench text-primary me-1"></i> <strong style="color: #495057;">Interventies</strong>: Opvolging van onderhoudswerken (correctief of preventief).
- <i class="bi bi-ui-checks text-primary me-1"></i> <strong style="color: #495057;">Controles</strong>: Kwaliteitsverificatie en oplevering van de uitgevoerde werken.
- <strong style="color: #0f5132;">Planning & Middelen</strong>:
- <i class="bi bi-calendar2-week text-primary me-1"></i> <strong style="color: #495057;">Kalender</strong>: Tijdsweergave en agenda van interventies en werven.
- <i class="bi bi-people text-primary me-1"></i> <strong style="color: #495057;">Teams</strong>: Organisatie en toewijzing van interventieteams.
- <strong style="color: #0f5132;">Logistiek & Materiaal</strong>:
- <i class="bi bi-buildings text-primary me-1"></i> <strong style="color: #495057;">Magazijnen</strong>: Beheer van uw opslaglocaties voor materiaal.
- <i class="bi bi-arrow-repeat text-primary me-1"></i> <strong style="color: #495057;">Voorraadstromen</strong>: Bewegingen, in-/uitgangen en traceerbaarheid van onderdelen.
- <i class="bi bi-cart text-primary me-1"></i> <strong style="color: #495057;">Aankopen</strong>: Aanvragen en bestellingen van materiaal en benodigdheden.
## <span style="color: #0d6efd;">3. Weergave-indelingen</span>
Op de meeste pagina's (Assets, Interventies) kunt u kiezen om weer te geven:
- Alleen de **kaart** (<i class="bi bi-globe-europe-africa"></i>).
- Alleen de **tabel** met gegevens (<i class="bi bi-table"></i>).
- **Beide** naast elkaar (<i class="bi bi-layout-split"></i>, standaard).
- Alleen de **kaart** (<i class="bi bi-globe-europe-africa text-primary"></i>).
- Alleen de **tabel** met gegevens (<i class="bi bi-table text-primary"></i>).
- **Beide** naast elkaar (<i class="bi bi-layout-split text-primary"></i>, par défaut).
Met deze knoppen (bovenaan rechts op de betreffende pagina's) kunt u de kaart of de tabel verbergen om uw werkruimte te maximaliseren. Uw voorkeuren voor de indeling worden automatisch opgeslagen voor uw volgende bezoeken.

View file

@ -282,3 +282,21 @@
width: 2.5rem;
height: 2.5rem;
}
/* Styles for Help Content inside Large Format Modal */
#help-content-container.in-modal .help-guide-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 1.25rem;
}
#help-content-container.in-modal .help-markdown-content {
max-width: 960px;
margin: 0 auto;
padding: 0.5rem 1rem;
}
#help-content-container.in-modal .help-search-wrapper {
max-width: 500px;
}

View file

@ -1,4 +1,4 @@
/* Help Panel Interaction Javascript */
/* Help Panel & Modal Interaction Javascript */
document.addEventListener('DOMContentLoaded', () => {
// DOM Elements
@ -6,6 +6,13 @@ document.addEventListener('DOMContentLoaded', () => {
const panel = document.getElementById('help-sidebar-panel');
const backdrop = document.getElementById('help-panel-backdrop');
const closeBtn = document.getElementById('helpPanelClose');
const expandBtn = document.getElementById('helpExpandBtn');
const modalEl = document.getElementById('helpLargeModal');
const modalBody = document.getElementById('helpModalBody');
const sidebarBody = document.getElementById('help-sidebar-body');
const contentContainer = document.getElementById('help-content-container');
const modalSwitchToSidebarBtn = document.getElementById('helpModalSwitchToSidebarBtn');
const indexView = document.getElementById('help-index-view');
const detailView = document.getElementById('help-detail-view');
@ -20,42 +27,128 @@ document.addEventListener('DOMContentLoaded', () => {
return;
}
// Toggle Drawer Open/Close
function openHelpPanel() {
let bsHelpModal = null;
if (modalEl && window.bootstrap && window.bootstrap.Modal) {
bsHelpModal = new bootstrap.Modal(modalEl);
}
// Persistent display mode ('sidebar' | 'modal') saved in localStorage
function getDisplayMode() {
return localStorage.getItem('help_display_mode') || 'sidebar';
}
function setDisplayMode(mode) {
localStorage.setItem('help_display_mode', mode);
}
// Attach content container to target parent element (sidebar or modal)
function attachContentToTarget(targetMode) {
if (!contentContainer) return;
if (targetMode === 'modal' && modalBody) {
if (contentContainer.parentElement !== modalBody) {
modalBody.appendChild(contentContainer);
}
contentContainer.classList.add('in-modal');
} else if (sidebarBody) {
if (contentContainer.parentElement !== sidebarBody) {
sidebarBody.appendChild(contentContainer);
}
contentContainer.classList.remove('in-modal');
}
}
// Open Help according to display mode
function openHelp(requestedMode) {
const mode = requestedMode || getDisplayMode();
if (mode === 'modal' && bsHelpModal) {
closeSidebarPanelSilent();
attachContentToTarget('modal');
bsHelpModal.show();
sessionStorage.setItem('helpPanelOpen', 'true');
sessionStorage.setItem('helpPanelDisplayMode', 'modal');
} else {
if (bsHelpModal) bsHelpModal.hide();
attachContentToTarget('sidebar');
openSidebarPanel();
}
}
function openSidebarPanel() {
panel.classList.add('open');
backdrop.classList.add('show');
sessionStorage.setItem('helpPanelOpen', 'true');
sessionStorage.setItem('helpPanelDisplayMode', 'sidebar');
}
function closeSidebarPanelSilent() {
panel.classList.remove('open');
backdrop.classList.remove('show');
}
function closeHelpPanel() {
panel.classList.remove('open');
backdrop.classList.remove('show');
closeSidebarPanelSilent();
if (bsHelpModal) bsHelpModal.hide();
sessionStorage.setItem('helpPanelOpen', 'false');
sessionStorage.removeItem('helpPanelDoc');
// Reset to index view when closing
setTimeout(() => {
showIndexView();
if (searchInput) {
searchInput.value = '';
filterGuides('');
}
}, 350); // wait for transition
}, 350);
}
// Toggle help on trigger click
trigger.addEventListener('click', (e) => {
e.preventDefault();
if (panel.classList.contains('open')) {
const isModalVisible = modalEl && modalEl.classList.contains('show');
const isSidebarOpen = panel.classList.contains('open');
if (isModalVisible) {
if (bsHelpModal) bsHelpModal.hide();
sessionStorage.setItem('helpPanelOpen', 'false');
} else if (isSidebarOpen) {
closeHelpPanel();
} else {
openHelpPanel();
openHelp();
}
});
// Expand button (Sidebar -> Modal)
if (expandBtn) {
expandBtn.addEventListener('click', (e) => {
e.preventDefault();
setDisplayMode('modal');
openHelp('modal');
});
}
// Switch to sidebar button (Modal -> Sidebar)
if (modalSwitchToSidebarBtn) {
modalSwitchToSidebarBtn.addEventListener('click', (e) => {
e.preventDefault();
setDisplayMode('sidebar');
openHelp('sidebar');
});
}
closeBtn.addEventListener('click', closeHelpPanel);
backdrop.addEventListener('click', closeHelpPanel);
// Escape Key to Close
// Track modal close via bootstrap backdrop / ESC
if (modalEl) {
modalEl.addEventListener('hidden.bs.modal', () => {
if (sessionStorage.getItem('helpPanelDisplayMode') === 'modal') {
sessionStorage.setItem('helpPanelOpen', 'false');
}
});
}
// Escape Key to Close Sidebar
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && panel.classList.contains('open')) {
closeHelpPanel();
@ -93,9 +186,9 @@ document.addEventListener('DOMContentLoaded', () => {
});
if (visibleCount === 0) {
noResults.classList.remove('d-none');
if (noResults) noResults.classList.remove('d-none');
} else {
noResults.classList.add('d-none');
if (noResults) noResults.classList.add('d-none');
}
}
@ -127,7 +220,8 @@ document.addEventListener('DOMContentLoaded', () => {
function showDetailView() {
indexView.classList.add('d-none');
detailView.classList.remove('d-none');
detailView.scrollTop = 0;
if (detailView) detailView.scrollTop = 0;
if (modalBody) modalBody.scrollTop = 0;
}
// Dynamic AJAX loading
@ -135,7 +229,6 @@ document.addEventListener('DOMContentLoaded', () => {
showDetailView();
sessionStorage.setItem('helpPanelDoc', docName);
// Show loading spinner
const loadingText = panel.getAttribute('data-loading-text') || 'Chargement...';
detailContent.innerHTML = `
<div class="help-loader">
@ -181,24 +274,30 @@ document.addEventListener('DOMContentLoaded', () => {
// Restore state from sessionStorage on page load
const isHelpOpen = sessionStorage.getItem('helpPanelOpen') === 'true';
const activeDocName = sessionStorage.getItem('helpPanelDoc');
const storedDisplayMode = sessionStorage.getItem('helpPanelDisplayMode') || getDisplayMode();
if (isHelpOpen) {
// Temporarily disable transition to prevent visible flicker
if (storedDisplayMode === 'modal') {
openHelp('modal');
if (activeDocName) {
loadHelpDocument(activeDocName);
}
} else {
const originalPanelTransition = panel.style.transition;
const originalBackdropTransition = backdrop.style.transition;
panel.style.transition = 'none';
backdrop.style.transition = 'none';
openHelpPanel();
openHelp('sidebar');
if (activeDocName) {
loadHelpDocument(activeDocName);
}
// Restore transition after browser renders the initial open state
setTimeout(() => {
panel.style.transition = originalPanelTransition;
backdrop.style.transition = originalBackdropTransition;
}, 50);
}
}
});

View file

@ -15,12 +15,19 @@
<i class="bi bi-question-circle"></i>
{% translate "Centre d'aide" %}
</h5>
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-sm btn-outline-primary d-flex align-items-center gap-1" id="helpExpandBtn" title="{% translate 'Agrandir en grand format' %}">
<i class="bi bi-arrows-angle-expand"></i>
<span class="d-none d-sm-inline">{% translate "Agrandir" %}</span>
</button>
<button type="button" class="btn-close" id="helpPanelClose" aria-label="Close"></button>
</div>
</div>
<!-- Body -->
<div class="help-panel-body">
<div class="help-panel-body" id="help-sidebar-body">
<div id="help-content-container">
<!-- ================= INDEX VIEW ================= -->
<div id="help-index-view">
<!-- Search bar -->
@ -42,6 +49,15 @@
<i class="bi bi-chevron-right help-guide-link-icon"></i>
</a>
<!-- Guide: Concepts et notions clés -->
<a href="#" class="help-guide-link" data-doc-name="concepts">
<div>
<h6 class="help-guide-link-title">{% translate "Concepts et notions clés de StreetUp" %}</h6>
<p class="help-guide-link-desc">{% translate "Comprendre la différence entre Assets, Observations, Inspections, Interventions et Contrôles." %}</p>
</div>
<i class="bi bi-chevron-right help-guide-link-icon"></i>
</a>
<!-- Guide 2: Assets -->
<a href="#" class="help-guide-link" data-doc-name="assets">
<div>
@ -113,6 +129,31 @@
<!-- Dynamic Markdown HTML goes here -->
<div id="help-detail-content"></div>
</div>
</div>
</div>
</div>
<!-- Help Large Format Modal -->
<div class="modal fade" id="helpLargeModal" tabindex="-1" aria-labelledby="helpLargeModalLabel" aria-hidden="true" style="z-index: 1070;">
<div class="modal-dialog modal-xl modal-dialog-scrollable modal-dialog-centered">
<div class="modal-content shadow-lg border-0">
<div class="modal-header bg-light align-items-center justify-content-between py-2 px-3">
<h5 class="modal-title d-flex align-items-center gap-2 text-primary fw-bold fs-6" id="helpLargeModalLabel">
<i class="bi bi-question-circle"></i>
{% translate "Centre d'aide" %}
</h5>
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-sm btn-outline-primary d-flex align-items-center gap-1" id="helpModalSwitchToSidebarBtn" title="{% translate 'Réduire en panneau latéral' %}">
<i class="bi bi-layout-sidebar-reverse"></i>
<span class="d-none d-sm-inline">{% translate "Réduire en panneau latéral" %}</span>
</button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body p-4" id="helpModalBody">
<!-- Dynamic Help Content Container gets attached here when modal is active -->
</div>
</div>
</div>
</div>

View file

@ -545,7 +545,7 @@ def get_help_document(request, doc_name):
from django.utils import translation
from django.http import HttpResponseForbidden
ALLOWED_DOCS = ['prise_en_main', 'assets', 'approuver_interventions', 'gerer_projets', 'statuts_intervention', 'creer_controle']
ALLOWED_DOCS = ['prise_en_main', 'concepts', 'assets', 'approuver_interventions', 'gerer_projets', 'statuts_intervention', 'creer_controle']
if doc_name not in ALLOWED_DOCS:
return JsonResponse({'error': _('Document non trouvé')}, status=404)

View file

@ -339,38 +339,23 @@
<div class="d-flex flex-column sidebar pe-3" id="sidebar">
{% block sidebar %}
<a href="/" class="nav-link d-flex align-items-center p-2 {% if request.path == '/' %}active{% endif %}">
<i class="bi bi-house-fill" data-bs-toggle="tooltip" data-bs-placement="right" title="Accueil"></i>
<i class="bi bi-house-fill" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Accueil' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Accueil" %}</span>
</a>
<hr class="my-1">
<a href="/assets/" class="nav-link d-flex align-items-center p-2 {% if request.path == '/assets/' or request.path|slice:':14' == '/assets/maps/' %}active{% endif %}">
<i class="bi bi-layers" data-bs-toggle="tooltip" data-bs-placement="right" title="Assets"></i>
<i class="bi bi-layers" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Assets' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Assets" %}</span>
</a>
{% if user.config|has_any_role:"admin,manager,external_manager,controller,observer,operator,editor,top_manager" %}
<a href="/observations/" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':13' == '/observations/' %}active{% endif %}">
<i class="bi bi-eye" data-bs-toggle="tooltip" data-bs-placement="right" title="observations"></i>
<i class="bi bi-eye" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Observations' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Observations" %}</span>
</a>
{% endif %}
<a href="/interventions/" class="nav-link d-flex align-items-center p-2 {% if request.path == '/interventions/' %}active{% endif %}">
<i class="bi bi-wrench" data-bs-toggle="tooltip" data-bs-placement="right" title="Interventions"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Interventions" %}</span>
</a>
{% if user.config|has_any_role:"admin,manager,controller,external_manager,top_manager" %}
<a href="/projects/" class="nav-link d-flex align-items-center p-2 {% if request.path == '/projects/' %}active{% endif %}">
<i class="bi bi-wrench-adjustable" data-bs-toggle="tooltip" data-bs-placement="right" title="Projets"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Projets" %}</span>
</a>
{% endif %}
{% if user.config|has_any_role:"admin,manager,controller,external_manager,top_manager" %}
<a href="/controls/" class="nav-link d-flex align-items-center p-2 {% if request.path == '/controls/' %}active{% endif %}">
<i class="bi bi-ui-checks" data-bs-toggle="tooltip" data-bs-placement="right" title="Projets"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Contrôles" %}</span>
</a>
{% endif %}
<a href="{% url 'inspections:inspections_list' %}" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':12' == '/inspections' %}active{% endif %}">
<i class="bi bi-search" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Inspections' %}"></i>
@ -379,46 +364,63 @@
<hr class="my-1">
{% if user.config|has_any_role:"admin,manager,controller,external_manager,top_manager" %}
<a href="/contracts/" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':11' == '/contracts/' and request.path|slice:':17' != '/contracts/teams/' or request.path|slice:':8' == '/orders/' %}active{% endif %}">
<i class="bi bi-currency-euro" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Commandes' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Commandes" %}</span>
</a>
{% endif %}
{% if user.config|has_any_role:"admin,manager,controller,external_manager,top_manager" %}
<a href="/projects/" class="nav-link d-flex align-items-center p-2 {% if request.path == '/projects/' %}active{% endif %}">
<i class="bi bi-wrench-adjustable" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Projets' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Projets" %}</span>
</a>
{% endif %}
<a href="/interventions/" class="nav-link d-flex align-items-center p-2 {% if request.path == '/interventions/' %}active{% endif %}">
<i class="bi bi-wrench" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Interventions' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Interventions" %}</span>
</a>
{% if user.config|has_any_role:"admin,manager,controller,external_manager,top_manager" %}
<a href="/controls/" class="nav-link d-flex align-items-center p-2 {% if request.path == '/controls/' %}active{% endif %}">
<i class="bi bi-ui-checks" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Contrôles' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Contrôles" %}</span>
</a>
{% endif %}
<hr class="my-1">
<a href="/interventions/calendar/" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':24' == '/interventions/calendar/' %}active{% endif %}">
<i class="bi bi-calendar2-week" data-bs-toggle="tooltip" data-bs-placement="right" title="Calendrier"></i>
<i class="bi bi-calendar2-week" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Calendrier' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Calendrier" %}</span>
</a>
{% if user.config|can_view_teams %}
<a href="/contracts/teams/" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':17' == '/contracts/teams/' %}active{% endif %}">
<i class="bi bi-people" data-bs-toggle="tooltip" data-bs-placement="right" title="Équipes"></i>
<i class="bi bi-people" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Équipes' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Équipes" %}</span>
</a>
{% endif %}
{% if user.config|has_any_role:"admin,manager,controller,external_manager,top_manager" %}
<hr class="my-1">
<a href="/contracts/" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':8' == '/orders/' %}active{% endif %}">
<i class="bi bi-currency-euro" data-bs-toggle="tooltip" data-bs-placement="right" title="Commandes"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Commandes" %}</span>
</a>
{% endif %}
<hr class="my-1">
{% if user.config|has_any_role:"admin,stock_manager,manager,controller,top_manager" %}
<hr class="my-1">
<a href="/stock/warehouses/" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':18' == '/stock/warehouses/' %}active{% endif %}">
<i class="bi bi-buildings" data-bs-toggle="tooltip" data-bs-placement="right" title="Entrepôts"></i>
<i class="bi bi-buildings" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Entrepôts' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Entrepôts" %}</span>
</a>
{% if user.config|has_any_role:"admin,stock_manager,top_manager" %}
<a href="/stock/movements/" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':17' == '/stock/movements/' %}active{% endif %}">
<i class="bi bi-arrow-repeat" data-bs-toggle="tooltip" data-bs-placement="right" title="Flux de Stock"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Flux de Stock" %}</span>
<i class="bi bi-arrow-repeat" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Flux de stock' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Flux de stock" %}</span>
</a>
<a href="/stock/purchases/" class="nav-link d-flex align-items-center p-2 {% if request.path|slice:':17' == '/stock/purchases/' %}active{% endif %}">
<i class="bi bi-cart" data-bs-toggle="tooltip" data-bs-placement="right" title="Achats"></i>
<i class="bi bi-cart" data-bs-toggle="tooltip" data-bs-placement="right" title="{% translate 'Achats' %}"></i>
<span class="ms-2 text d-none d-md-inline">{% translate "Achats" %}</span>
</a>
{% endif %}
<hr class="my-1">
{% endif %}
{% endblock sidebar %}