add search filter, toggle options, count unlocated events
This commit is contained in:
parent
ee48a3c665
commit
d22dbde2e7
12 changed files with 797 additions and 165 deletions
|
|
@ -1,42 +1,46 @@
|
|||
<div class="layout">
|
||||
@if(showOptions){
|
||||
<div class="aside">
|
||||
<div class="toolbar">
|
||||
<!-- <span class="loading-indicator">⏳</span> -->
|
||||
@if (isLoading) {
|
||||
<span class="loading-indicator">⏳</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="filters">
|
||||
|
||||
|
||||
<label (click)="showFilters = !showFilters">
|
||||
Filtre rapide
|
||||
@if (showFilters) {
|
||||
<span>▼</span>
|
||||
} @else {
|
||||
<span>▶</span>
|
||||
<div class="aside-content">
|
||||
<div class="toolbar">
|
||||
<!-- <span class="loading-indicator">⏳</span> -->
|
||||
@if (isLoading) {
|
||||
<span class="loading-indicator">⏳</span>
|
||||
}
|
||||
</label>
|
||||
|
||||
<div class="filters-group">
|
||||
@if (showFilters) {
|
||||
<span class="muted">{{filteredFeatures.length}} évènements chargés</span>
|
||||
<hr>
|
||||
<div class="controls">
|
||||
<div class="control-group">
|
||||
<label>Jours à venir</label>
|
||||
<input
|
||||
type="number"
|
||||
class="input"
|
||||
[(ngModel)]="daysAhead"
|
||||
(ngModelChange)="onDaysAheadChange()"
|
||||
min="1"
|
||||
max="30"
|
||||
placeholder="7">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="filters">
|
||||
|
||||
<label (click)="showFilters = !showFilters">
|
||||
Filtre rapide
|
||||
@if (showFilters) {
|
||||
<span>▼</span>
|
||||
} @else {
|
||||
<span>▶</span>
|
||||
}
|
||||
</label>
|
||||
|
||||
<div class="filters-group">
|
||||
@if (showFilters) {
|
||||
<span class="muted">{{filteredFeatures.length}} évènements chargés</span>
|
||||
<hr>
|
||||
<div class="controls">
|
||||
<div class="control-group">
|
||||
<label>Jours à venir</label>
|
||||
<input
|
||||
type="number"
|
||||
class="input"
|
||||
[(ngModel)]="daysAhead"
|
||||
(ngModelChange)="onDaysAheadChange()"
|
||||
min="1"
|
||||
max="30"
|
||||
placeholder="7">
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>
|
||||
<input
|
||||
|
|
@ -46,102 +50,130 @@
|
|||
Rechargement auto (1min)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="control-group">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
[(ngModel)]="useBboxFilter"
|
||||
(change)="onBboxFilterToggle()">
|
||||
Filtrer par zone visible (bbox)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<input class="input" type="text" placeholder="Rechercher..." [(ngModel)]="searchText" (ngModelChange)="onSearchChange()">
|
||||
|
||||
<div class="control-group">
|
||||
<app-what-filter [label]="'Filtrer par type d\'événement'" [available]="availableWhatTypes" [selected]="selectedWhatFilter" (selectedChange)="selectedWhatFilter = $event; onWhatFilterChange()"></app-what-filter>
|
||||
<label>Période (début / fin)</label>
|
||||
<div style="display:flex; gap:6px;">
|
||||
<input class="input" type="date" [(ngModel)]="startDateStr">
|
||||
<input class="input" type="date" [(ngModel)]="endDateStr">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<app-osm></app-osm>
|
||||
|
||||
<app-menu></app-menu>
|
||||
<hr>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <app-unlocated-events [events]="filteredFeatures"></app-unlocated-events> -->
|
||||
|
||||
<hr>
|
||||
@if(showEditForm){
|
||||
|
||||
<div class="guide">
|
||||
<h3>Guide</h3>
|
||||
<ul>
|
||||
<li> Créer un évènement: Cliquez sur le bouton "+" pour créer un nouvel évènement. Sélectionnez un preset, remplissez les informations, cliquez quelque part sur la carte pour définir un emplacement. Puis appuyez sur créer.</li>
|
||||
<li> Mettre à jour un évènement: Sélectionnez un évènement sur la carte ou dans la liste pour le modifier.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<app-edit-form [selected]="selected" (saved)="onSaved($event)" (created)="onCreated($event)" (deleted)="onDeleted($event)" (canceled)="onCanceled()"></app-edit-form>
|
||||
}
|
||||
|
||||
<div id="fixed_actions">
|
||||
<button class="button btn btn-primary" (click)="createEvent()" title="Créer un évènement">+ nouvel évènement</button>
|
||||
<button class="button" (click)="toggleView()" title="Basculer carte / tableau">📊</button>
|
||||
<div class="downloaders">
|
||||
<button class="button" (click)="downloadGeoJSON()" title="Télécharger GeoJSON">📥 GeoJSON</button>
|
||||
<button class="button" (click)="downloadCSV()" title="Télécharger CSV">📥 CSV</button>
|
||||
<div class="control-group">
|
||||
<button class="btn" (click)="onQuickSearchSubmit()">Rechercher</button>
|
||||
</div>
|
||||
<div class="selectors">
|
||||
<button class="button" [class.active]="selectionMode==='rectangle'" (click)="startRectSelection()" title="Sélection rectangulaire">▭</button>
|
||||
<button class="button" [class.active]="selectionMode==='polygon'" (click)="startPolySelection()" title="Sélection polygone">⬠</button>
|
||||
@if (selectedIds.length) {
|
||||
<span class="muted">{{selectedIds.length}} sélectionné(s)</span>
|
||||
|
||||
<div class="control-group">
|
||||
<app-what-filter [label]="'Filtrer par type d\'événement'" [available]="availableWhatTypes" [selected]="selectedWhatFilter" (selectedChange)="selectedWhatFilter = $event; onWhatFilterChange()"></app-what-filter>
|
||||
</div>
|
||||
|
||||
|
||||
<app-osm></app-osm>
|
||||
|
||||
<app-menu></app-menu>
|
||||
<hr>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- <app-unlocated-events [events]="filteredFeatures"></app-unlocated-events> -->
|
||||
|
||||
<hr>
|
||||
@if(showEditForm){
|
||||
|
||||
<div class="guide">
|
||||
<h3>Guide</h3>
|
||||
<ul>
|
||||
<li> Créer un évènement: Cliquez sur le bouton "+" pour créer un nouvel évènement. Sélectionnez un preset, remplissez les informations, cliquez quelque part sur la carte pour définir un emplacement. Puis appuyez sur créer.</li>
|
||||
<li> Mettre à jour un évènement: Sélectionnez un évènement sur la carte ou dans la liste pour le modifier.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<app-edit-form [selected]="selected" (saved)="onSaved($event)" (created)="onCreated($event)" (deleted)="onDeleted($event)" (canceled)="onCanceled()"></app-edit-form>
|
||||
}
|
||||
|
||||
<div id="fixed_actions">
|
||||
<button class="button btn btn-primary" (click)="createEvent()" title="Créer un évènement">+ nouvel évènement</button>
|
||||
<button class="button" (click)="toggleView()" title="Basculer carte / tableau">📊</button>
|
||||
<div class="downloaders">
|
||||
<button class="button" (click)="downloadGeoJSON()" title="Télécharger GeoJSON">📥 GeoJSON</button>
|
||||
<button class="button" (click)="downloadCSV()" title="Télécharger CSV">📥 CSV</button>
|
||||
</div>
|
||||
<div class="selectors">
|
||||
<button class="button" [class.active]="selectionMode==='rectangle'" (click)="startRectSelection()" title="Sélection rectangulaire">▭</button>
|
||||
<button class="button" [class.active]="selectionMode==='polygon'" (click)="startPolySelection()" title="Sélection polygone">⬠</button>
|
||||
@if (selectedIds.length) {
|
||||
<span class="muted">{{selectedIds.length}} sélectionné(s)</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@if(selected !== null){
|
||||
<div class="selected">
|
||||
|
||||
<h3> sélectionné: {{selected.properties.name}}</h3>
|
||||
|
||||
{{selected.properties.label}}
|
||||
<br>
|
||||
{{selected.properties.label}}
|
||||
<br>
|
||||
{{selected.properties.what}}
|
||||
<br>
|
||||
{{selected.properties.where}}
|
||||
<br>
|
||||
{{selected.properties.lat}}
|
||||
<br>
|
||||
{{selected.properties.lon}}
|
||||
|
||||
<br>
|
||||
{{selected.properties.wikidata}}
|
||||
<br>
|
||||
{{selected.properties.featureType}}
|
||||
<br>
|
||||
{{selected.properties.type}}
|
||||
<br>
|
||||
start:
|
||||
{{selected.properties.start}}
|
||||
<br>
|
||||
end:
|
||||
{{selected.properties.stop}}
|
||||
<br>
|
||||
source
|
||||
{{selected.properties.source}}
|
||||
<br>
|
||||
description:
|
||||
{{selected.properties.description}}
|
||||
<br>
|
||||
createdate:
|
||||
{{selected.properties.createdate}}
|
||||
<br>
|
||||
lastupdate:
|
||||
{{selected.properties.lastupdate}}
|
||||
|
||||
@if(selected !== null){
|
||||
<div class="selected">
|
||||
|
||||
<h3> sélectionné: {{selected.properties.name}}</h3>
|
||||
|
||||
{{selected.properties.label}}
|
||||
<br>
|
||||
{{selected.properties.label}}
|
||||
<br>
|
||||
{{selected.properties.what}}
|
||||
<br>
|
||||
{{selected.properties.where}}
|
||||
<br>
|
||||
{{selected.properties.lat}}
|
||||
<br>
|
||||
{{selected.properties.lon}}
|
||||
|
||||
<br>
|
||||
{{selected.properties.wikidata}}
|
||||
<br>
|
||||
{{selected.properties.featureType}}
|
||||
<br>
|
||||
{{selected.properties.type}}
|
||||
<br>
|
||||
start:
|
||||
{{selected.properties.start}}
|
||||
<br>
|
||||
end:
|
||||
{{selected.properties.stop}}
|
||||
<br>
|
||||
source
|
||||
{{selected.properties.source}}
|
||||
<br>
|
||||
description:
|
||||
{{selected.properties.description}}
|
||||
<br>
|
||||
createdate:
|
||||
{{selected.properties.createdate}}
|
||||
<br>
|
||||
lastupdate:
|
||||
{{selected.properties.lastupdate}}
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="main">
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
}
|
||||
<div class="main {{showOptions? 'is-small' : 'is-full'}}">
|
||||
<button class="button toggle-options" (click)="showOptions = !showOptions">
|
||||
Options
|
||||
</button>
|
||||
@if (theme()) {
|
||||
<div class="subtheme-bar">
|
||||
<div class="help">Thème: {{ theme() }} — Cliquez sur la carte pour définir des coordonnées puis créez un évènement du sous-thème choisi.</div>
|
||||
|
|
@ -155,10 +187,54 @@ lastupdate:
|
|||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (!showTable) {
|
||||
@if (!showTable && !showUnlocatedList) {
|
||||
<div class="map">
|
||||
<app-all-events [features]="filteredFeatures" [selected]="selected" [selectMode]="selectionMode" (selection)="onSelection($event)" (select)="onSelect($event)" (pickCoords)="onPickCoords($event)"></app-all-events>
|
||||
</div>
|
||||
} @else if (showUnlocatedList) {
|
||||
<div class="table-wrapper" style="overflow:auto;height:100%;">
|
||||
<div class="unlocated-layout">
|
||||
<aside class="agenda-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h3>Sans lieu / en ligne</h3>
|
||||
<small>{{unlocatedOrOnline.length}} évènements</small>
|
||||
</div>
|
||||
<div class="day-groups">
|
||||
<ul class="event-list">
|
||||
@for (f of unlocatedOrOnline; track f.id) {
|
||||
<li class="event-item" (click)="onSelect({ id: f?.properties?.id ?? f?.id, properties: f.properties, geometry: f.geometry })" [class.active]="selected?.id === (f?.properties?.id ?? f?.id)">
|
||||
<span class="event-icon">📌</span>
|
||||
<div class="event-meta">
|
||||
<div class="event-title">{{f?.properties?.label || f?.properties?.name || 'Événement'}}</div>
|
||||
<div class="event-when">{{f?.properties?.start || f?.properties?.when || '—'}}</div>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
<main class="agenda-main">
|
||||
@if (selected) {
|
||||
<div class="event-edit-panel">
|
||||
<div class="panel-header">
|
||||
<h3>Détails</h3>
|
||||
<button class="btn-close" (click)="selected = null">×</button>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<app-edit-form
|
||||
[selected]="selected"
|
||||
(saved)="onSaved($event)"
|
||||
(created)="onCreated($event)"
|
||||
(deleted)="onDeleted($event)">
|
||||
</app-edit-form>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="hint">Sélectionnez un évènement à gauche pour voir les détails.</div>
|
||||
}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="table-wrapper" style="overflow:auto;height:100%;">
|
||||
<table style="width:100%;border-collapse:collapse;">
|
||||
|
|
@ -194,6 +270,7 @@ lastupdate:
|
|||
<select class="input" [(ngModel)]="batchAction">
|
||||
<option value="none">Choisir...</option>
|
||||
<option value="changeWhat">Changer le type d'évènement (what)</option>
|
||||
<option value="setField">Remplacer une propriété</option>
|
||||
<option value="delete">Supprimer</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
@ -203,10 +280,36 @@ lastupdate:
|
|||
<input class="input" type="text" [(ngModel)]="batchWhat" placeholder="ex: traffic.roadwork" />
|
||||
</div>
|
||||
}
|
||||
@if (batchAction==='setField') {
|
||||
<div class="row">
|
||||
<label>Clé de propriété</label>
|
||||
<input class="input" type="text" [(ngModel)]="batchFieldKey" placeholder="ex: where" />
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Nouvelle valeur</label>
|
||||
<input class="input" type="text" [(ngModel)]="batchFieldValue" placeholder="ex: Paris, 12e" />
|
||||
</div>
|
||||
}
|
||||
<div class="actions">
|
||||
<button class="btn" (click)="applyBatch()" [disabled]="batchAction==='none'">Appliquer</button>
|
||||
<button class="btn btn-ghost" (click)="clearSelection()">Annuler</button>
|
||||
</div>
|
||||
@if (batchSummary) {
|
||||
<div class="summary">
|
||||
<span>Succès: {{batchSummary.success}}</span>
|
||||
<span>Échecs: {{batchSummary.failed}}</span>
|
||||
<span>Erreurs réseau: {{batchSummary.networkErrors}}</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Boutons flottants en bas à droite -->
|
||||
<div class="floating-actions">
|
||||
<button class="fab counter" (click)="toggleUnlocatedPanel()" title="Non localisés ou en ligne">
|
||||
{{unlocatedOrOnline.length}}
|
||||
</button>
|
||||
<button class="fab plus" (click)="createMammoth()" title="Créer un nouvel évènement (mammouth)">+
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue