migrate angular 21 finalize
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, inject} from '@angular/core';
|
||||
import {File} from './file';
|
||||
import {Observable} from 'rxjs';
|
||||
import {FileServer} from './fileServer';
|
||||
@@ -8,7 +8,7 @@ import {DbService} from '../../../services/db.service';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class FileDataService {
|
||||
public constructor(private db: DbService) {}
|
||||
private db = inject(DbService);
|
||||
|
||||
public async set(songId: string, file: FileServer): Promise<string> {
|
||||
const songRef = this.db.doc('songs/' + songId);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, inject} from '@angular/core';
|
||||
import {deleteObject, getDownloadURL, ref, Storage} from '@angular/fire/storage';
|
||||
import {from, Observable} from 'rxjs';
|
||||
import {FileDataService} from './file-data.service';
|
||||
@@ -7,10 +7,8 @@ import {FileDataService} from './file-data.service';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class FileService {
|
||||
public constructor(
|
||||
private storage: Storage,
|
||||
private fileDataService: FileDataService
|
||||
) {}
|
||||
private storage = inject(Storage);
|
||||
private fileDataService = inject(FileDataService);
|
||||
|
||||
public getDownloadUrl(path: string): Observable<string> {
|
||||
return from(getDownloadURL(ref(this.storage, path)));
|
||||
|
||||
@@ -2,14 +2,14 @@ import {getScale, scaleMapping} from './key.helper';
|
||||
|
||||
describe('key.helper', () => {
|
||||
it('should render Gb correctly', () => {
|
||||
expect(scaleMapping['Gb']).toBe('G♭');
|
||||
void expect(scaleMapping['Gb']).toBe('G♭');
|
||||
});
|
||||
|
||||
it('should expose a sharp-based scale for D', () => {
|
||||
expect(getScale('D')).toEqual(['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H']);
|
||||
void expect(getScale('D')).toEqual(['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H']);
|
||||
});
|
||||
|
||||
it('should keep flat-based spelling for Db', () => {
|
||||
expect(getScale('Db')).toEqual(['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'H']);
|
||||
void expect(getScale('Db')).toEqual(['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'H']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, inject} from '@angular/core';
|
||||
import {Song} from './song';
|
||||
import {Observable} from 'rxjs';
|
||||
import {DbService} from '../../../services/db.service';
|
||||
@@ -8,6 +8,8 @@ import {shareReplay, startWith} from 'rxjs/operators';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SongDataService {
|
||||
private dbService = inject(DbService);
|
||||
|
||||
private collection = 'songs';
|
||||
public list$: Observable<Song[]> = this.dbService.col$<Song>(this.collection).pipe(
|
||||
startWith([] as Song[]), // immediate empty emit keeps UI responsive while first snapshot arrives
|
||||
@@ -17,11 +19,6 @@ export class SongDataService {
|
||||
})
|
||||
);
|
||||
|
||||
public constructor(private dbService: DbService) {
|
||||
// Warm the shared stream once at startup to avoid first-navigation delay.
|
||||
// this.list$.subscribe();
|
||||
}
|
||||
|
||||
public read$ = (songId: string): Observable<Song | null> => this.dbService.doc$(this.collection + '/' + songId);
|
||||
public update$ = async (songId: string, data: Partial<Song>): Promise<void> => await this.dbService.doc(this.collection + '/' + songId).update(data);
|
||||
public add = async (data: Partial<Song>): Promise<string> => (await this.dbService.col(this.collection).add(data)).id;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, inject} from '@angular/core';
|
||||
|
||||
import {Observable} from 'rxjs';
|
||||
import {SongService} from './song.service';
|
||||
@@ -9,7 +9,7 @@ import {take} from 'rxjs/operators';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SongListResolver {
|
||||
public constructor(private songService: SongService) {}
|
||||
private songService = inject(SongService);
|
||||
|
||||
public resolve(): Observable<Song[]> {
|
||||
return this.songService.list$().pipe(take(1));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, inject} from '@angular/core';
|
||||
import {firstValueFrom, Observable} from 'rxjs';
|
||||
import {Song} from './song';
|
||||
import {SongDataService} from './song-data.service';
|
||||
@@ -16,21 +16,15 @@ export type SongLegalType = 'open' | 'allowed';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SongService {
|
||||
private songDataService = inject(SongDataService);
|
||||
private userService = inject(UserService);
|
||||
|
||||
public static TYPES: SongType[] = ['Praise', 'Worship', 'Misc'];
|
||||
public static STATUS: SongStatus[] = ['draft', 'set', 'final'];
|
||||
|
||||
public static LEGAL_OWNER: SongLegalOwner[] = ['CCLI', 'other'];
|
||||
public static LEGAL_TYPE: SongLegalType[] = ['open', 'allowed'];
|
||||
|
||||
// private list: Song[];
|
||||
|
||||
public constructor(
|
||||
private songDataService: SongDataService,
|
||||
private userService: UserService
|
||||
) {
|
||||
// importCCLI = (songs: Song[]) => this.updateFromCLI(songs);
|
||||
}
|
||||
|
||||
public list$ = (): Observable<Song[]> => this.songDataService.list$; //.pipe(tap(_ => (this.list = _)));
|
||||
public read$ = (songId: string): Observable<Song | null> => this.songDataService.read$(songId);
|
||||
public read = (songId: string): Promise<Song | null> => firstValueFrom(this.read$(songId));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, inject} from '@angular/core';
|
||||
import {TransposeService} from './transpose.service';
|
||||
import {TransposeMode} from './transpose-mode';
|
||||
import {SectionType} from './section-type';
|
||||
@@ -11,9 +11,9 @@ import {Line} from './line';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class TextRenderingService {
|
||||
private regexSection = /(Strophe|Refrain|Bridge)/;
|
||||
private transposeService = inject(TransposeService);
|
||||
|
||||
public constructor(private transposeService: TransposeService) {}
|
||||
private regexSection = /(Strophe|Refrain|Bridge)/;
|
||||
|
||||
public parse(text: string, transpose: TransposeMode | null, withComments = true): Section[] {
|
||||
if (!text) {
|
||||
|
||||
@@ -34,18 +34,18 @@ describe('TransposeService', () => {
|
||||
const distance = service.getDistance('C', 'Db');
|
||||
const map = service.getMap('C', 'Db', distance);
|
||||
|
||||
expect(distance).toBe(1);
|
||||
expect(map?.['C']).toBe('Db');
|
||||
expect(map?.['G']).toBe('Ab');
|
||||
void expect(distance).toBe(1);
|
||||
void expect(map?.['C']).toBe('Db');
|
||||
void expect(map?.['G']).toBe('Ab');
|
||||
});
|
||||
|
||||
it('should keep german B/H notation consistent', () => {
|
||||
const distance = service.getDistance('H', 'C');
|
||||
const map = service.getMap('H', 'C', distance);
|
||||
|
||||
expect(distance).toBe(1);
|
||||
expect(map?.['H']).toBe('C');
|
||||
expect(map?.['B']).toBe('C#');
|
||||
void expect(distance).toBe(1);
|
||||
void expect(map?.['H']).toBe('C');
|
||||
void expect(map?.['B']).toBe('C#');
|
||||
});
|
||||
|
||||
it('should render unknown chords as X', () => {
|
||||
@@ -57,7 +57,7 @@ describe('TransposeService', () => {
|
||||
|
||||
const rendered = service.renderChords(line);
|
||||
|
||||
expect(rendered.text).toBe('Xsus4');
|
||||
void expect(rendered.text).toBe('Xsus4');
|
||||
});
|
||||
|
||||
it('should render unknown slash chords as X', () => {
|
||||
@@ -69,7 +69,7 @@ describe('TransposeService', () => {
|
||||
|
||||
const rendered = service.renderChords(line);
|
||||
|
||||
expect(rendered.text).toBe('C/X');
|
||||
void expect(rendered.text).toBe('C/X');
|
||||
});
|
||||
|
||||
it('should transpose lines with long chord positions without truncating', () => {
|
||||
@@ -81,7 +81,7 @@ describe('TransposeService', () => {
|
||||
|
||||
const rendered = service.renderChords(line);
|
||||
|
||||
expect(rendered.text.length).toBe(121);
|
||||
expect(rendered.text.endsWith('C')).toBeTrue();
|
||||
void expect(rendered.text.length).toBe(121);
|
||||
void expect(rendered.text.endsWith('C')).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, inject} from '@angular/core';
|
||||
import {Upload} from './upload';
|
||||
import {FileDataService} from './file-data.service';
|
||||
import {ref, Storage, uploadBytesResumable} from '@angular/fire/storage';
|
||||
@@ -9,12 +9,8 @@ import {FileServer} from './fileServer';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UploadService extends FileBase {
|
||||
public constructor(
|
||||
private fileDataService: FileDataService,
|
||||
private storage: Storage
|
||||
) {
|
||||
super();
|
||||
}
|
||||
private fileDataService = inject(FileDataService);
|
||||
private storage = inject(Storage);
|
||||
|
||||
public pushUpload(songId: string, upload: Upload): void {
|
||||
const directory = this.directory(songId);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Component, Input, inject} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup} from '@angular/forms';
|
||||
import {SongService} from '../../services/song.service';
|
||||
@@ -21,6 +21,8 @@ import {SongTypePipe} from '../../../../widget-modules/pipes/song-type-translate
|
||||
imports: [ReactiveFormsModule, MatFormField, MatLabel, MatInput, MatSelect, MatOption, LegalTypePipe, KeyPipe, SongTypePipe],
|
||||
})
|
||||
export class FilterComponent {
|
||||
private router = inject(Router);
|
||||
|
||||
public filterFormGroup: UntypedFormGroup;
|
||||
@Input() public route = '/';
|
||||
@Input() public songs: Song[] = [];
|
||||
@@ -28,11 +30,10 @@ export class FilterComponent {
|
||||
public legalType = SongService.LEGAL_TYPE;
|
||||
public keys = KEYS;
|
||||
|
||||
public constructor(
|
||||
private router: Router,
|
||||
activatedRoute: ActivatedRoute,
|
||||
fb: UntypedFormBuilder
|
||||
) {
|
||||
public constructor() {
|
||||
const activatedRoute = inject(ActivatedRoute);
|
||||
const fb = inject(UntypedFormBuilder);
|
||||
|
||||
this.filterFormGroup = fb.group({
|
||||
q: '',
|
||||
type: '',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {ChangeDetectionStrategy, Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, OnDestroy, OnInit, inject} from '@angular/core';
|
||||
import {SongService} from '../services/song.service';
|
||||
import {Song} from '../services/song';
|
||||
import {map} from 'rxjs/operators';
|
||||
@@ -25,6 +25,10 @@ import {FaIconComponent} from '@fortawesome/angular-fontawesome';
|
||||
imports: [ListHeaderComponent, FilterComponent, CardComponent, RouterLink, RoleDirective, FaIconComponent, AsyncPipe],
|
||||
})
|
||||
export class SongListComponent implements OnInit, OnDestroy {
|
||||
private songService = inject(SongService);
|
||||
private activatedRoute = inject(ActivatedRoute);
|
||||
private scrollService = inject(ScrollService);
|
||||
|
||||
public anyFilterActive = false;
|
||||
public songs$: Observable<Song[]> = combineLatest([
|
||||
this.activatedRoute.queryParams.pipe(map(_ => _ as FilterValues)),
|
||||
@@ -39,12 +43,6 @@ export class SongListComponent implements OnInit, OnDestroy {
|
||||
public faDraft = faPencilRuler;
|
||||
public faFinal = faCheck;
|
||||
|
||||
public constructor(
|
||||
private songService: SongService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private scrollService: ScrollService
|
||||
) {}
|
||||
|
||||
public ngOnInit(): void {
|
||||
setTimeout(() => this.scrollService.restoreScrollPositionFor('songlist'), 100);
|
||||
setTimeout(() => this.scrollService.restoreScrollPositionFor('songlist'), 300);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component} from '@angular/core';
|
||||
import {Component, inject} from '@angular/core';
|
||||
import {Upload} from '../../../services/upload';
|
||||
import {UploadService} from '../../../services/upload.service';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
@@ -19,16 +19,16 @@ import {FileComponent} from './file/file.component';
|
||||
imports: [CardComponent, NgStyle, MatIconButton, MatIcon, FileComponent, AsyncPipe],
|
||||
})
|
||||
export class EditFileComponent {
|
||||
private activatedRoute = inject(ActivatedRoute);
|
||||
private uploadService = inject(UploadService);
|
||||
private fileService = inject(FileDataService);
|
||||
|
||||
public selectedFiles: FileList | null = null;
|
||||
public currentUpload: Upload | null = null;
|
||||
public songId: string | null = null;
|
||||
public files$: Observable<File[]>;
|
||||
|
||||
public constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private uploadService: UploadService,
|
||||
private fileService: FileDataService
|
||||
) {
|
||||
public constructor() {
|
||||
this.activatedRoute.params
|
||||
.pipe(
|
||||
map(param => param as {songId: string}),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Component, Input, inject} from '@angular/core';
|
||||
import {Observable} from 'rxjs';
|
||||
import {File} from '../../../../services/file';
|
||||
import {faTrashAlt} from '@fortawesome/free-solid-svg-icons';
|
||||
@@ -14,6 +14,8 @@ import {AsyncPipe} from '@angular/common';
|
||||
imports: [MatIconButton, FaIconComponent, AsyncPipe],
|
||||
})
|
||||
export class FileComponent {
|
||||
private fileService = inject(FileService);
|
||||
|
||||
public url$: Observable<string> | null = null;
|
||||
public name = '';
|
||||
public faTrash = faTrashAlt;
|
||||
@@ -21,8 +23,6 @@ export class FileComponent {
|
||||
private fileId: string | null = null;
|
||||
private path: string | null = null;
|
||||
|
||||
public constructor(private fileService: FileService) {}
|
||||
|
||||
@Input()
|
||||
public set file(file: File) {
|
||||
this.url$ = this.fileService.getDownloadUrl(file.path + '/' + file.name);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Component, OnInit, inject} from '@angular/core';
|
||||
import {Song} from '../../../services/song';
|
||||
import {ReactiveFormsModule, UntypedFormGroup} from '@angular/forms';
|
||||
import {ActivatedRoute, Router, RouterStateSnapshot} from '@angular/router';
|
||||
@@ -59,6 +59,12 @@ import {StatusPipe} from '../../../../../widget-modules/pipes/status-translater/
|
||||
],
|
||||
})
|
||||
export class EditSongComponent implements OnInit {
|
||||
private activatedRoute = inject(ActivatedRoute);
|
||||
private songService = inject(SongService);
|
||||
private editService = inject(EditService);
|
||||
private router = inject(Router);
|
||||
public dialog = inject(MatDialog);
|
||||
|
||||
public song: Song | null = null;
|
||||
public form: UntypedFormGroup = new UntypedFormGroup({});
|
||||
public keys = KEYS;
|
||||
@@ -73,14 +79,6 @@ export class EditSongComponent implements OnInit {
|
||||
public faLink = faExternalLinkAlt;
|
||||
public songtextFocus = false;
|
||||
|
||||
public constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private songService: SongService,
|
||||
private editService: EditService,
|
||||
private router: Router,
|
||||
public dialog: MatDialog
|
||||
) {}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.activatedRoute.params
|
||||
.pipe(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Component, OnInit, inject} from '@angular/core';
|
||||
import {first, map, switchMap} from 'rxjs/operators';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {SongService} from '../../../services/song.service';
|
||||
@@ -13,12 +13,10 @@ import {CardComponent} from '../../../../../widget-modules/components/card/card.
|
||||
imports: [CardComponent, DatePipe],
|
||||
})
|
||||
export class HistoryComponent implements OnInit {
|
||||
public song: Song | null = null;
|
||||
private activatedRoute = inject(ActivatedRoute);
|
||||
private songService = inject(SongService);
|
||||
|
||||
public constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private songService: SongService
|
||||
) {}
|
||||
public song: Song | null = null;
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.activatedRoute.params
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Component, Input, inject} from '@angular/core';
|
||||
import {File} from '../../services/file';
|
||||
import {getDownloadURL, ref, Storage} from '@angular/fire/storage';
|
||||
import {from, Observable} from 'rxjs';
|
||||
@@ -11,11 +11,11 @@ import {AsyncPipe} from '@angular/common';
|
||||
imports: [AsyncPipe],
|
||||
})
|
||||
export class FileComponent {
|
||||
private storage = inject(Storage);
|
||||
|
||||
public url$: Observable<string> | null = null;
|
||||
public name = '';
|
||||
|
||||
public constructor(private storage: Storage) {}
|
||||
|
||||
@Input()
|
||||
public set file(file: File) {
|
||||
this.url$ = from(getDownloadURL(ref(this.storage, file.path + '/' + file.name)));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {Component, OnDestroy, OnInit, inject} from '@angular/core';
|
||||
import {faSave} from '@fortawesome/free-solid-svg-icons';
|
||||
import {ReactiveFormsModule, UntypedFormControl, UntypedFormGroup, Validators} from '@angular/forms';
|
||||
import {SongService} from '../../services/song.service';
|
||||
@@ -19,6 +19,9 @@ import {ButtonComponent} from '../../../../widget-modules/components/button/butt
|
||||
imports: [CardComponent, ReactiveFormsModule, MatFormField, MatLabel, MatInput, ButtonRowComponent, ButtonComponent],
|
||||
})
|
||||
export class NewComponent implements OnInit, OnDestroy {
|
||||
private songService = inject(SongService);
|
||||
private router = inject(Router);
|
||||
|
||||
public faSave = faSave;
|
||||
public form: UntypedFormGroup = new UntypedFormGroup({
|
||||
number: new UntypedFormControl(null, Validators.required),
|
||||
@@ -26,11 +29,6 @@ export class NewComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
private subs: Subscription[] = [];
|
||||
|
||||
public constructor(
|
||||
private songService: SongService,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.form.reset();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Component, OnInit, inject} from '@angular/core';
|
||||
import {ActivatedRoute, Router, RouterLink} from '@angular/router';
|
||||
import {SongService} from '../services/song.service';
|
||||
import {distinctUntilChanged, map, switchMap} from 'rxjs/operators';
|
||||
@@ -51,6 +51,14 @@ import {ShowTypePipe} from '../../../widget-modules/pipes/show-type-translater/s
|
||||
],
|
||||
})
|
||||
export class SongComponent implements OnInit {
|
||||
private activatedRoute = inject(ActivatedRoute);
|
||||
private songService = inject(SongService);
|
||||
private fileService = inject(FileDataService);
|
||||
private userService = inject(UserService);
|
||||
private router = inject(Router);
|
||||
private showService = inject(ShowService);
|
||||
private showSongService = inject(ShowSongService);
|
||||
|
||||
public song$: Observable<Song | null> | null = null;
|
||||
public files$: Observable<File[] | null> | null = null;
|
||||
public user$: Observable<User | null> | null = null;
|
||||
@@ -60,15 +68,9 @@ export class SongComponent implements OnInit {
|
||||
public faFileCirclePlus = faFileCirclePlus;
|
||||
public privateShows$ = this.showService.list$().pipe(map(show => show.filter(_ => !_.published).sort((a, b) => b.date.toMillis() - a.date.toMillis())));
|
||||
|
||||
public constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private songService: SongService,
|
||||
private fileService: FileDataService,
|
||||
private userService: UserService,
|
||||
private router: Router,
|
||||
private showService: ShowService,
|
||||
private showSongService: ShowSongService
|
||||
) {
|
||||
public constructor() {
|
||||
const userService = this.userService;
|
||||
|
||||
this.user$ = userService.user$;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user