Cleanup Code
This commit is contained in:
@@ -1,21 +1,22 @@
|
|||||||
import { SongsComponent } from './components/songs/songs.component';
|
import {SongsComponent} from './components/songs/songs.component';
|
||||||
import { NgModule } from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'songs',
|
path: 'songs',
|
||||||
component: SongsComponent
|
component: SongsComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
redirectTo: 'songs',
|
redirectTo: 'songs',
|
||||||
pathMatch: 'full'
|
pathMatch: 'full'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [RouterModule.forRoot(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
export class AppRoutingModule { }
|
export class AppRoutingModule {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.less']
|
styleUrls: ['./app.component.less']
|
||||||
})
|
})
|
||||||
export class AppComponent { }
|
export class AppComponent {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,69 +1,70 @@
|
|||||||
import { BrowserModule } from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
import { NgModule } from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||||
import { ODataModule } from 'odata-v4-ng';
|
import {ODataModule} from 'odata-v4-ng';
|
||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import {AppRoutingModule} from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import {HttpClientModule} from '@angular/common/http';
|
||||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import {MatInputModule} from '@angular/material/input';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import {MatTableModule} from '@angular/material/table';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import {MatCardModule} from '@angular/material/card';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import {MatButtonModule} from '@angular/material/button';
|
||||||
import { MatChipsModule } from '@angular/material/chips';
|
import {MatChipsModule} from '@angular/material/chips';
|
||||||
import { MatRadioModule } from '@angular/material/radio';
|
import {MatRadioModule} from '@angular/material/radio';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import {MatSelectModule} from '@angular/material/select';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import {MatTooltipModule} from '@angular/material/tooltip';
|
||||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
import {MatProgressBarModule} from '@angular/material/progress-bar';
|
||||||
|
|
||||||
import { TableComponent } from './components/songs/table/table.component';
|
import {TableComponent} from './components/songs/table/table.component';
|
||||||
import { SongsComponent } from './components/songs/songs.component';
|
import {SongsComponent} from './components/songs/songs.component';
|
||||||
import { SongComponent } from './components/songs/song/song.component';
|
import {SongComponent} from './components/songs/song/song.component';
|
||||||
import { SongEditComponent } from './components/songs/song-edit/song-edit.component';
|
import {SongEditComponent} from './components/songs/song-edit/song-edit.component';
|
||||||
import { SongNewComponent } from './components/songs/song-new/song-new.component';
|
import {SongNewComponent} from './components/songs/song-new/song-new.component';
|
||||||
import { SongFormComponent } from './components/songs/song-form/song-form.component';
|
import {SongFormComponent} from './components/songs/song-form/song-form.component';
|
||||||
import { SongFilesComponent } from './components/songs/song-files/song-files.component';
|
import {SongFilesComponent} from './components/songs/song-files/song-files.component';
|
||||||
import { FileUploadModule } from 'ng2-file-upload';
|
import {FileUploadModule} from 'ng2-file-upload';
|
||||||
import { SongFileEditComponent } from './components/songs/song-file-edit/song-file-edit.component';
|
import {SongFileEditComponent} from './components/songs/song-file-edit/song-file-edit.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
SongsComponent,
|
SongsComponent,
|
||||||
TableComponent,
|
TableComponent,
|
||||||
SongComponent,
|
SongComponent,
|
||||||
SongEditComponent,
|
SongEditComponent,
|
||||||
SongNewComponent,
|
SongNewComponent,
|
||||||
SongFormComponent,
|
SongFormComponent,
|
||||||
SongFilesComponent,
|
SongFilesComponent,
|
||||||
SongFileEditComponent
|
SongFileEditComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
ODataModule,
|
ODataModule,
|
||||||
|
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatCardModule,
|
MatCardModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatChipsModule,
|
MatChipsModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatProgressBarModule,
|
MatProgressBarModule,
|
||||||
|
|
||||||
FontAwesomeModule,
|
FontAwesomeModule,
|
||||||
FileUploadModule,
|
FileUploadModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
<div class="song-detail-container">
|
<div class="song-detail-container">
|
||||||
<mat-card class="mat-elevation-z8" *ngIf="form">
|
<mat-card *ngIf="form" class="mat-elevation-z8">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<div mat-card-avatar>
|
<div mat-card-avatar>
|
||||||
<button mat-icon-button (click)="onBack()" color="warn">
|
<button (click)="onBack()" color="warn" mat-icon-button>
|
||||||
<fa-icon [icon]="faArrow"></fa-icon>
|
<fa-icon [icon]="faArrow"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<mat-card-title>Titel bearbeiten</mat-card-title>
|
<mat-card-title>Titel bearbeiten</mat-card-title>
|
||||||
<mat-card-subtitle>
|
<mat-card-subtitle>
|
||||||
Daten werden nach der Eingabe automatisch gespeichert
|
Daten werden nach der Eingabe automatisch gespeichert
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<app-song-form [form]="form"></app-song-form>
|
<app-song-form [form]="form"></app-song-form>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<!-- <mat-card-actions>
|
<!-- <mat-card-actions>
|
||||||
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
||||||
<button mat-button (click)="onClickEdit()">
|
<button mat-button (click)="onClickEdit()">
|
||||||
<fa-icon [icon]="faEdit"></fa-icon> Bearbeiten
|
<fa-icon [icon]="faEdit"></fa-icon> Bearbeiten
|
||||||
</button>
|
</button>
|
||||||
</mat-card-actions> -->
|
</mat-card-actions> -->
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,34 @@
|
|||||||
import { SongsService } from 'src/app/data/songs.service';
|
import {SongsService} from 'src/app/data/songs.service';
|
||||||
import { FormGroup } from '@angular/forms';
|
import {FormGroup} from '@angular/forms';
|
||||||
import {
|
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core';
|
||||||
Component,
|
import {EditSongService} from 'src/app/data/edit-song.service';
|
||||||
OnInit,
|
import {faLongArrowAltLeft} from '@fortawesome/free-solid-svg-icons';
|
||||||
ChangeDetectionStrategy,
|
import {State} from 'src/app/data/state';
|
||||||
ChangeDetectorRef
|
|
||||||
} from '@angular/core';
|
|
||||||
import { EditSongService } from 'src/app/data/edit-song.service';
|
|
||||||
import { faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import { State } from 'src/app/data/state';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-song-edit',
|
selector: 'app-song-edit',
|
||||||
templateUrl: './song-edit.component.html',
|
templateUrl: './song-edit.component.html',
|
||||||
styleUrls: ['./song-edit.component.less'],
|
styleUrls: ['./song-edit.component.less'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SongEditComponent implements OnInit {
|
export class SongEditComponent implements OnInit {
|
||||||
public form: FormGroup = null;
|
public form: FormGroup = null;
|
||||||
public faArrow = faLongArrowAltLeft;
|
public faArrow = faLongArrowAltLeft;
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private editSongService: EditSongService,
|
private editSongService: EditSongService,
|
||||||
private songsService: SongsService,
|
private songsService: SongsService,
|
||||||
private change: ChangeDetectorRef
|
private change: ChangeDetectorRef
|
||||||
) {}
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.form = this.editSongService.initSongEditForm(true);
|
this.form = this.editSongService.initSongEditForm(true);
|
||||||
this.change.markForCheck();
|
this.change.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onBack(): void {
|
public onBack(): void {
|
||||||
this.songsService.state = State.read;
|
this.songsService.state = State.read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<form *ngIf="form">
|
<form *ngIf="form">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input
|
<input
|
||||||
matInput
|
[formControl]="form.controls.Name"
|
||||||
placeholder="Dateiname"
|
matInput
|
||||||
[formControl]="form.controls.Name"
|
placeholder="Dateiname"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Art</mat-label>
|
<mat-label>Art</mat-label>
|
||||||
<mat-select [formControl]="form.controls.FileType">
|
<mat-select [formControl]="form.controls.FileType">
|
||||||
<mat-option *ngFor="let type of fileTypes" [value]="type.value">
|
<mat-option *ngFor="let type of fileTypes" [value]="type.value">
|
||||||
{{ type.text }}
|
{{ type.text }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
form {
|
form {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr 1fr;
|
grid-template-columns: 2fr 1fr;
|
||||||
grid-column-gap: 10px;
|
grid-column-gap: 10px;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
@@ -1,50 +1,44 @@
|
|||||||
import { SongsService } from './../../../data/songs.service';
|
import {SongsService} from '../../../data/songs.service';
|
||||||
import { FileType } from './../../../models/files-types.model.ts';
|
import {FileType} from '../../../models/files-types.model.ts';
|
||||||
import { FormGroup } from '@angular/forms';
|
import {FormGroup} from '@angular/forms';
|
||||||
import {
|
import {Component, EventEmitter, Input, OnDestroy, OnInit, Output} from '@angular/core';
|
||||||
Component,
|
import {EditSongService} from 'src/app/data/edit-song.service';
|
||||||
OnInit,
|
import {Subscription} from 'rxjs';
|
||||||
OnDestroy,
|
|
||||||
Input,
|
|
||||||
Output,
|
|
||||||
EventEmitter
|
|
||||||
} from '@angular/core';
|
|
||||||
import { EditSongService } from 'src/app/data/edit-song.service';
|
|
||||||
import { Subscription } from 'rxjs';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-song-file-edit',
|
selector: 'app-song-file-edit',
|
||||||
templateUrl: './song-file-edit.component.html',
|
templateUrl: './song-file-edit.component.html',
|
||||||
styleUrls: ['./song-file-edit.component.less']
|
styleUrls: ['./song-file-edit.component.less']
|
||||||
})
|
})
|
||||||
export class SongFileEditComponent implements OnInit, OnDestroy {
|
export class SongFileEditComponent implements OnInit, OnDestroy {
|
||||||
@Input() fileId: number;
|
@Input() fileId: number;
|
||||||
@Output() back = new EventEmitter();
|
@Output() back = new EventEmitter();
|
||||||
public form: FormGroup;
|
public form: FormGroup;
|
||||||
public subscription: Subscription;
|
public subscription: Subscription;
|
||||||
public fileTypes = [
|
public fileTypes = [
|
||||||
{ value: FileType.None, text: null },
|
{value: FileType.None, text: null},
|
||||||
{ value: FileType.Sheet, text: 'Text' },
|
{value: FileType.Sheet, text: 'Text'},
|
||||||
{ value: FileType.Chords, text: 'Text + Akkorde' },
|
{value: FileType.Chords, text: 'Text + Akkorde'},
|
||||||
{ value: FileType.MuseScore, text: 'MuseScore' }
|
{value: FileType.MuseScore, text: 'MuseScore'}
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private editSongService: EditSongService,
|
private editSongService: EditSongService,
|
||||||
private songService: SongsService
|
private songService: SongsService
|
||||||
) {}
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
const form = this.editSongService.initFileEditForm(
|
const form = this.editSongService.initFileEditForm(
|
||||||
this.songService.selectedSong.value.ID,
|
this.songService.selectedSong.value.ID,
|
||||||
this.fileId
|
this.fileId
|
||||||
);
|
);
|
||||||
this.form = form.form;
|
this.form = form.form;
|
||||||
this.subscription = form.changeSubscription;
|
this.subscription = form.changeSubscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnDestroy(): void {
|
public ngOnDestroy(): void {
|
||||||
this.form = null;
|
this.form = null;
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +1,90 @@
|
|||||||
<div class="song-detail-container files" *ngIf="song">
|
<div *ngIf="song" class="song-detail-container files">
|
||||||
<mat-card class="mat-elevation-z8">
|
<mat-card class="mat-elevation-z8">
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<table mat-table [dataSource]="song.Files" class="mat-elevation-z8">
|
<table [dataSource]="song.Files" class="mat-elevation-z8" mat-table>
|
||||||
<ng-container matColumnDef="name">
|
<ng-container matColumnDef="name">
|
||||||
<th mat-header-cell *matHeaderCellDef>
|
<th *matHeaderCellDef mat-header-cell>
|
||||||
Angehängte Dateien
|
Angehängte Dateien
|
||||||
</th>
|
</th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td *matCellDef="let element" mat-cell>
|
||||||
<span *ngIf="fileEditId !== element.ID">{{ element.Name }}</span>
|
<span *ngIf="fileEditId !== element.ID">{{ element.Name }}</span>
|
||||||
<app-song-file-edit
|
<app-song-file-edit
|
||||||
[fileId]="element.ID"
|
(back)="onClickEdit(null)"
|
||||||
(back)="onClickEdit(null)"
|
*ngIf="fileEditId === element.ID"
|
||||||
*ngIf="fileEditId === element.ID"
|
[fileId]="element.ID"
|
||||||
></app-song-file-edit>
|
></app-song-file-edit>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="action">
|
<ng-container matColumnDef="action">
|
||||||
<th mat-header-cell *matHeaderCellDef>
|
<th *matHeaderCellDef mat-header-cell>
|
||||||
<input
|
<input
|
||||||
type="file"
|
#newFileUploaderRef
|
||||||
ng2FileSelect
|
[uploader]="newFileUploader"
|
||||||
[uploader]="newFileUploader"
|
multiple
|
||||||
multiple
|
ng2FileSelect
|
||||||
style="display:none"
|
style="display:none"
|
||||||
#newFileUploaderRef
|
type="file"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
(click)="newFileUploaderRef.click()"
|
||||||
(click)="newFileUploaderRef.click()"
|
mat-icon-button
|
||||||
matTooltip="neue Datei hochladen"
|
matTooltip="neue Datei hochladen"
|
||||||
matTooltipPosition="left"
|
matTooltipPosition="left"
|
||||||
>
|
>
|
||||||
<fa-icon [icon]="faFileUpload"></fa-icon>
|
<fa-icon [icon]="faFileUpload"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</th>
|
</th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td *matCellDef="let element" mat-cell>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
(click)="onClickEdit(element.ID)"
|
||||||
(click)="onClickEdit(element.ID)"
|
*ngIf="fileEditId !== element.ID"
|
||||||
matTooltip="Eintrag bearbeiten"
|
mat-icon-button
|
||||||
matTooltipPosition="left"
|
matTooltip="Eintrag bearbeiten"
|
||||||
*ngIf="fileEditId !== element.ID"
|
matTooltipPosition="left"
|
||||||
>
|
>
|
||||||
<fa-icon [icon]="faEdit"></fa-icon>
|
<fa-icon [icon]="faEdit"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
(click)="onClickDownload(element.ID, element.Name)"
|
||||||
(click)="onClickDownload(element.ID, element.Name)"
|
*ngIf="fileEditId !== element.ID"
|
||||||
matTooltip="Datei herunterladen"
|
mat-icon-button
|
||||||
matTooltipPosition="left"
|
matTooltip="Datei herunterladen"
|
||||||
*ngIf="fileEditId !== element.ID"
|
matTooltipPosition="left"
|
||||||
>
|
>
|
||||||
<fa-icon [icon]="faDownload"></fa-icon>
|
<fa-icon [icon]="faDownload"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
(click)="onClickEdit(null)"
|
||||||
matTooltip="Zurück zur Tabelle"
|
*ngIf="fileEditId === element.ID"
|
||||||
matTooltipPosition="left"
|
mat-icon-button
|
||||||
(click)="onClickEdit(null)"
|
matTooltip="Zurück zur Tabelle"
|
||||||
*ngIf="fileEditId === element.ID"
|
matTooltipPosition="left"
|
||||||
>
|
>
|
||||||
<fa-icon [icon]="faArrow"></fa-icon>
|
<fa-icon [icon]="faArrow"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
(click)="onClickDelete(element.ID)"
|
||||||
matTooltip="Anhang löschen"
|
*ngIf="fileEditId === element.ID"
|
||||||
matTooltipPosition="left"
|
mat-icon-button
|
||||||
(click)="onClickDelete(element.ID)"
|
matTooltip="Anhang löschen"
|
||||||
*ngIf="fileEditId === element.ID"
|
matTooltipPosition="left"
|
||||||
>
|
>
|
||||||
<fa-icon [icon]="faTrash"></fa-icon>
|
<fa-icon [icon]="faTrash"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr
|
<tr
|
||||||
mat-header-row
|
(fileOver)="onFileOverNew($event)"
|
||||||
*matHeaderRowDef="columns"
|
*matHeaderRowDef="columns"
|
||||||
ng2FileDrop
|
[class.file-over]="fileOverNew"
|
||||||
[uploader]="newFileUploader"
|
[uploader]="newFileUploader"
|
||||||
(fileOver)="onFileOverNew($event)"
|
mat-header-row
|
||||||
[class.file-over]="fileOverNew"
|
ng2FileDrop
|
||||||
></tr>
|
></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: columns"></tr>
|
<tr *matRowDef="let row; columns: columns" mat-row></tr>
|
||||||
</table>
|
</table>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,11 +5,12 @@
|
|||||||
button {
|
button {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.file-over {
|
tr.file-over {
|
||||||
background: #f908;
|
background: #f908;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +1,71 @@
|
|||||||
import { switchMap } from 'rxjs/operators';
|
import {switchMap} from 'rxjs/operators';
|
||||||
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
|
import {ChangeDetectorRef, Component} from '@angular/core';
|
||||||
import { Song } from 'src/app/models/song.model';
|
import {Song} from 'src/app/models/song.model';
|
||||||
import { SongsService } from 'src/app/data/songs.service';
|
import {SongsService} from 'src/app/data/songs.service';
|
||||||
import { DownloadService } from 'src/app/data/download.service';
|
import {DownloadService} from 'src/app/data/download.service';
|
||||||
import {
|
import {faDownload, faEdit, faFileUpload, faLongArrowAltLeft, faTrash} from '@fortawesome/free-solid-svg-icons';
|
||||||
faFileUpload,
|
import {FileuploadFactory} from 'src/app/services/fileupload.factory';
|
||||||
faDownload,
|
import {FileUploader} from 'ng2-file-upload';
|
||||||
faEdit,
|
|
||||||
faLongArrowAltLeft,
|
|
||||||
faTrash
|
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import { FileuploadFactory } from 'src/app/services/fileupload.factory';
|
|
||||||
import { FileUploader } from 'ng2-file-upload';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-song-files',
|
selector: 'app-song-files',
|
||||||
templateUrl: './song-files.component.html',
|
templateUrl: './song-files.component.html',
|
||||||
styleUrls: ['./song-files.component.less']
|
styleUrls: ['./song-files.component.less']
|
||||||
})
|
})
|
||||||
export class SongFilesComponent {
|
export class SongFilesComponent {
|
||||||
public song: Song;
|
public song: Song;
|
||||||
public selectedSongId = 0;
|
public selectedSongId = 0;
|
||||||
public faFileUpload = faFileUpload;
|
public faFileUpload = faFileUpload;
|
||||||
public faTrash = faTrash;
|
public faTrash = faTrash;
|
||||||
public faArrow = faLongArrowAltLeft;
|
public faArrow = faLongArrowAltLeft;
|
||||||
public faDownload = faDownload;
|
public faDownload = faDownload;
|
||||||
public faEdit = faEdit;
|
public faEdit = faEdit;
|
||||||
public columns = ['name', 'action'];
|
public columns = ['name', 'action'];
|
||||||
public newFileUploader: FileUploader;
|
public newFileUploader: FileUploader;
|
||||||
public fileEditId: number;
|
public fileEditId: number;
|
||||||
|
|
||||||
public fileOverNew = false;
|
public fileOverNew = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private downloadService: DownloadService,
|
private downloadService: DownloadService,
|
||||||
private fileuploadFactory: FileuploadFactory,
|
private fileuploadFactory: FileuploadFactory,
|
||||||
private songService: SongsService,
|
private songService: SongsService,
|
||||||
change: ChangeDetectorRef
|
change: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
songService.selectedSong.subscribe(_ => {
|
songService.selectedSong.subscribe(_ => {
|
||||||
if (_) {
|
if (_) {
|
||||||
this.selectedSongId = _.ID;
|
this.selectedSongId = _.ID;
|
||||||
this.song = _;
|
this.song = _;
|
||||||
this.newFileUploader = this.fileuploadFactory.provideForNewFiles(_.ID);
|
this.newFileUploader = FileuploadFactory.provideForNewFiles(_.ID);
|
||||||
this.newFileUploader.onCompleteItem = () =>
|
this.newFileUploader.onCompleteItem = () =>
|
||||||
songService.selectSong(_.ID).subscribe();
|
songService.selectSong(_.ID).subscribe();
|
||||||
this.newFileUploader.onProgressItem = () => change.markForCheck;
|
this.newFileUploader.onProgressItem = () => change.markForCheck;
|
||||||
} else {
|
} else {
|
||||||
this.selectedSongId = 0;
|
this.selectedSongId = 0;
|
||||||
this.song = null;
|
this.song = null;
|
||||||
this.newFileUploader = null;
|
this.newFileUploader = null;
|
||||||
}
|
}
|
||||||
change.markForCheck();
|
change.markForCheck();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onClickDownload(fileId: number, filename): void {
|
public onClickDownload(fileId: number, filename): void {
|
||||||
this.downloadService.get(this.selectedSongId, fileId, filename);
|
this.downloadService.get(this.selectedSongId, fileId, filename);
|
||||||
}
|
}
|
||||||
public onFileOverNew(hover: boolean): void {
|
|
||||||
this.fileOverNew = hover;
|
public onFileOverNew(hover: boolean): void {
|
||||||
}
|
this.fileOverNew = hover;
|
||||||
public onClickEdit(fileId: number): void {
|
}
|
||||||
this.fileEditId = fileId;
|
|
||||||
}
|
public onClickEdit(fileId: number): void {
|
||||||
public onClickDelete(fileId: number): void {
|
this.fileEditId = fileId;
|
||||||
const songId = this.song.ID;
|
}
|
||||||
this.songService
|
|
||||||
.deleteFile$(songId, fileId)
|
public onClickDelete(fileId: number): void {
|
||||||
.pipe(switchMap(() => this.songService.selectSong(songId)))
|
const songId = this.song.ID;
|
||||||
.subscribe();
|
this.songService
|
||||||
}
|
.deleteFile$(songId, fileId)
|
||||||
|
.pipe(switchMap(() => this.songService.selectSong(songId)))
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ export const keys = [
|
|||||||
'A#',
|
'A#',
|
||||||
'b',
|
'b',
|
||||||
'h'
|
'h'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,53 +1,53 @@
|
|||||||
<form>
|
<form>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input
|
<input
|
||||||
matInput
|
[formControl]="form.controls.Name"
|
||||||
placeholder="Titel"
|
matInput
|
||||||
[formControl]="form.controls.Name"
|
placeholder="Titel"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<mat-radio-group [formControl]="form.controls.SongType">
|
<mat-radio-group [formControl]="form.controls.SongType">
|
||||||
<mat-radio-button value="Praise">Lobpreis</mat-radio-button>
|
<mat-radio-button value="Praise">Lobpreis</mat-radio-button>
|
||||||
<mat-radio-button value="Worship">Anbetung</mat-radio-button>
|
<mat-radio-button value="Worship">Anbetung</mat-radio-button>
|
||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input
|
<input
|
||||||
matInput
|
[formControl]="form.controls.Number"
|
||||||
placeholder="Nummer"
|
matInput
|
||||||
[formControl]="form.controls.Number"
|
placeholder="Nummer"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Tonart</mat-label>
|
<mat-label>Tonart</mat-label>
|
||||||
<mat-select [formControl]="form.controls.Key">
|
<mat-select [formControl]="form.controls.Key">
|
||||||
<mat-option *ngFor="let key of keys" [value]="key">
|
<mat-option *ngFor="let key of keys" [value]="key">
|
||||||
{{ key }}
|
{{ key }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input
|
<input
|
||||||
matInput
|
[formControl]="form.controls.Tempo"
|
||||||
placeholder="Tempo"
|
matInput
|
||||||
[formControl]="form.controls.Tempo"
|
placeholder="Tempo"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<textarea
|
<textarea
|
||||||
matInput
|
[formControl]="form.controls.Text"
|
||||||
placeholder="Liedtext"
|
[matTextareaAutosize]="true"
|
||||||
[formControl]="form.controls.Text"
|
matInput
|
||||||
[matTextareaAutosize]="true"
|
placeholder="Liedtext"
|
||||||
></textarea>
|
></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<textarea
|
<textarea
|
||||||
matInput
|
[formControl]="form.controls.Comments"
|
||||||
placeholder="Kommentare"
|
[matTextareaAutosize]="true"
|
||||||
[formControl]="form.controls.Comments"
|
matInput
|
||||||
[matTextareaAutosize]="true"
|
placeholder="Kommentare"
|
||||||
></textarea>
|
></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
form {
|
form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
.row {
|
|
||||||
display: grid;
|
.row {
|
||||||
grid-template-columns: 3fr 1fr 1fr 1fr;
|
display: grid;
|
||||||
grid-column-gap: 20px;
|
grid-template-columns: 3fr 1fr 1fr 1fr;
|
||||||
}
|
grid-column-gap: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { FormGroup } from '@angular/forms';
|
import {FormGroup} from '@angular/forms';
|
||||||
import { Component, Input } from '@angular/core';
|
import {Component, Input} from '@angular/core';
|
||||||
import { keys } from './keys';
|
import {keys} from './keys';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-song-form',
|
selector: 'app-song-form',
|
||||||
templateUrl: './song-form.component.html',
|
templateUrl: './song-form.component.html',
|
||||||
styleUrls: ['./song-form.component.less']
|
styleUrls: ['./song-form.component.less']
|
||||||
})
|
})
|
||||||
export class SongFormComponent {
|
export class SongFormComponent {
|
||||||
@Input() public form: FormGroup;
|
@Input() public form: FormGroup;
|
||||||
public keys = keys;
|
public keys = keys;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
<div class="song-detail-container">
|
<div class="song-detail-container">
|
||||||
<mat-card class="mat-elevation-z8" *ngIf="form">
|
<mat-card *ngIf="form" class="mat-elevation-z8">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<div mat-card-avatar>
|
<div mat-card-avatar>
|
||||||
<button mat-icon-button (click)="onBack()" color="warn">
|
<button (click)="onBack()" color="warn" mat-icon-button>
|
||||||
<fa-icon [icon]="faArrow"></fa-icon>
|
<fa-icon [icon]="faArrow"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<mat-card-title>Neuen Titel anlegen</mat-card-title>
|
<mat-card-title>Neuen Titel anlegen</mat-card-title>
|
||||||
<mat-card-subtitle>
|
<mat-card-subtitle>
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<app-song-form [form]="form"></app-song-form>
|
<app-song-form [form]="form"></app-song-form>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions>
|
<mat-card-actions>
|
||||||
<button mat-button (click)="onClickAdd()">
|
<button (click)="onClickAdd()" mat-button>
|
||||||
<fa-icon [icon]="faSave"></fa-icon> neu anlegen
|
<fa-icon [icon]="faSave"></fa-icon>
|
||||||
</button>
|
neu anlegen
|
||||||
</mat-card-actions>
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,39 +1,40 @@
|
|||||||
import { EditSongService } from './../../../data/edit-song.service';
|
import {EditSongService} from '../../../data/edit-song.service';
|
||||||
import { FormGroup } from '@angular/forms';
|
import {FormGroup} from '@angular/forms';
|
||||||
import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core';
|
||||||
import { faLongArrowAltLeft, faSave } from '@fortawesome/free-solid-svg-icons';
|
import {faLongArrowAltLeft, faSave} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { State } from 'src/app/data/state';
|
import {State} from 'src/app/data/state';
|
||||||
import { SongsService } from 'src/app/data/songs.service';
|
import {SongsService} from 'src/app/data/songs.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-song-new',
|
selector: 'app-song-new',
|
||||||
templateUrl: './song-new.component.html',
|
templateUrl: './song-new.component.html',
|
||||||
styleUrls: ['./song-new.component.less'],
|
styleUrls: ['./song-new.component.less'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SongNewComponent implements OnInit {
|
export class SongNewComponent implements OnInit {
|
||||||
public faArrow = faLongArrowAltLeft;
|
public faArrow = faLongArrowAltLeft;
|
||||||
public faSave = faSave;
|
public faSave = faSave;
|
||||||
public form: FormGroup;
|
public form: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private editSongService: EditSongService,
|
private editSongService: EditSongService,
|
||||||
private songsService: SongsService,
|
private songsService: SongsService,
|
||||||
private change: ChangeDetectorRef
|
private change: ChangeDetectorRef
|
||||||
) { }
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.form = this.editSongService.initSongEditForm(false);
|
this.form = this.editSongService.initSongEditForm(false);
|
||||||
this.change.markForCheck();
|
this.change.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onBack(): void {
|
public onBack(): void {
|
||||||
this.songsService.state = State.list;
|
this.songsService.state = State.list;
|
||||||
this.songsService.resetSelectedSong();
|
this.songsService.resetSelectedSong();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onClickAdd(): void {
|
public onClickAdd(): void {
|
||||||
this.songsService.saveNewSong$(this.form.value).subscribe();
|
this.songsService.saveNewSong$(this.form.value).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,32 @@
|
|||||||
<div class="song-detail-container" *ngIf="song">
|
<div *ngIf="song" class="song-detail-container">
|
||||||
<mat-card class="mat-elevation-z8">
|
<mat-card class="mat-elevation-z8">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<div mat-card-avatar>
|
<div mat-card-avatar>
|
||||||
<button mat-icon-button (click)="onBack()" color="warn">
|
<button (click)="onBack()" color="warn" mat-icon-button>
|
||||||
<fa-icon [icon]="faArrow"></fa-icon>
|
<fa-icon [icon]="faArrow"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<mat-card-title>{{ song.Name }}</mat-card-title>
|
<mat-card-title>{{ song.Name }}</mat-card-title>
|
||||||
<mat-card-subtitle>
|
<mat-card-subtitle>
|
||||||
<mat-chip-list>
|
<mat-chip-list>
|
||||||
<mat-chip *ngIf="renderSongType(song.SongType)" [style.background]="renderSongType(song.SongType).color">{{ renderSongType(song.SongType).name }}</mat-chip>
|
<mat-chip *ngIf="renderSongType(song.SongType)"
|
||||||
<mat-chip *ngIf="song.Key">Tonart: {{ song.Key }}</mat-chip>
|
[style.background]="renderSongType(song.SongType).color">{{ renderSongType(song.SongType).name }}</mat-chip>
|
||||||
<mat-chip *ngIf="song.Tempo">Tempo: {{ song.Tempo }}</mat-chip>
|
<mat-chip *ngIf="song.Key">Tonart: {{ song.Key }}</mat-chip>
|
||||||
</mat-chip-list></mat-card-subtitle
|
<mat-chip *ngIf="song.Tempo">Tempo: {{ song.Tempo }}</mat-chip>
|
||||||
>
|
</mat-chip-list>
|
||||||
</mat-card-header>
|
</mat-card-subtitle
|
||||||
<mat-card-content>
|
>
|
||||||
<p *ngFor="let line of text">{{ line }}</p>
|
</mat-card-header>
|
||||||
<br />
|
<mat-card-content>
|
||||||
<p *ngFor="let line of comments">{{ line }}</p>
|
<p *ngFor="let line of text">{{ line }}</p>
|
||||||
</mat-card-content>
|
<br/>
|
||||||
<mat-card-actions>
|
<p *ngFor="let line of comments">{{ line }}</p>
|
||||||
<button mat-button (click)="onClickEdit()">
|
</mat-card-content>
|
||||||
<fa-icon [icon]="faEdit"></fa-icon> bearbeiten
|
<mat-card-actions>
|
||||||
</button>
|
<button (click)="onClickEdit()" mat-button>
|
||||||
</mat-card-actions>
|
<fa-icon [icon]="faEdit"></fa-icon>
|
||||||
</mat-card>
|
bearbeiten
|
||||||
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,62 +1,61 @@
|
|||||||
import { SongsService } from 'src/app/data/songs.service';
|
import {SongsService} from 'src/app/data/songs.service';
|
||||||
import {
|
import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from '@angular/core';
|
||||||
Component,
|
import {faEdit, faLongArrowAltLeft} from '@fortawesome/free-solid-svg-icons';
|
||||||
ChangeDetectionStrategy,
|
import {Song} from 'src/app/models/song.model';
|
||||||
ChangeDetectorRef
|
import {State} from 'src/app/data/state';
|
||||||
} from '@angular/core';
|
|
||||||
import { faLongArrowAltLeft, faEdit } from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import { Song } from 'src/app/models/song.model';
|
|
||||||
import { DownloadService } from 'src/app/data/download.service';
|
|
||||||
import { State } from 'src/app/data/state';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-song',
|
selector: 'app-song',
|
||||||
templateUrl: './song.component.html',
|
templateUrl: './song.component.html',
|
||||||
styleUrls: ['./song.component.less'],
|
styleUrls: ['./song.component.less'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SongComponent {
|
export class SongComponent {
|
||||||
public song: Song;
|
public song: Song;
|
||||||
public faArrow = faLongArrowAltLeft;
|
public faArrow = faLongArrowAltLeft;
|
||||||
public faEdit = faEdit;
|
public faEdit = faEdit;
|
||||||
public selectedSongId = 0;
|
public selectedSongId = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private songService: SongsService,
|
private songService: SongsService,
|
||||||
change: ChangeDetectorRef
|
change: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
songService.selectedSong.subscribe(_ => {
|
songService.selectedSong.subscribe(_ => {
|
||||||
if (_) {
|
if (_) {
|
||||||
this.selectedSongId = _.ID;
|
this.selectedSongId = _.ID;
|
||||||
this.song = _;
|
this.song = _;
|
||||||
} else {
|
} else {
|
||||||
this.selectedSongId = 0;
|
this.selectedSongId = 0;
|
||||||
this.song = null;
|
this.song = null;
|
||||||
}
|
}
|
||||||
change.markForCheck();
|
change.markForCheck();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public onBack(): void {
|
|
||||||
this.songService.resetSelectedSong();
|
public get text(): string[] {
|
||||||
}
|
return this.song && this.song.Text ? this.song.Text.split(/\r?\n/) : [];
|
||||||
|
}
|
||||||
public onClickEdit(): void {
|
|
||||||
this.songService.state = State.edit;
|
public get comments(): string[] {
|
||||||
}
|
return this.song && this.song.Comments ? this.song.Comments.split(/\r?\n/) : [];
|
||||||
|
}
|
||||||
public get text(): string[] {
|
|
||||||
return this.song && this.song.Text ? this.song.Text.split(/\r?\n/) : [];
|
public onBack(): void {
|
||||||
}
|
this.songService.resetSelectedSong();
|
||||||
|
}
|
||||||
public get comments(): string[] {
|
|
||||||
return this.song && this.song.Comments ? this.song.Comments.split(/\r?\n/) : [];
|
public onClickEdit(): void {
|
||||||
}
|
this.songService.state = State.edit;
|
||||||
|
}
|
||||||
public renderSongType(songType: string) {
|
|
||||||
switch (songType) {
|
public renderSongType(songType: string) {
|
||||||
case 'Praise': return {name: 'Lobpreis', color: '#99FFB8'};
|
switch (songType) {
|
||||||
case 'Worship': return {name: 'Anbetung', color: '#C999FF'};
|
case 'Praise':
|
||||||
default: return null;
|
return {name: 'Lobpreis', color: '#99FFB8'};
|
||||||
|
case 'Worship':
|
||||||
|
return {name: 'Anbetung', color: '#C999FF'};
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<app-table></app-table>
|
<app-table></app-table>
|
||||||
<app-song-edit [@blend] *ngIf="songsService.state === State.edit"></app-song-edit>
|
<app-song-edit *ngIf="songsService.state === State.edit" [@blend]></app-song-edit>
|
||||||
<app-song-new [@blend] *ngIf="songsService.state === State.new"></app-song-new>
|
<app-song-new *ngIf="songsService.state === State.new" [@blend]></app-song-new>
|
||||||
<app-song [@blend] *ngIf="songsService.state === State.read"></app-song>
|
<app-song *ngIf="songsService.state === State.read" [@blend]></app-song>
|
||||||
<app-song-files [@blend] *ngIf="songsService.state === State.read"></app-song-files>
|
<app-song-files *ngIf="songsService.state === State.read" [@blend]></app-song-files>
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { blend } from 'src/app/services/animation';
|
import {blend} from 'src/app/services/animation';
|
||||||
import { Component } from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import { SongsService } from 'src/app/data/songs.service';
|
import {SongsService} from 'src/app/data/songs.service';
|
||||||
import { State } from 'src/app/data/state';
|
import {State} from 'src/app/data/state';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-songs',
|
selector: 'app-songs',
|
||||||
templateUrl: './songs.component.html',
|
templateUrl: './songs.component.html',
|
||||||
styleUrls: ['./songs.component.less'],
|
styleUrls: ['./songs.component.less'],
|
||||||
animations: [blend]
|
animations: [blend]
|
||||||
})
|
})
|
||||||
export class SongsComponent {
|
export class SongsComponent {
|
||||||
public State = State;
|
public State = State;
|
||||||
constructor(public songsService: SongsService) {
|
|
||||||
songsService.loadSongList$().subscribe();
|
constructor(public songsService: SongsService) {
|
||||||
}
|
songsService.loadSongList$().subscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,75 +1,75 @@
|
|||||||
<div
|
<div
|
||||||
class="page-container mat-elevation-z8"
|
[class.pinned]="songsService.state !== State.list"
|
||||||
[class.pinned]="songsService.state !== State.list"
|
class="page-container mat-elevation-z8"
|
||||||
>
|
>
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
(click)="onClickNew()"
|
||||||
(click)="onClickNew()"
|
class="button-new"
|
||||||
class="button-new"
|
mat-icon-button
|
||||||
matTooltip="neuen Titel anlegen"
|
matTooltip="neuen Titel anlegen"
|
||||||
matTooltipPosition="left"
|
matTooltipPosition="left"
|
||||||
>
|
>
|
||||||
<fa-icon [icon]="faNew"></fa-icon>
|
<fa-icon [icon]="faNew"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
<table
|
<table
|
||||||
mat-table
|
[dataSource]="songsService.songs | async"
|
||||||
[dataSource]="songsService.songs | async"
|
class="mat-elevation-z8"
|
||||||
class="mat-elevation-z8"
|
mat-table
|
||||||
>
|
>
|
||||||
<ng-container matColumnDef="Number">
|
<ng-container matColumnDef="Number">
|
||||||
<th mat-header-cell *matHeaderCellDef>#</th>
|
<th *matHeaderCellDef mat-header-cell>#</th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td *matCellDef="let element" mat-cell>
|
||||||
<mat-chip-list>
|
<mat-chip-list>
|
||||||
<mat-chip>{{ element.Number }}</mat-chip>
|
<mat-chip>{{ element.Number }}</mat-chip>
|
||||||
</mat-chip-list>
|
</mat-chip-list>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="Name">
|
<ng-container matColumnDef="Name">
|
||||||
<th mat-header-cell *matHeaderCellDef>Titel</th>
|
<th *matHeaderCellDef mat-header-cell>Titel</th>
|
||||||
<td mat-cell *matCellDef="let element">{{ element.Name }}</td>
|
<td *matCellDef="let element" mat-cell>{{ element.Name }}</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="Key">
|
<ng-container matColumnDef="Key">
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th *matHeaderCellDef mat-header-cell></th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td *matCellDef="let element" mat-cell>
|
||||||
<mat-chip-list *ngIf="element.Key">
|
<mat-chip-list *ngIf="element.Key">
|
||||||
<mat-chip>{{ element.Key }}</mat-chip>
|
<mat-chip>{{ element.Key }}</mat-chip>
|
||||||
</mat-chip-list>
|
</mat-chip-list>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="SongType">
|
<ng-container matColumnDef="SongType">
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th *matHeaderCellDef mat-header-cell></th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td *matCellDef="let element" mat-cell>
|
||||||
<mat-chip-list
|
<mat-chip-list
|
||||||
*ngIf="element.SongType && element.SongType !== 'None'"
|
*ngIf="element.SongType && element.SongType !== 'None'"
|
||||||
>
|
>
|
||||||
<mat-chip
|
<mat-chip
|
||||||
[style.background-color]="renderSongType(element.SongType).color"
|
[style.background-color]="renderSongType(element.SongType).color"
|
||||||
>{{ renderSongType(element.SongType).name }}</mat-chip
|
>{{ renderSongType(element.SongType).name }}</mat-chip
|
||||||
>
|
>
|
||||||
</mat-chip-list>
|
</mat-chip-list>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="Tempo">
|
<ng-container matColumnDef="Tempo">
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th *matHeaderCellDef mat-header-cell></th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td *matCellDef="let element" mat-cell>
|
||||||
<mat-chip-list *ngIf="element.Tempo">
|
<mat-chip-list *ngIf="element.Tempo">
|
||||||
<mat-chip>{{ element.Tempo }}</mat-chip>
|
<mat-chip>{{ element.Tempo }}</mat-chip>
|
||||||
</mat-chip-list>
|
</mat-chip-list>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="columns; sticky: true"></tr>
|
<tr *matHeaderRowDef="columns; sticky: true" mat-header-row></tr>
|
||||||
<tr
|
<tr
|
||||||
[class.selected]="selectedSongId === row.ID"
|
(click)="onClick(row.ID)"
|
||||||
mat-row
|
*matRowDef="let row; columns: columns"
|
||||||
*matRowDef="let row; columns: columns"
|
[class.selected]="selectedSongId === row.ID"
|
||||||
(click)="onClick(row.ID)"
|
mat-row
|
||||||
></tr>
|
></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ table {
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,56 @@
|
|||||||
import { SongsService } from './../../../data/songs.service';
|
import {SongsService} from '../../../data/songs.service';
|
||||||
import {
|
import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from '@angular/core';
|
||||||
Component,
|
import {State} from 'src/app/data/state';
|
||||||
ChangeDetectionStrategy,
|
import {faFileMedical} from '@fortawesome/free-solid-svg-icons';
|
||||||
ChangeDetectorRef
|
|
||||||
} from '@angular/core';
|
|
||||||
import { State } from 'src/app/data/state';
|
|
||||||
import { faFileMedical } from '@fortawesome/free-solid-svg-icons';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-table',
|
selector: 'app-table',
|
||||||
templateUrl: './table.component.html',
|
templateUrl: './table.component.html',
|
||||||
styleUrls: ['./table.component.less'],
|
styleUrls: ['./table.component.less'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class TableComponent {
|
export class TableComponent {
|
||||||
public selectedSongId = 0;
|
public selectedSongId = 0;
|
||||||
public State = State;
|
public State = State;
|
||||||
public faNew = faFileMedical;
|
public faNew = faFileMedical;
|
||||||
public columnsFull = ['Number', 'Name', 'Key', 'SongType', 'Tempo'];
|
public columnsFull = ['Number', 'Name', 'Key', 'SongType', 'Tempo'];
|
||||||
public columnsPinned = ['Number', 'Name'];
|
public columnsPinned = ['Number', 'Name'];
|
||||||
public get columns(): string[] {
|
|
||||||
return this.songsService.state === State.list ? this.columnsFull : this.columnsPinned;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public songsService: SongsService,
|
public songsService: SongsService,
|
||||||
private change: ChangeDetectorRef
|
private change: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
songsService.selectedSong.subscribe(_ => {
|
songsService.selectedSong.subscribe(_ => {
|
||||||
this.selectedSongId = _ ? _.ID : 0;
|
this.selectedSongId = _ ? _.ID : 0;
|
||||||
this.change.markForCheck();
|
this.change.markForCheck();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
public renderSongType(songType: string) {
|
|
||||||
switch (songType) {
|
|
||||||
case 'Praise': return {name: 'Lobpreis', color: '#99FFB8'};
|
|
||||||
case 'Worship': return {name: 'Anbetung', color: '#C999FF'};
|
|
||||||
default: return null;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public onClick(id: number): void {
|
public get columns(): string[] {
|
||||||
this.songsService.selectSong(id).subscribe();
|
return this.songsService.state === State.list ? this.columnsFull : this.columnsPinned;
|
||||||
this.change.detectChanges();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public onClickNew(): void {
|
public renderSongType(songType: string) {
|
||||||
this.songsService.selectSong(null).subscribe();
|
switch (songType) {
|
||||||
this.songsService.state = State.new;
|
case 'Praise':
|
||||||
this.change.detectChanges();
|
return {name: 'Lobpreis', color: '#99FFB8'};
|
||||||
}
|
case 'Worship':
|
||||||
|
return {name: 'Anbetung', color: '#C999FF'};
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onClick(id: number): void {
|
||||||
|
this.songsService.selectSong(id).subscribe();
|
||||||
|
this.change.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onClickNew(): void {
|
||||||
|
this.songsService.selectSong(null).subscribe();
|
||||||
|
this.songsService.state = State.new;
|
||||||
|
this.change.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
import { base } from './urls';
|
import {base} from './urls';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DownloadService {
|
export class DownloadService {
|
||||||
constructor(private httpClient: HttpClient) {}
|
constructor(private httpClient: HttpClient) {
|
||||||
|
}
|
||||||
|
|
||||||
public get(songId: number, fileId: number, filename: string) {
|
public get(songId: number, fileId: number, filename: string) {
|
||||||
return this.httpClient
|
return this.httpClient
|
||||||
.get(base + '/api/songs/' + songId + '/files/' + fileId, {
|
.get(base + '/api/songs/' + songId + '/files/' + fileId, {
|
||||||
responseType: 'blob' as 'json',
|
responseType: 'blob' as 'json',
|
||||||
observe: 'response'
|
observe: 'response'
|
||||||
})
|
})
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(response: any) => {
|
(response: any) => {
|
||||||
const contentType = response.headers.get('Content-Type');
|
const contentType = response.headers.get('Content-Type');
|
||||||
const downloadLink = document.createElement('a');
|
const downloadLink = document.createElement('a');
|
||||||
const blob = new Blob([response.body], { type: contentType });
|
const blob = new Blob([response.body], {type: contentType});
|
||||||
downloadLink.href = window.URL.createObjectURL(blob);
|
downloadLink.href = window.URL.createObjectURL(blob);
|
||||||
downloadLink.setAttribute('download', filename);
|
downloadLink.setAttribute('download', filename);
|
||||||
document.body.appendChild(downloadLink);
|
document.body.appendChild(downloadLink);
|
||||||
downloadLink.click();
|
downloadLink.click();
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log('download error:', JSON.stringify(error));
|
console.log('download error:', JSON.stringify(error));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,105 +1,106 @@
|
|||||||
import { FileType } from './../models/files-types.model.ts';
|
import {SongsService} from 'src/app/data/songs.service';
|
||||||
import { SongsService } from 'src/app/data/songs.service';
|
import {Injectable} from '@angular/core';
|
||||||
import { Injectable } from '@angular/core';
|
import {FormControl, FormGroup, Validators} from '@angular/forms';
|
||||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
import {switchMap} from 'rxjs/operators';
|
||||||
import { switchMap } from 'rxjs/operators';
|
import {Song} from '../models/song.model';
|
||||||
import { Song } from '../models/song.model';
|
import {Subscription} from 'rxjs';
|
||||||
import { Subscription } from 'rxjs';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class EditSongService {
|
export class EditSongService {
|
||||||
constructor(private songsService: SongsService) {}
|
constructor(private songsService: SongsService) {
|
||||||
|
|
||||||
public initSongEditForm(attachSync: boolean): FormGroup {
|
|
||||||
const song = attachSync
|
|
||||||
? this.songsService.selectedSong.value
|
|
||||||
: this.defaultValues();
|
|
||||||
const form = new FormGroup({
|
|
||||||
Number: new FormControl(song.Number, {
|
|
||||||
updateOn: 'blur',
|
|
||||||
validators: [Validators.required, Validators.min(1)]
|
|
||||||
}),
|
|
||||||
Name: new FormControl(song.Name, {
|
|
||||||
updateOn: 'blur',
|
|
||||||
validators: Validators.required
|
|
||||||
}),
|
|
||||||
Text: new FormControl(song.Text, { updateOn: 'blur' }),
|
|
||||||
SongType: new FormControl(song.SongType, {
|
|
||||||
updateOn: 'blur',
|
|
||||||
validators: Validators.required
|
|
||||||
}),
|
|
||||||
Key: new FormControl(song.Key, {
|
|
||||||
updateOn: 'blur',
|
|
||||||
validators: Validators.required
|
|
||||||
}),
|
|
||||||
Tempo: new FormControl(song.Tempo, { updateOn: 'blur' }),
|
|
||||||
Comments: new FormControl(song.Comments, { updateOn: 'blur' })
|
|
||||||
});
|
|
||||||
|
|
||||||
if (attachSync) {
|
|
||||||
this.attachSync(form, song);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return form;
|
public initSongEditForm(attachSync: boolean): FormGroup {
|
||||||
}
|
const song = attachSync
|
||||||
|
? this.songsService.selectedSong.value
|
||||||
|
: this.defaultValues();
|
||||||
|
const form = new FormGroup({
|
||||||
|
Number: new FormControl(song.Number, {
|
||||||
|
updateOn: 'blur',
|
||||||
|
validators: [Validators.required, Validators.min(1)]
|
||||||
|
}),
|
||||||
|
Name: new FormControl(song.Name, {
|
||||||
|
updateOn: 'blur',
|
||||||
|
validators: Validators.required
|
||||||
|
}),
|
||||||
|
Text: new FormControl(song.Text, {updateOn: 'blur'}),
|
||||||
|
SongType: new FormControl(song.SongType, {
|
||||||
|
updateOn: 'blur',
|
||||||
|
validators: Validators.required
|
||||||
|
}),
|
||||||
|
Key: new FormControl(song.Key, {
|
||||||
|
updateOn: 'blur',
|
||||||
|
validators: Validators.required
|
||||||
|
}),
|
||||||
|
Tempo: new FormControl(song.Tempo, {updateOn: 'blur'}),
|
||||||
|
Comments: new FormControl(song.Comments, {updateOn: 'blur'})
|
||||||
|
});
|
||||||
|
|
||||||
public initFileEditForm(songId: number, fileId: number): {form: FormGroup, changeSubscription: Subscription } {
|
if (attachSync) {
|
||||||
const file = this.songsService.selectedSong.value.Files.filter(
|
this.attachSync(form, song);
|
||||||
_ => _.ID === fileId
|
}
|
||||||
)[0];
|
|
||||||
const form = new FormGroup({
|
|
||||||
Name: new FormControl(file.Name, {
|
|
||||||
updateOn: 'blur',
|
|
||||||
validators: Validators.required
|
|
||||||
}),
|
|
||||||
FileType: new FormControl(file.FileType, {
|
|
||||||
updateOn: 'blur'
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const changeSubscription = form.valueChanges.pipe(
|
return form;
|
||||||
switchMap(_ => this.songsService.updateFile$(songId, fileId, _.Name, _.FileType)),
|
}
|
||||||
switchMap(() => this.songsService.selectSong(songId))
|
|
||||||
).subscribe();
|
|
||||||
|
|
||||||
return {form : form, changeSubscription: changeSubscription};
|
public initFileEditForm(songId: number, fileId: number): { form: FormGroup, changeSubscription: Subscription } {
|
||||||
}
|
const file = this.songsService.selectedSong.value.Files.filter(
|
||||||
|
_ => _.ID === fileId
|
||||||
|
)[0];
|
||||||
|
const form = new FormGroup({
|
||||||
|
Name: new FormControl(file.Name, {
|
||||||
|
updateOn: 'blur',
|
||||||
|
validators: Validators.required
|
||||||
|
}),
|
||||||
|
FileType: new FormControl(file.FileType, {
|
||||||
|
updateOn: 'blur'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
private attachSync(form: FormGroup, song: Song) {
|
const changeSubscription = form.valueChanges.pipe(
|
||||||
const controls = Object.keys(form.controls);
|
switchMap(_ => this.songsService.updateFile$(songId, fileId, _.Name, _.FileType)),
|
||||||
controls.forEach(control => {
|
switchMap(() => this.songsService.selectSong(songId))
|
||||||
form.controls[control].valueChanges
|
).subscribe();
|
||||||
.pipe(
|
|
||||||
switchMap(value => this.songsService.patch$(song.ID, control, value)),
|
|
||||||
switchMap(() => this.songsService.selectSong(song.ID))
|
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private defaultValues(): Song {
|
return {form: form, changeSubscription: changeSubscription};
|
||||||
const song: Song = {
|
}
|
||||||
ID: null,
|
|
||||||
Number: this.firstFreeNumber(),
|
|
||||||
Name: null,
|
|
||||||
Tempo: null,
|
|
||||||
Text: null,
|
|
||||||
SongType: null,
|
|
||||||
Key: null,
|
|
||||||
Comments: null,
|
|
||||||
Final: false,
|
|
||||||
Files: []
|
|
||||||
};
|
|
||||||
|
|
||||||
return song;
|
private attachSync(form: FormGroup, song: Song) {
|
||||||
}
|
const controls = Object.keys(form.controls);
|
||||||
|
controls.forEach(control => {
|
||||||
|
form.controls[control].valueChanges
|
||||||
|
.pipe(
|
||||||
|
switchMap(value => this.songsService.patch$(song.ID, control, value)),
|
||||||
|
switchMap(() => this.songsService.selectSong(song.ID))
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private firstFreeNumber(): number {
|
private defaultValues(): Song {
|
||||||
let number = 0;
|
const song: Song = {
|
||||||
const numbers = this.songsService.songs.value.map(_ => _.Number);
|
ID: null,
|
||||||
while (numbers.indexOf(++number) !== -1) {}
|
Number: this.firstFreeNumber(),
|
||||||
return number;
|
Name: null,
|
||||||
}
|
Tempo: null,
|
||||||
|
Text: null,
|
||||||
|
SongType: null,
|
||||||
|
Key: null,
|
||||||
|
Comments: null,
|
||||||
|
Final: false,
|
||||||
|
Files: []
|
||||||
|
};
|
||||||
|
|
||||||
|
return song;
|
||||||
|
}
|
||||||
|
|
||||||
|
private firstFreeNumber(): number {
|
||||||
|
let number = 0;
|
||||||
|
const numbers = this.songsService.songs.value.map(_ => _.Number);
|
||||||
|
while (numbers.indexOf(++number) !== -1) {
|
||||||
|
}
|
||||||
|
return number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,63 @@
|
|||||||
import { Song } from 'src/app/models/song.model';
|
import {Expand, ODataQuery, ODataService} from 'odata-v4-ng';
|
||||||
import { ODataService, ODataQuery, Expand } from 'odata-v4-ng';
|
import {Observable} from 'rxjs';
|
||||||
import { Observable } from 'rxjs';
|
import {map, tap} from 'rxjs/operators';
|
||||||
import { map, tap } from 'rxjs/operators';
|
import {base} from './urls';
|
||||||
import { base } from './urls';
|
|
||||||
|
|
||||||
export class OdataService {
|
export class OdataService {
|
||||||
private url: string;
|
private url: string;
|
||||||
constructor(private odataService: ODataService, private entity: string) {
|
|
||||||
this.url = base + '/odata/';
|
|
||||||
}
|
|
||||||
|
|
||||||
public list$<TResponse>(properties: string[]): Observable<TResponse[]> {
|
constructor(private odataService: ODataService, private entity: string) {
|
||||||
const query = new ODataQuery(this.odataService, this.url)
|
this.url = base + '/odata/';
|
||||||
.entitySet(this.entity)
|
}
|
||||||
.select(properties);
|
|
||||||
const get = query.get().pipe(map(_ => _.toPropertyValue<TResponse[]>()));
|
|
||||||
|
|
||||||
return get;
|
public list$<TResponse>(properties: string[]): Observable<TResponse[]> {
|
||||||
}
|
const query = new ODataQuery(this.odataService, this.url)
|
||||||
|
.entitySet(this.entity)
|
||||||
|
.select(properties);
|
||||||
|
const get = query.get().pipe(map(_ => _.toPropertyValue<TResponse[]>()));
|
||||||
|
|
||||||
public get$<TResponse>(
|
return get;
|
||||||
id: number,
|
}
|
||||||
properties: string[],
|
|
||||||
expands: string[]
|
|
||||||
): Observable<TResponse> {
|
|
||||||
const query = new ODataQuery(this.odataService, this.url)
|
|
||||||
.entitySet(this.entity)
|
|
||||||
.entityKey(id)
|
|
||||||
.expand(expands.map(_ => new Expand(_)))
|
|
||||||
.select(properties);
|
|
||||||
const get = query.get().pipe(map(_ => _.toEntity<TResponse>()));
|
|
||||||
|
|
||||||
return get;
|
public get$<TResponse>(
|
||||||
}
|
id: number,
|
||||||
|
properties: string[],
|
||||||
|
expands: string[]
|
||||||
|
): Observable<TResponse> {
|
||||||
|
const query = new ODataQuery(this.odataService, this.url)
|
||||||
|
.entitySet(this.entity)
|
||||||
|
.entityKey(id)
|
||||||
|
.expand(expands.map(_ => new Expand(_)))
|
||||||
|
.select(properties);
|
||||||
|
const get = query.get().pipe(map(_ => _.toEntity<TResponse>()));
|
||||||
|
|
||||||
public patch$(id: number, control: string, value: any): Observable<boolean> {
|
return get;
|
||||||
const valueSet = { [control]: value };
|
}
|
||||||
const query = new ODataQuery(this.odataService, this.url)
|
|
||||||
.entitySet(this.entity)
|
|
||||||
.entityKey(id);
|
|
||||||
const get = query.patch(valueSet).pipe(map(() => true));
|
|
||||||
|
|
||||||
return get;
|
public patch$(id: number, control: string, value: any): Observable<boolean> {
|
||||||
}
|
const valueSet = {[control]: value};
|
||||||
|
const query = new ODataQuery(this.odataService, this.url)
|
||||||
|
.entitySet(this.entity)
|
||||||
|
.entityKey(id);
|
||||||
|
const get = query.patch(valueSet).pipe(map(() => true));
|
||||||
|
|
||||||
public post$<TResponse>(values: any): Observable<TResponse> {
|
return get;
|
||||||
const querry = new ODataQuery(this.odataService, this.url);
|
}
|
||||||
const post = querry
|
|
||||||
.entitySet(this.entity)
|
|
||||||
.post(values)
|
|
||||||
.pipe(
|
|
||||||
tap(_ => console.log(_)),
|
|
||||||
map(_ => {
|
|
||||||
const mapped = _.toEntity<TResponse>();
|
|
||||||
return mapped;
|
|
||||||
}),
|
|
||||||
tap(_ => console.log(_))
|
|
||||||
);
|
|
||||||
|
|
||||||
return post;
|
public post$<TResponse>(values: any): Observable<TResponse> {
|
||||||
}
|
const querry = new ODataQuery(this.odataService, this.url);
|
||||||
|
const post = querry
|
||||||
|
.entitySet(this.entity)
|
||||||
|
.post(values)
|
||||||
|
.pipe(
|
||||||
|
tap(_ => console.log(_)),
|
||||||
|
map(_ => {
|
||||||
|
const mapped = _.toEntity<TResponse>();
|
||||||
|
return mapped;
|
||||||
|
}),
|
||||||
|
tap(_ => console.log(_))
|
||||||
|
);
|
||||||
|
|
||||||
|
return post;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,124 +1,124 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import { FileType } from './../models/files-types.model.ts';
|
import {FileType} from './../models/files-types.model.ts';
|
||||||
import { Injectable } from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import { ODataService } from 'odata-v4-ng';
|
import {ODataService} from 'odata-v4-ng';
|
||||||
import { OdataService } from './odata.service';
|
import {OdataService} from './odata.service';
|
||||||
import { Song } from '../models/song.model';
|
import {Song} from '../models/song.model';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import {BehaviorSubject, Observable} from 'rxjs';
|
||||||
import { tap, switchMap } from 'rxjs/operators';
|
import {switchMap, tap} from 'rxjs/operators';
|
||||||
import { State } from './state';
|
import {State} from './state';
|
||||||
import { base } from './urls';
|
import {base} from './urls';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class SongsService extends OdataService {
|
export class SongsService extends OdataService {
|
||||||
public state = State.list;
|
public state = State.list;
|
||||||
|
|
||||||
public songs: BehaviorSubject<Song[]> = new BehaviorSubject<Song[]>([]);
|
public songs: BehaviorSubject<Song[]> = new BehaviorSubject<Song[]>([]);
|
||||||
public selectedSong: BehaviorSubject<Song> = new BehaviorSubject<Song>(null);
|
public selectedSong: BehaviorSubject<Song> = new BehaviorSubject<Song>(null);
|
||||||
|
|
||||||
constructor(odataService: ODataService, private httpClient: HttpClient) {
|
constructor(odataService: ODataService, private httpClient: HttpClient) {
|
||||||
super(odataService, 'songs');
|
super(odataService, 'songs');
|
||||||
}
|
|
||||||
|
|
||||||
public loadSongList$(): Observable<Song[]> {
|
|
||||||
const properties = ['ID', 'Name', 'Number', 'SongType', 'Key', 'Tempo'];
|
|
||||||
const list = this.list$<Song>(properties).pipe(
|
|
||||||
tap(_ => this.songs.next(_))
|
|
||||||
);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public loadSongListAndGoTo$(id: number): Observable<Song> {
|
|
||||||
const properties = ['ID', 'Name', 'Number', 'SongType', 'Key', 'Tempo'];
|
|
||||||
const list = this.list$<Song>(properties).pipe(
|
|
||||||
tap(_ => {
|
|
||||||
this.songs.next(_);
|
|
||||||
}),
|
|
||||||
switchMap(() => this.selectSong(id))
|
|
||||||
);
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public selectSong(id: number): Observable<Song> {
|
|
||||||
this.state = State.read;
|
|
||||||
const filter = this.songs.value.filter(_ => _.ID === id);
|
|
||||||
const song = filter.length === 1 ? filter[0] : null;
|
|
||||||
if (!song) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const get = this.get$<Song>(id, ['Text', 'Comments'], ['Files']).pipe(tap(_ => {
|
public loadSongList$(): Observable<Song[]> {
|
||||||
song.Text = _.Text;
|
const properties = ['ID', 'Name', 'Number', 'SongType', 'Key', 'Tempo'];
|
||||||
song.Comments = _.Comments;
|
const list = this.list$<Song>(properties).pipe(
|
||||||
song.Files = _.Files;
|
tap(_ => this.songs.next(_))
|
||||||
this.selectedSong.next(song);
|
);
|
||||||
}));
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
return get;
|
public loadSongListAndGoTo$(id: number): Observable<Song> {
|
||||||
}
|
const properties = ['ID', 'Name', 'Number', 'SongType', 'Key', 'Tempo'];
|
||||||
|
const list = this.list$<Song>(properties).pipe(
|
||||||
|
tap(_ => {
|
||||||
|
this.songs.next(_);
|
||||||
|
}),
|
||||||
|
switchMap(() => this.selectSong(id))
|
||||||
|
);
|
||||||
|
|
||||||
public resetSelectedSong() {
|
return list;
|
||||||
this.state = State.list;
|
}
|
||||||
this.selectedSong.next(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public patch$(id: number, control: string, value: any): Observable<boolean> {
|
public selectSong(id: number): Observable<Song> {
|
||||||
const patch = super.patch$(id, control, value).pipe(
|
this.state = State.read;
|
||||||
tap(() => {
|
const filter = this.songs.value.filter(_ => _.ID === id);
|
||||||
const songs = this.songs.value;
|
const song = filter.length === 1 ? filter[0] : null;
|
||||||
const song = songs.filter(_ => _.ID === id)[0];
|
if (!song) {
|
||||||
song[control] = value;
|
return;
|
||||||
this.songs.next(songs);
|
}
|
||||||
this.selectedSong.next(song);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return patch;
|
const get = this.get$<Song>(id, ['Text', 'Comments'], ['Files']).pipe(tap(_ => {
|
||||||
}
|
song.Text = _.Text;
|
||||||
|
song.Comments = _.Comments;
|
||||||
|
song.Files = _.Files;
|
||||||
|
this.selectedSong.next(song);
|
||||||
|
}));
|
||||||
|
|
||||||
public saveNewSong$(values: any): Observable<Song> {
|
return get;
|
||||||
const newSong = super
|
}
|
||||||
.post$<Song>(values)
|
|
||||||
.pipe(switchMap(_ => this.loadSongListAndGoTo$(_.ID)));
|
|
||||||
|
|
||||||
return newSong;
|
public resetSelectedSong() {
|
||||||
}
|
this.state = State.list;
|
||||||
|
this.selectedSong.next(null);
|
||||||
|
}
|
||||||
|
|
||||||
public updateFile$(
|
public patch$(id: number, control: string, value: any): Observable<boolean> {
|
||||||
songId: number,
|
const patch = super.patch$(id, control, value).pipe(
|
||||||
fileId: number,
|
tap(() => {
|
||||||
name: string,
|
const songs = this.songs.value;
|
||||||
fileType: FileType
|
const song = songs.filter(_ => _.ID === id)[0];
|
||||||
): Observable<any> {
|
song[control] = value;
|
||||||
const url =
|
this.songs.next(songs);
|
||||||
base +
|
this.selectedSong.next(song);
|
||||||
'/api/songs/' +
|
})
|
||||||
songId +
|
);
|
||||||
'/files/' +
|
|
||||||
fileId +
|
|
||||||
'/edit?Name=' +
|
|
||||||
name +
|
|
||||||
'&FileType=' +
|
|
||||||
fileType;
|
|
||||||
const get = this.httpClient.get(url);
|
|
||||||
return get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public deleteFile$(
|
return patch;
|
||||||
songId: number,
|
}
|
||||||
fileId: number
|
|
||||||
): Observable<any> {
|
public saveNewSong$(values: any): Observable<Song> {
|
||||||
const url =
|
const newSong = super
|
||||||
base +
|
.post$<Song>(values)
|
||||||
'/api/songs/' +
|
.pipe(switchMap(_ => this.loadSongListAndGoTo$(_.ID)));
|
||||||
songId +
|
|
||||||
'/files/' +
|
return newSong;
|
||||||
fileId +
|
}
|
||||||
'/delete';
|
|
||||||
const get = this.httpClient.get(url);
|
public updateFile$(
|
||||||
return get;
|
songId: number,
|
||||||
}
|
fileId: number,
|
||||||
|
name: string,
|
||||||
|
fileType: FileType
|
||||||
|
): Observable<any> {
|
||||||
|
const url =
|
||||||
|
base +
|
||||||
|
'/api/songs/' +
|
||||||
|
songId +
|
||||||
|
'/files/' +
|
||||||
|
fileId +
|
||||||
|
'/edit?Name=' +
|
||||||
|
name +
|
||||||
|
'&FileType=' +
|
||||||
|
fileType;
|
||||||
|
const get = this.httpClient.get(url);
|
||||||
|
return get;
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteFile$(
|
||||||
|
songId: number,
|
||||||
|
fileId: number
|
||||||
|
): Observable<any> {
|
||||||
|
const url =
|
||||||
|
base +
|
||||||
|
'/api/songs/' +
|
||||||
|
songId +
|
||||||
|
'/files/' +
|
||||||
|
fileId +
|
||||||
|
'/delete';
|
||||||
|
const get = this.httpClient.get(url);
|
||||||
|
return get;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export enum State {
|
export enum State {
|
||||||
read,
|
read,
|
||||||
edit,
|
edit,
|
||||||
new,
|
new,
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { FileType } from './files-types.model.ts';
|
import {FileType} from './files-types.model.ts';
|
||||||
|
|
||||||
export interface File {
|
export interface File {
|
||||||
ID: number;
|
ID: number;
|
||||||
Name: string;
|
Name: string;
|
||||||
FileType: FileType;
|
FileType: FileType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export enum FileType {
|
export enum FileType {
|
||||||
None = 'None',
|
None = 'None',
|
||||||
Sheet = 'Sheet',
|
Sheet = 'Sheet',
|
||||||
Chords = 'Chords',
|
Chords = 'Chords',
|
||||||
MuseScore = 'MuseScore'
|
MuseScore = 'MuseScore'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { File } from './file.model';
|
import {File} from './file.model';
|
||||||
|
|
||||||
export interface Song {
|
export interface Song {
|
||||||
ID: number;
|
ID: number;
|
||||||
Number: number;
|
Number: number;
|
||||||
Name: string;
|
Name: string;
|
||||||
Text: string;
|
Text: string;
|
||||||
Comments: string;
|
Comments: string;
|
||||||
Key: string;
|
Key: string;
|
||||||
Tempo: number;
|
Tempo: number;
|
||||||
SongType: string;
|
SongType: string;
|
||||||
Final: boolean;
|
Final: boolean;
|
||||||
Files: File[];
|
Files: File[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { trigger, transition, style, animate } from '@angular/animations';
|
import {animate, style, transition, trigger} from '@angular/animations';
|
||||||
|
|
||||||
export const blend = trigger('blend', [
|
export const blend = trigger('blend', [
|
||||||
transition(':enter', [
|
transition(':enter', [
|
||||||
style({ opacity: 0, display: 'none' }),
|
style({opacity: 0, display: 'none'}),
|
||||||
animate('400ms', style({ opacity: 0 , display: 'none'})),
|
animate('400ms', style({opacity: 0, display: 'none'})),
|
||||||
animate('300ms', style({ opacity: 1, display: 'block' }))
|
animate('300ms', style({opacity: 1, display: 'block'}))
|
||||||
]),
|
]),
|
||||||
transition(':leave', [
|
transition(':leave', [
|
||||||
style({ opacity: 1, display: 'block' }),
|
style({opacity: 1, display: 'block'}),
|
||||||
animate('300ms', style({ opacity: 0, display: 'none' }))
|
animate('300ms', style({opacity: 0, display: 'none'}))
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { base } from './../data/urls';
|
import {base} from '../data/urls';
|
||||||
import { Injectable } from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import { FileUploader } from 'ng2-file-upload';
|
import {FileUploader} from 'ng2-file-upload';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class FileuploadFactory {
|
export class FileuploadFactory {
|
||||||
public provideForNewFiles(songId: number): FileUploader {
|
public static provideForNewFiles(songId: number): FileUploader {
|
||||||
const uploader = new FileUploader({
|
const uploader = new FileUploader({
|
||||||
url: base + '/api/songs/' + songId + '/files',
|
url: base + '/api/songs/' + songId + '/files',
|
||||||
autoUpload: true,
|
autoUpload: true,
|
||||||
isHTML5: true
|
isHTML5: true
|
||||||
});
|
});
|
||||||
|
|
||||||
return uploader;
|
return uploader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: true
|
production: true
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// The list of file replacements can be found in `angular.json`.
|
// The list of file replacements can be found in `angular.json`.
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false
|
production: false
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Wgenerator</title>
|
<title>Wgenerator</title>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link href="favicon.ico" rel="icon" type="image/x-icon">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -2,30 +2,30 @@
|
|||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
basePath: '',
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
plugins: [
|
plugins: [
|
||||||
require('karma-jasmine'),
|
require('karma-jasmine'),
|
||||||
require('karma-chrome-launcher'),
|
require('karma-chrome-launcher'),
|
||||||
require('karma-jasmine-html-reporter'),
|
require('karma-jasmine-html-reporter'),
|
||||||
require('karma-coverage-istanbul-reporter'),
|
require('karma-coverage-istanbul-reporter'),
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
],
|
],
|
||||||
client: {
|
client: {
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
coverageIstanbulReporter: {
|
||||||
dir: require('path').join(__dirname, '../coverage'),
|
dir: require('path').join(__dirname, '../coverage'),
|
||||||
reports: ['html', 'lcovonly'],
|
reports: ['html', 'lcovonly'],
|
||||||
fixWebpackSourcePaths: true
|
fixWebpackSourcePaths: true
|
||||||
},
|
},
|
||||||
reporters: ['progress', 'kjhtml'],
|
reporters: ['progress', 'kjhtml'],
|
||||||
port: 9876,
|
port: 9876,
|
||||||
colors: true,
|
colors: true,
|
||||||
logLevel: config.LOG_INFO,
|
logLevel: config.LOG_INFO,
|
||||||
autoWatch: true,
|
autoWatch: true,
|
||||||
browsers: ['Chrome'],
|
browsers: ['Chrome'],
|
||||||
singleRun: false
|
singleRun: false
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { enableProdMode } from '@angular/core';
|
import {enableProdMode} from '@angular/core';
|
||||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
import { AppModule } from './app/app.module';
|
import {AppModule} from './app/app.module';
|
||||||
import { environment } from './environments/environment';
|
import {environment} from './environments/environment';
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
enableProdMode();
|
enableProdMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
|
|||||||
@@ -59,20 +59,20 @@
|
|||||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||||
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||||
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||||
*/
|
*/
|
||||||
// (window as any).__Zone_enable_cross_context_check = true;
|
// (window as any).__Zone_enable_cross_context_check = true;
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* Zone JS is required by default for Angular itself.
|
* Zone JS is required by default for Angular itself.
|
||||||
*/
|
*/
|
||||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
|
|||||||
@@ -19,17 +19,21 @@ html {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
transition: all 300ms ease-in-out;
|
transition: all 300ms ease-in-out;
|
||||||
|
|
||||||
.mat-table tbody {
|
.mat-table tbody {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
th.mat-header-cell:first-of-type {
|
th.mat-header-cell:first-of-type {
|
||||||
border-top-left-radius: 8px;
|
border-top-left-radius: 8px;
|
||||||
transition: all 300ms ease-in-out;
|
transition: all 300ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
th.mat-header-cell:last-of-type {
|
th.mat-header-cell:last-of-type {
|
||||||
border-top-right-radius: 8px;
|
border-top-right-radius: 8px;
|
||||||
transition: all 300ms ease-in-out;
|
transition: all 300ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-table thead {
|
.mat-table thead {
|
||||||
border-top-right-radius: 8px;
|
border-top-right-radius: 8px;
|
||||||
border-top-left-radius: 8px;
|
border-top-left-radius: 8px;
|
||||||
@@ -40,13 +44,16 @@ html {
|
|||||||
tr.selected {
|
tr.selected {
|
||||||
background-color: #0002;
|
background-color: #0002;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr:hover {
|
tr:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #0001;
|
background-color: #0001;
|
||||||
|
|
||||||
td {
|
td {
|
||||||
color: #ff9900;
|
color: #ff9900;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td.mat-cell {
|
td.mat-cell {
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
@@ -58,14 +65,17 @@ html {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 70vw;
|
right: 70vw;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
|
|
||||||
th.mat-header-cell:first-of-type {
|
th.mat-header-cell:first-of-type {
|
||||||
border-top-left-radius: 0px;
|
border-top-left-radius: 0px;
|
||||||
transition: all 300ms ease-in-out;
|
transition: all 300ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
th.mat-header-cell:last-of-type {
|
th.mat-header-cell:last-of-type {
|
||||||
border-top-right-radius: 0px;
|
border-top-right-radius: 0px;
|
||||||
transition: all 300ms ease-in-out;
|
transition: all 300ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-table thead {
|
.mat-table thead {
|
||||||
border-top-right-radius: 0px;
|
border-top-right-radius: 0px;
|
||||||
border-top-left-radius: 0px;
|
border-top-left-radius: 0px;
|
||||||
@@ -95,9 +105,11 @@ html {
|
|||||||
|
|
||||||
.song-detail-container {
|
.song-detail-container {
|
||||||
margin-left: 30vw;
|
margin-left: 30vw;
|
||||||
|
|
||||||
.mat-form-field-infix {
|
.mat-form-field-infix {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-radio-button {
|
.mat-radio-button {
|
||||||
margin: 15px 10px 0 10px;
|
margin: 15px 10px 0 10px;
|
||||||
}
|
}
|
||||||
@@ -106,15 +118,17 @@ html {
|
|||||||
.mat-card {
|
.mat-card {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: none;
|
background: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
td.mat-cell:last-of-type, td.mat-footer-cell:last-of-type, th.mat-header-cell:last-of-type {
|
td.mat-cell:last-of-type, td.mat-footer-cell:last-of-type, th.mat-header-cell:last-of-type {
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
import 'zone.js/dist/zone-testing';
|
import 'zone.js/dist/zone-testing';
|
||||||
import { getTestBed } from '@angular/core/testing';
|
import {getTestBed} from '@angular/core/testing';
|
||||||
import {
|
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
|
||||||
BrowserDynamicTestingModule,
|
|
||||||
platformBrowserDynamicTesting
|
|
||||||
} from '@angular/platform-browser-dynamic/testing';
|
|
||||||
|
|
||||||
declare const require: any;
|
declare const require: any;
|
||||||
|
|
||||||
// First, initialize the Angular testing environment.
|
// First, initialize the Angular testing environment.
|
||||||
getTestBed().initTestEnvironment(
|
getTestBed().initTestEnvironment(
|
||||||
BrowserDynamicTestingModule,
|
BrowserDynamicTestingModule,
|
||||||
platformBrowserDynamicTesting()
|
platformBrowserDynamicTesting()
|
||||||
);
|
);
|
||||||
// Then we find all the tests.
|
// Then we find all the tests.
|
||||||
const context = require.context('./', true, /\.spec\.ts$/);
|
const context = require.context('./', true, /\.spec\.ts$/);
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tslint.json",
|
"extends": "../tslint.json",
|
||||||
"rules": {
|
"rules": {
|
||||||
"directive-selector": [
|
"directive-selector": [
|
||||||
true,
|
true,
|
||||||
"attribute",
|
"attribute",
|
||||||
"app",
|
"app",
|
||||||
"camelCase"
|
"camelCase"
|
||||||
],
|
],
|
||||||
"component-selector": [
|
"component-selector": [
|
||||||
true,
|
true,
|
||||||
"element",
|
"element",
|
||||||
"app",
|
"app",
|
||||||
"kebab-case"
|
"kebab-case"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user