From 83ee30e1da4b051099ac2617e1721c476a88a55c Mon Sep 17 00:00:00 2001 From: Cedric Spindler Date: Wed, 20 Sep 2023 11:54:41 +0200 Subject: [PATCH 1/5] Rename entries to notes --- src/app/app.component.ts | 8 +-- src/app/app.module.ts | 4 +- .../entry-form/entry-form.component.html | 10 ++-- .../entry-form/entry-form.component.spec.ts | 12 ++-- .../entry-form/entry-form.component.ts | 56 +++++++++---------- src/app/components/map/map.component.ts | 16 +++--- src/app/services/data.service.ts | 24 ++++---- src/app/services/entry.service.ts | 38 ++++++------- src/app/shared/entry.type.ts | 4 +- src/app/shared/tag.type.ts | 2 +- 10 files changed, 87 insertions(+), 87 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index c05840e..11dbfe6 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -2,7 +2,7 @@ import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core'; import { MatSlideToggle } from '@angular/material/slide-toggle'; import { KeycloakProfile } from 'keycloak-js'; import { Deployment } from './shared'; -import { DataService, EntryService, OidcService, ParcoursService, StateService, TrackRecorderService } from './services'; +import { DataService, NoteService, OidcService, ParcoursService, StateService, TrackRecorderService } from './services'; import pkgJson from '../../package.json'; import { AudioService } from './services/audio.service'; import { StackService } from './services/stack.service'; @@ -31,7 +31,7 @@ export class AppComponent implements OnInit, AfterViewInit { public stackService: StackService, public trackRecorder: TrackRecorderService, public audioService: AudioService, - private entryService: EntryService, + private noteService: NoteService, public dataService: DataService, public state: StateService, public authService: OidcService, @@ -44,8 +44,8 @@ export class AppComponent implements OnInit, AfterViewInit { } ngAfterViewInit() { - this.entryService.active.subscribe(state => this.toggleAddMarkers.checked = state); - this.toggleAddMarkers.change.subscribe(() => this.entryService.toggle()); + this.noteService.active.subscribe(state => this.toggleAddMarkers.checked = state); + this.toggleAddMarkers.change.subscribe(() => this.noteService.toggle()); this.toggleDebugView.change.subscribe(state => this.state.setDebugView(state.checked)); } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ae49bfb..2e1e929 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -15,7 +15,7 @@ import { KeycloakAngularModule, KeycloakService } from 'keycloak-angular'; import { MAP_STYLE_CONFIG } from './shared/configuration'; import { RecordControlComponent } from './components/record-control/record-control.component'; import { LoginComponent } from './components/login/login.component'; -import { EntryFormComponent } from './components/entry-form/entry-form.component'; +import { NoteFormComponent } from './components/entry-form/entry-form.component'; import { InfoComponent } from './components/info/info.component'; import { StackFadeComponent } from './components/stack-fade/stack-fade.component'; import { DistanceWarningDialogComponent } from './components/distance-warning-dialog.component'; @@ -62,7 +62,7 @@ function initializeKeycloak(keycloak: KeycloakService) { MapComponent, RecordControlComponent, LoginComponent, - EntryFormComponent, + NoteFormComponent, InfoComponent, StackFadeComponent, DistanceWarningDialogComponent, diff --git a/src/app/components/entry-form/entry-form.component.html b/src/app/components/entry-form/entry-form.component.html index 5e86f62..75a0a62 100644 --- a/src/app/components/entry-form/entry-form.component.html +++ b/src/app/components/entry-form/entry-form.component.html @@ -1,8 +1,8 @@ -
+ - Add entry to map - Edit entry + Add note to map + Edit note @@ -23,7 +23,7 @@ Description - + @@ -51,7 +51,7 @@ - + diff --git a/src/app/components/entry-form/entry-form.component.spec.ts b/src/app/components/entry-form/entry-form.component.spec.ts index 3e81ef5..f725b5f 100644 --- a/src/app/components/entry-form/entry-form.component.spec.ts +++ b/src/app/components/entry-form/entry-form.component.spec.ts @@ -1,18 +1,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { EntryFormComponent } from './entry-form.component'; +import { NoteFormComponent } from './entry-form.component'; -describe('EntryFormComponent', () => { - let component: EntryFormComponent; - let fixture: ComponentFixture; +describe('NoteFormComponent', () => { + let component: NoteFormComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EntryFormComponent ] + declarations: [ NoteFormComponent ] }) .compileComponents(); - fixture = TestBed.createComponent(EntryFormComponent); + fixture = TestBed.createComponent(NoteFormComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/components/entry-form/entry-form.component.ts b/src/app/components/entry-form/entry-form.component.ts index ac9a2f8..231e74d 100644 --- a/src/app/components/entry-form/entry-form.component.ts +++ b/src/app/components/entry-form/entry-form.component.ts @@ -7,7 +7,7 @@ import { MapMouseEvent } from 'maplibre-gl'; import { delayWhen, timer, Observable, throwError, of } from 'rxjs'; import { mergeMap, map, retryWhen, take, tap, catchError } from 'rxjs/operators'; import { DataService } from 'src/app/services'; -import { Entry } from 'src/app/shared'; +import { Note } from 'src/app/shared'; const genericRetryStrategy = ({ @@ -25,11 +25,11 @@ const genericRetryStrategy = ({ }; @Component({ - selector: 'app-entry-form', + selector: 'app-note-form', templateUrl: './entry-form.component.html', styleUrls: ['./entry-form.component.css'] }) -export class EntryFormComponent { +export class NoteFormComponent { public locationLoading = false; @@ -39,8 +39,8 @@ export class EntryFormComponent { 'Other', ] - public entryForm = new FormGroup({ - entry_id: new FormControl(null, { nonNullable: false}), + public noteForm = new FormGroup({ + note_id: new FormControl(null, { nonNullable: false}), name: new FormControl('', { validators: [Validators.required], nonNullable: true}), lng: new FormControl(0, { validators: [Validators.required], nonNullable: true}), lat: new FormControl(0, { validators: [Validators.required], nonNullable: true}), @@ -51,32 +51,32 @@ export class EntryFormComponent { }); constructor( - private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: { event?: MapMouseEvent & Object, entry?: Entry }, + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { event?: MapMouseEvent & Object, note?: Note }, private geolocation: GeolocationService, private dataService: DataService, private snackBar: MatSnackBar, ) { if (data.event) { - this.entryForm.patchValue(data.event.lngLat); + this.noteForm.patchValue(data.event.lngLat); } - if (data.entry) { - this.entryForm.patchValue({ - date: data.entry.date ?? new Date().toISOString(), - entry_id: data.entry.entry_id, - name: data.entry.name, - description: data.entry.description, - type: data.entry.type, - lng: data.entry.location.lon, - lat: data.entry.location.lat, + if (data.note) { + this.noteForm.patchValue({ + date: data.note.date ?? new Date().toISOString(), + note_id: data.note.note_id, + name: data.note.name, + description: data.note.description, + type: data.note.type, + lng: data.note.location.lon, + lat: data.note.location.lat, }); } } protected submit() { - const v = this.entryForm.value; - const entry = { - entry_id: v.entry_id ?? undefined, + const v = this.noteForm.value; + const note = { + note_id: v.note_id ?? undefined, date: v.date ?? undefined, name: v.name, description: v.description ?? undefined, @@ -86,17 +86,17 @@ export class EntryFormComponent { }, type: v.type ?? undefined, }; - const request = v.entry_id ? this.dataService.patchEntry(entry) : this.dataService.postEntry(entry); - request.subscribe(entry => { - this.entryForm.reset(); - this.dialogRef.close({ action: 'edit', entry: entry }); + const request = v.note_id ? this.dataService.patchNote(note) : this.dataService.postNote(note); + request.subscribe(note => { + this.noteForm.reset(); + this.dialogRef.close({ action: 'edit', note: note }); }); } protected delete() { - const entry_id = this.entryForm.controls.entry_id.value; - if (entry_id) this.dataService.deleteEntry(entry_id).subscribe( - () => this.dialogRef.close({ action: 'delete', entry: this.data.entry! })); + const note_id = this.noteForm.controls.note_id.value; + if (note_id) this.dataService.deleteNote(note_id).subscribe( + () => this.dialogRef.close({ action: 'delete', note: this.data.note! })); } @@ -117,7 +117,7 @@ export class EntryFormComponent { tap(() => this.locationLoading = false), take(1)) .subscribe((l: GeolocationPosition) => { - this.entryForm.patchValue({ + this.noteForm.patchValue({ lng: l.coords.longitude, lat: l.coords.latitude }); }); diff --git a/src/app/components/map/map.component.ts b/src/app/components/map/map.component.ts index 2c2e948..3bdeca6 100644 --- a/src/app/components/map/map.component.ts +++ b/src/app/components/map/map.component.ts @@ -4,7 +4,7 @@ import { } from '@angular/core'; import { Map, Marker, GeoJSONSource, Popup } from 'maplibre-gl'; import { Feature, Position } from 'geojson'; -import { DataService, EntryService, OidcService, ParcoursService, TrackRecorderService } from 'src/app/services'; +import { DataService, NoteService, OidcService, ParcoursService, TrackRecorderService } from 'src/app/services'; import { CoordinatePoint, Deployment, MAP_STYLE_CONFIG } from 'src/app/shared'; import { map, of, Subject, switchMap, takeUntil } from 'rxjs'; @@ -37,7 +37,7 @@ export class MapComponent implements AfterViewInit, OnDestroy { private trackRecorder: TrackRecorderService, private dataService: DataService, private authService: OidcService, - private entryService: EntryService) { + private noteService: NoteService) { // draw track this.trackRecorder.track.pipe( @@ -116,21 +116,21 @@ export class MapComponent implements AfterViewInit, OnDestroy { }); this.map.on('click', ev => { - this.entryService.add(ev); + this.noteService.add(ev); }) - this.entryService.entries.pipe(takeUntil(this.destroy)).subscribe(entries => { + this.noteService.notes.pipe(takeUntil(this.destroy)).subscribe(notes => { this.markers.forEach(m => m.remove()); - entries.forEach(m => { + notes.forEach(m => { this.markers.push(new Marker({draggable: true, scale: 0.6}) .setLngLat([m.location.lon, m.location.lat]) .on('dragend', event => { - const update = { entry_id: m.entry_id, + const update = { note_id: m.note_id, location: { lon: event.target._lngLat.lng, lat: event.target._lngLat.lat } }; - this.dataService.patchEntry(update).subscribe(() => m.location = update.location); + this.dataService.patchNote(update).subscribe(() => m.location = update.location); }) - .setPopup(new Popup().on('open', () => this.entryService.edit(m))) + .setPopup(new Popup().on('open', () => this.noteService.edit(m))) .addTo(this.map!)); }) }); diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts index 4ad2759..d16afe8 100644 --- a/src/app/services/data.service.ts +++ b/src/app/services/data.service.ts @@ -1,7 +1,7 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { Deployment, Entry, ImageStack, SectionText, StackImage, WalkPath } from '../shared'; +import { Deployment, Note, ImageStack, SectionText, StackImage, WalkPath } from '../shared'; @Injectable({ providedIn: 'root' @@ -22,28 +22,28 @@ export class DataService { return this.http.get>(`${this.apiUrl}/deployments${queryParams}`); } - public listEntries(from?: Date, to?: Date): Observable> { + public listNotes(from?: Date, to?: Date): Observable> { let params = new HttpParams() if (from) params = params.set('from', from?.toISOString()); if (to) params = params.set('to', to?.toISOString()); - return this.http.get>(`${this.apiUrl}/entries`, { params }); + return this.http.get>(`${this.apiUrl}/notes`, { params }); } - public getEntryById(id: number): Observable { - return this.http.get(`${this.apiUrl}/entry/${id}`); + public getNoteById(id: number): Observable { + return this.http.get(`${this.apiUrl}/note/${id}`); } - public postEntry(entry: Partial): Observable { - return this.http.post(`${this.apiUrl}/entries`, entry); + public postNote(note: Partial): Observable { + return this.http.post(`${this.apiUrl}/notes`, note); } - public patchEntry(entry: Partial): Observable { - if (entry.entry_id) return this.http.patch(`${this.apiUrl}/entry/${entry.entry_id}`, entry); - else throw new Error('entry is missing an ID'); + public patchNote(note: Partial): Observable { + if (note.note_id) return this.http.patch(`${this.apiUrl}/note/${note.note_id}`, note); + else throw new Error('note is missing an ID'); } - public deleteEntry(id: number): Observable { - return this.http.delete(`${this.apiUrl}/entry/${id}`); + public deleteNote(id: number): Observable { + return this.http.delete(`${this.apiUrl}/note/${id}`); } /** diff --git a/src/app/services/entry.service.ts b/src/app/services/entry.service.ts index 5d418a5..d5bd2e9 100644 --- a/src/app/services/entry.service.ts +++ b/src/app/services/entry.service.ts @@ -2,49 +2,49 @@ import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MapMouseEvent } from 'maplibre-gl'; import { BehaviorSubject } from 'rxjs'; -import { EntryFormComponent } from '../components/entry-form/entry-form.component'; +import { NoteFormComponent } from '../components/entry-form/entry-form.component'; import { DataService } from './data.service'; -import { Entry } from '../shared'; +import { Note } from '../shared'; @Injectable({ providedIn: 'root' }) -export class EntryService { +export class NoteService { - private _entries: Entry[] = []; + private _notes: Note[] = []; public active = new BehaviorSubject(false); - public entries = new BehaviorSubject([]); + public notes = new BehaviorSubject([]); constructor( private dialog: MatDialog, private dataService: DataService ) { - this.dataService.listEntries().subscribe(entries => { - this._entries = entries; - this.entries.next(this._entries); + this.dataService.listNotes().subscribe(notes => { + this._notes = notes; + this.notes.next(this._notes); }); } public add(event: MapMouseEvent & Object) { if (this.active.getValue()) { - const dialogRef = this.dialog.open(EntryFormComponent, { data: { event: event } }); - dialogRef.afterClosed().subscribe((result: { action: 'delete'|'edit', entry: Entry }) => { - if (result && result.entry) { - this._entries.push(result.entry); - this.entries.next(this._entries); + const dialogRef = this.dialog.open(NoteFormComponent, { data: { event: event } }); + dialogRef.afterClosed().subscribe((result: { action: 'delete'|'edit', note: Note }) => { + if (result && result.note) { + this._notes.push(result.note); + this.notes.next(this._notes); } }); } } - public edit(entry: Entry) { + public edit(note: Note) { if (!this.active.getValue()) { - const dialogRef = this.dialog.open(EntryFormComponent, { data: { entry: entry } }); - dialogRef.afterClosed().subscribe((result: { action: 'delete'|'edit', entry: Entry }) => { + const dialogRef = this.dialog.open(NoteFormComponent, { data: { note: note } }); + dialogRef.afterClosed().subscribe((result: { action: 'delete'|'edit', note: Note }) => { if (!result) return; - this._entries = this._entries.filter(e => e.entry_id !== result.entry.entry_id); - if (result.action === 'edit') this._entries.push(result.entry); - this.entries.next(this._entries); + this._notes = this._notes.filter(e => e.note_id !== result.note.note_id); + if (result.action === 'edit') this._notes.push(result.note); + this.notes.next(this._notes); }); } } diff --git a/src/app/shared/entry.type.ts b/src/app/shared/entry.type.ts index 8dfa918..66ba237 100644 --- a/src/app/shared/entry.type.ts +++ b/src/app/shared/entry.type.ts @@ -1,8 +1,8 @@ import { CoordinatePoint } from "./coordinate-point.type"; import { Tag } from "./tag.type"; -export interface Entry { - entry_id?: number; +export interface Note { + note_id?: number; date?: string; name: string; description?: string; diff --git a/src/app/shared/tag.type.ts b/src/app/shared/tag.type.ts index dcecba2..ab96942 100644 --- a/src/app/shared/tag.type.ts +++ b/src/app/shared/tag.type.ts @@ -2,7 +2,7 @@ export type Tag = { tag_id?: number; name: string; deployments?: number; - entries?: number; + notes?: number; created_at?: string; updated_at?: string; }; From 5c83b9e4ec9e7cb6de9cb7f77ffeaed665babdc1 Mon Sep 17 00:00:00 2001 From: Cedric Spindler Date: Wed, 20 Sep 2023 12:01:39 +0200 Subject: [PATCH 2/5] Update Note interface --- src/app/components/entry-form/entry-form.component.ts | 6 +++--- src/app/shared/entry.type.ts | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/app/components/entry-form/entry-form.component.ts b/src/app/components/entry-form/entry-form.component.ts index 231e74d..afc01a6 100644 --- a/src/app/components/entry-form/entry-form.component.ts +++ b/src/app/components/entry-form/entry-form.component.ts @@ -64,11 +64,11 @@ export class NoteFormComponent { this.noteForm.patchValue({ date: data.note.date ?? new Date().toISOString(), note_id: data.note.note_id, - name: data.note.name, + name: data.note.title, description: data.note.description, type: data.note.type, - lng: data.note.location.lon, - lat: data.note.location.lat, + lng: data.note.location?.lon, + lat: data.note.location?.lat, }); } } diff --git a/src/app/shared/entry.type.ts b/src/app/shared/entry.type.ts index 66ba237..1bd08a9 100644 --- a/src/app/shared/entry.type.ts +++ b/src/app/shared/entry.type.ts @@ -4,9 +4,10 @@ import { Tag } from "./tag.type"; export interface Note { note_id?: number; date?: string; - name: string; + title: string; description?: string; - location: CoordinatePoint; + location?: CoordinatePoint; type?: string; tags?: Tag[]; + files?: string[]; } From 4b68c7329ba15ce926794aae52dd4e7a94d75d0a Mon Sep 17 00:00:00 2001 From: Cedric Spindler Date: Wed, 20 Sep 2023 15:57:01 +0200 Subject: [PATCH 3/5] Rename name attribute to title --- src/app/components/entry-form/entry-form.component.html | 4 ++-- src/app/components/entry-form/entry-form.component.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/components/entry-form/entry-form.component.html b/src/app/components/entry-form/entry-form.component.html index 75a0a62..1e43eb3 100644 --- a/src/app/components/entry-form/entry-form.component.html +++ b/src/app/components/entry-form/entry-form.component.html @@ -7,8 +7,8 @@ - Name - + Title + diff --git a/src/app/components/entry-form/entry-form.component.ts b/src/app/components/entry-form/entry-form.component.ts index afc01a6..4e1c05b 100644 --- a/src/app/components/entry-form/entry-form.component.ts +++ b/src/app/components/entry-form/entry-form.component.ts @@ -41,7 +41,7 @@ export class NoteFormComponent { public noteForm = new FormGroup({ note_id: new FormControl(null, { nonNullable: false}), - name: new FormControl('', { validators: [Validators.required], nonNullable: true}), + title: new FormControl('', { validators: [Validators.required], nonNullable: true}), lng: new FormControl(0, { validators: [Validators.required], nonNullable: true}), lat: new FormControl(0, { validators: [Validators.required], nonNullable: true}), date: new FormControl(null, { validators: [], nonNullable: false}), @@ -64,7 +64,7 @@ export class NoteFormComponent { this.noteForm.patchValue({ date: data.note.date ?? new Date().toISOString(), note_id: data.note.note_id, - name: data.note.title, + title: data.note.title, description: data.note.description, type: data.note.type, lng: data.note.location?.lon, @@ -78,7 +78,7 @@ export class NoteFormComponent { const note = { note_id: v.note_id ?? undefined, date: v.date ?? undefined, - name: v.name, + title: v.title, description: v.description ?? undefined, location: { lat: v.lat!, From 566bef6fcd9b4a474b5ab1acb42ed697077e4d37 Mon Sep 17 00:00:00 2001 From: Cedric Spindler Date: Wed, 20 Sep 2023 15:57:15 +0200 Subject: [PATCH 4/5] Remove notes without location --- src/app/components/map/map.component.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/components/map/map.component.ts b/src/app/components/map/map.component.ts index 3bdeca6..085bed3 100644 --- a/src/app/components/map/map.component.ts +++ b/src/app/components/map/map.component.ts @@ -121,9 +121,10 @@ export class MapComponent implements AfterViewInit, OnDestroy { this.noteService.notes.pipe(takeUntil(this.destroy)).subscribe(notes => { this.markers.forEach(m => m.remove()); - notes.forEach(m => { + notes.filter(n => n.location !== undefined || n.location !== null) + .forEach(m => { this.markers.push(new Marker({draggable: true, scale: 0.6}) - .setLngLat([m.location.lon, m.location.lat]) + .setLngLat([m.location!.lon, m.location!.lat]) .on('dragend', event => { const update = { note_id: m.note_id, location: { lon: event.target._lngLat.lng, lat: event.target._lngLat.lat } From 15295b14e3150a9d23cba4b0961fb10d7ecd8723 Mon Sep 17 00:00:00 2001 From: Cedric Spindler Date: Wed, 20 Sep 2023 15:57:38 +0200 Subject: [PATCH 5/5] Add public flag and author to note interface --- src/app/shared/entry.type.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/shared/entry.type.ts b/src/app/shared/entry.type.ts index 1bd08a9..7ef93be 100644 --- a/src/app/shared/entry.type.ts +++ b/src/app/shared/entry.type.ts @@ -8,6 +8,8 @@ export interface Note { description?: string; location?: CoordinatePoint; type?: string; + public: boolean; + author: string; tags?: Tag[]; files?: string[]; }