delete functionality
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import {Body, Controller, Get, Post} from '@nestjs/common';
|
import {Body, Controller, Delete, Get, Param, Post} from '@nestjs/common';
|
||||||
import {PlaylistService} from "./playlist.service";
|
import {PlaylistService} from "./playlist.service";
|
||||||
import {PlaylistModel} from "./playlist.model";
|
import {PlaylistModel} from "./playlist.model";
|
||||||
|
|
||||||
@@ -19,4 +19,9 @@ export class PlaylistController {
|
|||||||
async create(@Body() playlist: PlaylistModel): Promise<void> {
|
async create(@Body() playlist: PlaylistModel): Promise<void> {
|
||||||
await this.service.create(playlist);
|
await this.service.create(playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
remove(@Param('id') id: number): Promise<void> {
|
||||||
|
return this.service.remove(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,7 @@ export class PlaylistService {
|
|||||||
|
|
||||||
async remove(id: number): Promise<void> {
|
async remove(id: number): Promise<void> {
|
||||||
await this.repository.delete(id);
|
await this.repository.delete(id);
|
||||||
|
this.io.emit('playlistDelete', {id});
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(playlist: PlaylistEntity): Promise<void> {
|
async create(playlist: PlaylistEntity): Promise<void> {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Controller, Get, Param, Res, StreamableFile} from '@nestjs/common';
|
import {Controller, Delete, Get, Param, Res, StreamableFile} from '@nestjs/common';
|
||||||
import {TrackService} from "./track.service";
|
import {TrackService} from "./track.service";
|
||||||
import {TrackModel} from "./track.model";
|
import {TrackModel} from "./track.model";
|
||||||
import {createReadStream} from "fs";
|
import {createReadStream} from "fs";
|
||||||
@@ -30,4 +30,9 @@ export class TrackController {
|
|||||||
res.set({'Content-Disposition': `attachment; filename="${track.artist} - ${track.song}.mp3"`,});
|
res.set({'Content-Disposition': `attachment; filename="${track.artist} - ${track.song}.mp3"`,});
|
||||||
return new StreamableFile(file);
|
return new StreamableFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
remove(@Param('id') id: number): Promise<void> {
|
||||||
|
return this.service.remove(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,6 @@ export class TrackEntity {
|
|||||||
@Column({default: Date.now()})
|
@Column({default: Date.now()})
|
||||||
createdAt?: number;
|
createdAt?: number;
|
||||||
|
|
||||||
@ManyToOne(() => PlaylistEntity, playlist => playlist.tracks)
|
@ManyToOne(() => PlaylistEntity, playlist => playlist.tracks, {onDelete: "CASCADE"})
|
||||||
playlist?: PlaylistEntity;
|
playlist?: PlaylistEntity;
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,7 @@ export class TrackService {
|
|||||||
|
|
||||||
async remove(id: number): Promise<void> {
|
async remove(id: number): Promise<void> {
|
||||||
await this.repository.delete(id);
|
await this.repository.delete(id);
|
||||||
|
this.io.emit('trackDelete', {id});
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(track: TrackEntity, playlist?: PlaylistEntity): Promise<void> {
|
async create(track: TrackEntity, playlist?: PlaylistEntity): Promise<void> {
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
<i class="fa-brands fa-spotify"></i>
|
<i class="fa-brands fa-spotify"></i>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="!playlist.error">
|
<span>
|
||||||
<span class="is-size-6 has-text-weight-medium">{{trackCompletedCount$ | async}}/{{trackCount$ | async}}</span>
|
<i class="fa-solid fa-xmark is-clickable hover-icon" title="Remove track from list" (click)="delete(playlist.id)"></i>
|
||||||
|
<span *ngIf="!playlist.error" class="is-size-6 has-text-weight-medium">{{trackCompletedCount$ | async}}/{{trackCount$ | async}}</span>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<ng-container *ngIf="playlist.collapsed">
|
<ng-container *ngIf="playlist.collapsed">
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
|
.hover-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-heading {
|
.panel-heading {
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
|
|
||||||
|
&:hover .hover-icon {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ export class PlaylistBoxComponent {
|
|||||||
|
|
||||||
@Input() set playlist(val: Playlist & PlaylistUi) {
|
@Input() set playlist(val: Playlist & PlaylistUi) {
|
||||||
this._playlist = val;
|
this._playlist = val;
|
||||||
this.trackCount$ = this.playlistService.getTrackCount(val.id);
|
this.trackCount$ = this.service.getTrackCount(val.id);
|
||||||
this.trackCompletedCount$ = this.playlistService.getCompletedTrackCount(val.id);
|
this.trackCompletedCount$ = this.service.getCompletedTrackCount(val.id);
|
||||||
this.statusClass$ = this.playlistService.getStatus$(val.id).pipe(
|
this.statusClass$ = this.service.getStatus$(val.id).pipe(
|
||||||
map(status => STATUS2CLASS[status])
|
map(status => STATUS2CLASS[status])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -43,10 +43,14 @@ export class PlaylistBoxComponent {
|
|||||||
trackCompletedCount$!: Observable<number>;
|
trackCompletedCount$!: Observable<number>;
|
||||||
statusClass$!: Observable<string>;
|
statusClass$!: Observable<string>;
|
||||||
|
|
||||||
constructor(private readonly playlistService: PlaylistService) { }
|
constructor(private readonly service: PlaylistService) { }
|
||||||
|
|
||||||
|
|
||||||
toggleCollapse(playlistId: number): void {
|
toggleCollapse(playlistId: number): void {
|
||||||
this.playlistService.toggleCollapsed(playlistId);
|
this.service.toggleCollapsed(playlistId);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(id: number): void {
|
||||||
|
this.service.delete(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
<i class="fa-solid fa-xmark hover-icon" title="Remove track from list" (click)="delete(track.id)"></i>
|
||||||
<ng-container [ngSwitch]="track.status">
|
<ng-container [ngSwitch]="track.status">
|
||||||
<span *ngSwitchCase="trackStatuses.New" class="tag is-info">New</span>
|
<span *ngSwitchCase="trackStatuses.New" class="tag is-info">New</span>
|
||||||
<span *ngSwitchCase="trackStatuses.Searching" class="tag is-warning">Searching</span>
|
<span *ngSwitchCase="trackStatuses.Searching" class="tag is-warning">Searching</span>
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
.hover-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-block {
|
.panel-block {
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
|
|
||||||
|
&:hover .hover-icon {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {Observable} from "rxjs";
|
|||||||
export class TrackListComponent {
|
export class TrackListComponent {
|
||||||
|
|
||||||
@Input() set playlistId(value: number) {
|
@Input() set playlistId(value: number) {
|
||||||
console.log(value);
|
|
||||||
this.tracks$ = this.service.getAllByPlaylist(value);
|
this.tracks$ = this.service.getAllByPlaylist(value);
|
||||||
}
|
}
|
||||||
tracks$!: Observable<Track[]>;
|
tracks$!: Observable<Track[]>;
|
||||||
@@ -21,6 +20,9 @@ export class TrackListComponent {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly service: TrackService,
|
private readonly service: TrackService,
|
||||||
) {
|
) { }
|
||||||
|
|
||||||
|
delete(id: number): void {
|
||||||
|
this.service.delete(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import { Injectable } from '@angular/core';
|
|||||||
import {createStore} from "@ngneat/elf";
|
import {createStore} from "@ngneat/elf";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import {HttpClient} from "@angular/common/http";
|
||||||
import {
|
import {
|
||||||
|
deleteEntities,
|
||||||
getEntityByPredicate,
|
getEntityByPredicate,
|
||||||
selectAllEntities, selectEntities,
|
selectAllEntities, selectEntities, selectEntity,
|
||||||
selectEntityByPredicate,
|
selectEntityByPredicate,
|
||||||
setEntities,
|
setEntities,
|
||||||
UIEntitiesRef,
|
UIEntitiesRef,
|
||||||
@@ -64,6 +65,7 @@ export class PlaylistService {
|
|||||||
private readonly trackService: TrackService,
|
private readonly trackService: TrackService,
|
||||||
) {
|
) {
|
||||||
this.socket.on('playlistUpdate', (playlist: Playlist) => this.store.update(upsertEntities(playlist)));
|
this.socket.on('playlistUpdate', (playlist: Playlist) => this.store.update(upsertEntities(playlist)));
|
||||||
|
this.socket.on('playlistDelete', ({id}: {id: number}) => this.store.update(deleteEntities(Number(id))));
|
||||||
this.socket.on('playlistNew', (playlist: Playlist) =>
|
this.socket.on('playlistNew', (playlist: Playlist) =>
|
||||||
this.store.update(
|
this.store.update(
|
||||||
upsertEntities(playlist),
|
upsertEntities(playlist),
|
||||||
@@ -72,8 +74,8 @@ export class PlaylistService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getById(playlistId: number): Observable<Playlist | undefined> {
|
getById(id: number): Observable<Playlist | undefined> {
|
||||||
return this.store.pipe(selectEntityByPredicate(({id}) => id === playlistId));
|
return this.store.pipe(selectEntity(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
getTrackCount(id: number): Observable<number> {
|
getTrackCount(id: number): Observable<number> {
|
||||||
@@ -126,4 +128,8 @@ export class PlaylistService {
|
|||||||
toggleCollapsed(id: number): void {
|
toggleCollapsed(id: number): void {
|
||||||
this.store.update(updateEntities(id, old => ({...old, collapsed: !old.collapsed}), { ref: UIEntitiesRef }))
|
this.store.update(updateEntities(id, old => ({...old, collapsed: !old.collapsed}), { ref: UIEntitiesRef }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(id: number): void {
|
||||||
|
this.http.delete(`${ENDPOINT}/${id}`).subscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {createStore} from "@ngneat/elf";
|
import {createStore} from "@ngneat/elf";
|
||||||
import {selectManyByPredicate, upsertEntities, withEntities} from "@ngneat/elf-entities";
|
import {deleteEntities, selectManyByPredicate, upsertEntities, withEntities} from "@ngneat/elf-entities";
|
||||||
import {Socket} from "ngx-socket-io";
|
import {Socket} from "ngx-socket-io";
|
||||||
import {map, Observable, tap} from "rxjs";
|
import {map, Observable, tap} from "rxjs";
|
||||||
import {trackRequestResult} from "@ngneat/elf-requests";
|
import {trackRequestResult} from "@ngneat/elf-requests";
|
||||||
@@ -41,7 +41,7 @@ export class TrackService {
|
|||||||
|
|
||||||
getAllByPlaylist(id: number, status?: TrackStatusEnum): Observable<Track[]> {
|
getAllByPlaylist(id: number, status?: TrackStatusEnum): Observable<Track[]> {
|
||||||
return this.store.pipe(
|
return this.store.pipe(
|
||||||
selectManyByPredicate(({playlistId}) => playlistId === id),
|
selectManyByPredicate((track) => track?.playlistId === id),
|
||||||
map(data => data.filter(item => status === undefined || item.status === status)),
|
map(data => data.filter(item => status === undefined || item.status === status)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -59,6 +59,7 @@ export class TrackService {
|
|||||||
private readonly socket: Socket,
|
private readonly socket: Socket,
|
||||||
) {
|
) {
|
||||||
this.socket.on('trackUpdate', (track: Track) => this.store.update(upsertEntities(track)));
|
this.socket.on('trackUpdate', (track: Track) => this.store.update(upsertEntities(track)));
|
||||||
|
this.socket.on('trackDelete', ({id}: {id: number}) => this.store.update(deleteEntities(id)));
|
||||||
this.socket.on('trackNew', ({track, playlistId}: {track: Track, playlistId: number}) =>
|
this.socket.on('trackNew', ({track, playlistId}: {track: Track, playlistId: number}) =>
|
||||||
this.store.update(upsertEntities([{...track, playlistId}]))
|
this.store.update(upsertEntities([{...track, playlistId}]))
|
||||||
);
|
);
|
||||||
@@ -70,4 +71,8 @@ export class TrackService {
|
|||||||
trackRequestResult([STORE_NAME], { skipCache: true }),
|
trackRequestResult([STORE_NAME], { skipCache: true }),
|
||||||
).subscribe();
|
).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(id: number): void {
|
||||||
|
this.http.delete(`${ENDPOINT}/${id}`).subscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user