up display; ajout scrap agendadulibre; qa évènements sans localisation

This commit is contained in:
Tykayn 2025-10-04 19:18:10 +02:00 committed by tykayn
parent 73f18e1d31
commit 6deed13d0b
25 changed files with 2165 additions and 53 deletions

View file

@ -2,7 +2,7 @@
<div class="aside">
<div class="toolbar">
<strong>OpenEventDatabase</strong>
<span class="muted">{{features.length}} évènements</span>
<span class="muted">{{filteredFeatures.length}} évènements</span>
@if (isLoading) {
<span class="loading">⏳ Chargement...</span>
}
@ -42,18 +42,29 @@
<div class="filters">
<label>Filtre rapide</label>
<input class="input" type="text" placeholder="Rechercher...">
<input class="input" type="text" placeholder="Rechercher..." [(ngModel)]="searchText" (ngModelChange)="onSearchChange()">
<div class="control-group">
<label>Filtrer par type d'événement</label>
<select class="input" [(ngModel)]="selectedWhatFilter" (ngModelChange)="onWhatFilterChange()">
<option value="">Tous les types</option>
@for (whatType of availableWhatTypes; track whatType) {
<option [value]="whatType">{{whatType}}</option>
}
</select>
</div>
</div>
<hr>
<app-unlocated-events [events]="features"></app-unlocated-events>
<app-unlocated-events [events]="filteredFeatures"></app-unlocated-events>
<app-menu></app-menu>
<hr>
<app-osm></app-osm>
<app-edit-form [selected]="selected" (saved)="onSaved($event)" (created)="onCreated($event)" (deleted)="onDeleted($event)"></app-edit-form>
</div>
<div class="main">
@if (!showTable) {
<div class="map">
<app-all-events [features]="features" [selected]="selected" (select)="onSelect($event)" (pickCoords)="onPickCoords($event)"></app-all-events>
<app-all-events [features]="filteredFeatures" [selected]="selected" (select)="onSelect($event)" (pickCoords)="onPickCoords($event)"></app-all-events>
</div>
} @else {
<div class="table-wrapper" style="overflow:auto;height:100%;">
@ -67,7 +78,7 @@
</tr>
</thead>
<tbody>
@for (f of features; track f.id) {
@for (f of filteredFeatures; track f.id) {
<tr (click)="onSelect({ id: f?.properties?.id ?? f?.id, properties: f.properties, geometry: f.geometry })" style="cursor:pointer;">
<td style="padding:6px;border-bottom:1px solid #f1f5f9;">{{f?.properties?.what}}</td>
<td style="padding:6px;border-bottom:1px solid #f1f5f9;">{{f?.properties?.label || f?.properties?.name}}</td>

View file

@ -4,7 +4,7 @@
.layout {
display: grid;
grid-template-columns: 340px 1fr;
grid-template-columns: 400px 1fr;
grid-template-rows: 100vh;
gap: 0;
}
@ -14,6 +14,7 @@
border-right: 1px solid rgba(0,0,0,0.06);
box-shadow: 2px 0 12px rgba(0,0,0,0.03);
padding: 16px;
padding-bottom: 150px;
overflow: auto;
}

View file

@ -6,6 +6,8 @@ import { AllEvents } from '../../maps/all-events/all-events';
import { EditForm } from '../../forms/edit-form/edit-form';
import { OedbApi } from '../../services/oedb-api';
import { UnlocatedEvents } from '../../shared/unlocated-events/unlocated-events';
import { OsmAuth } from '../../services/osm-auth';
import { Osm } from '../../forms/osm/osm';
@Component({
selector: 'app-home',
standalone: true,
@ -14,6 +16,7 @@ import { UnlocatedEvents } from '../../shared/unlocated-events/unlocated-events'
AllEvents,
UnlocatedEvents,
EditForm,
Osm,
FormsModule
],
templateUrl: './home.html',
@ -23,8 +26,10 @@ export class Home implements OnInit, OnDestroy {
OedbApi = inject(OedbApi);
private router = inject(Router);
private osmAuth = inject(OsmAuth);
features: Array<any> = [];
filteredFeatures: Array<any> = [];
selected: any | null = null;
showTable = false;
@ -33,6 +38,11 @@ export class Home implements OnInit, OnDestroy {
autoReloadInterval: any = null;
daysAhead = 7; // Nombre de jours dans le futur par défaut
isLoading = false;
// Propriétés pour les filtres
searchText = '';
selectedWhatFilter = '';
availableWhatTypes: string[] = [];
ngOnInit() {
this.loadEvents();
@ -57,6 +67,8 @@ export class Home implements OnInit, OnDestroy {
this.OedbApi.getEvents(params).subscribe((events: any) => {
this.features = Array.isArray(events?.features) ? events.features : [];
this.updateAvailableWhatTypes();
this.applyFilters();
this.isLoading = false;
});
}
@ -89,6 +101,50 @@ export class Home implements OnInit, OnDestroy {
this.loadEvents();
}
updateAvailableWhatTypes() {
const whatTypes = new Set<string>();
this.features.forEach(feature => {
if (feature?.properties?.what) {
whatTypes.add(feature.properties.what);
}
});
this.availableWhatTypes = Array.from(whatTypes).sort();
}
onSearchChange() {
this.applyFilters();
}
onWhatFilterChange() {
this.applyFilters();
}
applyFilters() {
let filtered = [...this.features];
// Filtre par texte de recherche
if (this.searchText.trim()) {
const searchLower = this.searchText.toLowerCase();
filtered = filtered.filter(feature => {
const label = feature?.properties?.label || feature?.properties?.name || '';
const description = feature?.properties?.description || '';
const what = feature?.properties?.what || '';
return label.toLowerCase().includes(searchLower) ||
description.toLowerCase().includes(searchLower) ||
what.toLowerCase().includes(searchLower);
});
}
// Filtre par type d'événement
if (this.selectedWhatFilter) {
filtered = filtered.filter(feature =>
feature?.properties?.what === this.selectedWhatFilter
);
}
this.filteredFeatures = filtered;
}
goToNewCategories() {
this.router.navigate(['/nouvelles-categories']);
}
@ -106,9 +162,16 @@ export class Home implements OnInit, OnDestroy {
geometry: { type: 'Point', coordinates: [lon, lat] }
};
} else {
const osmUsername = this.osmAuth.getUsername();
this.selected = {
id: null,
properties: { label: '', description: '', what: '', where: '' },
properties: {
label: '',
description: '',
what: '',
where: '',
...(osmUsername && { last_modified_by: osmUsername })
},
geometry: { type: 'Point', coordinates: [lon, lat] }
};
}
@ -141,7 +204,7 @@ export class Home implements OnInit, OnDestroy {
}
downloadGeoJSON() {
const blob = new Blob([JSON.stringify({ type: 'FeatureCollection', features: this.features }, null, 2)], { type: 'application/geo+json' });
const blob = new Blob([JSON.stringify({ type: 'FeatureCollection', features: this.filteredFeatures }, null, 2)], { type: 'application/geo+json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
@ -154,7 +217,7 @@ export class Home implements OnInit, OnDestroy {
downloadCSV() {
const header = ['id', 'what', 'label', 'start', 'stop', 'lon', 'lat'];
const rows = this.features.map((f: any) => [
const rows = this.filteredFeatures.map((f: any) => [
JSON.stringify(f?.properties?.id ?? f?.id ?? ''),
JSON.stringify(f?.properties?.what ?? ''),
JSON.stringify(f?.properties?.label ?? f?.properties?.name ?? ''),

View file

@ -1,6 +1,7 @@
<menu>
OpenEventDatabase
<a routerLink="/agenda">agenda</a>
<a routerLink="/unlocated-events">événements non localisés</a>
<a href="/demo/stats">stats</a>
<a href="https://source.cipherbliss.com/tykayn/oedb-backend">sources</a>