mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-02 10:15:47 +01:00
Add networkerror notify
This commit is contained in:
@@ -87,7 +87,6 @@ export class UserManageController {
|
|||||||
|
|
||||||
@Post('info')
|
@Post('info')
|
||||||
async getUser(@Body() body: UserInfoRequest): Promise<UserInfoResponse> {
|
async getUser(@Body() body: UserInfoRequest): Promise<UserInfoResponse> {
|
||||||
console.log(body);
|
|
||||||
const user = await this.usersService.findOne(body.username);
|
const user = await this.usersService.findOne(body.username);
|
||||||
if (HasFailed(user)) {
|
if (HasFailed(user)) {
|
||||||
this.logger.warn(user.getReason());
|
this.logger.warn(user.getReason());
|
||||||
|
@@ -8,6 +8,7 @@ import { AppRoutingModule } from './app.routing.module';
|
|||||||
import { FooterModule } from './components/footer/footer.module';
|
import { FooterModule } from './components/footer/footer.module';
|
||||||
import { HeaderModule } from './components/header/header.module';
|
import { HeaderModule } from './components/header/header.module';
|
||||||
import { GuardsModule } from './guards/guards.module';
|
import { GuardsModule } from './guards/guards.module';
|
||||||
|
import { UtilModule } from './util/util.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
@@ -17,6 +18,7 @@ import { GuardsModule } from './guards/guards.module';
|
|||||||
PortalModule,
|
PortalModule,
|
||||||
MatSidenavModule,
|
MatSidenavModule,
|
||||||
|
|
||||||
|
UtilModule.forRoot(),
|
||||||
GuardsModule,
|
GuardsModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
|
|
||||||
|
@@ -3,7 +3,6 @@ import { NgModule } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { UtilModule } from 'src/app/util/util.module';
|
|
||||||
import { CopyFieldComponent } from './copyfield.component';
|
import { CopyFieldComponent } from './copyfield.component';
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [CopyFieldComponent],
|
declarations: [CopyFieldComponent],
|
||||||
@@ -12,7 +11,6 @@ import { CopyFieldComponent } from './copyfield.component';
|
|||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
UtilModule,
|
|
||||||
],
|
],
|
||||||
exports: [CopyFieldComponent],
|
exports: [CopyFieldComponent],
|
||||||
})
|
})
|
||||||
|
@@ -5,7 +5,6 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { UtilModule } from 'src/app/util/util.module';
|
|
||||||
import { HeaderComponent } from './header.component';
|
import { HeaderComponent } from './header.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -16,7 +15,6 @@ import { HeaderComponent } from './header.component';
|
|||||||
RouterModule,
|
RouterModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
UtilModule,
|
|
||||||
],
|
],
|
||||||
declarations: [HeaderComponent],
|
declarations: [HeaderComponent],
|
||||||
exports: [HeaderComponent],
|
exports: [HeaderComponent],
|
||||||
|
@@ -24,12 +24,12 @@ export class PermissionGuard implements CanActivate, CanActivateChild {
|
|||||||
childRoute: ActivatedRouteSnapshot,
|
childRoute: ActivatedRouteSnapshot,
|
||||||
state: RouterStateSnapshot
|
state: RouterStateSnapshot
|
||||||
) {
|
) {
|
||||||
console.log('canActivateChild');
|
//console.log('canActivateChild');
|
||||||
return await this.can(childRoute, state);
|
return await this.can(childRoute, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
console.log('canActivate');
|
//console.log('canActivate');
|
||||||
return await this.can(route, state);
|
return await this.can(route, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
frontend/src/app/models/api-error.ts
Normal file
4
frontend/src/app/models/api-error.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface ApiError {
|
||||||
|
error: any;
|
||||||
|
url: RequestInfo;
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
import { Component, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||||
import { SysPreferenceResponse } from 'picsur-shared/dist/dto/api/pref.dto';
|
import { SysPreferenceResponse } from 'picsur-shared/dist/dto/api/pref.dto';
|
||||||
import { SysprefService as SysPrefService } from 'src/app/services/api/syspref.service';
|
import { SysprefService as SysPrefService } from 'src/app/services/api/syspref.service';
|
||||||
@@ -6,7 +6,7 @@ import { SysprefService as SysPrefService } from 'src/app/services/api/syspref.s
|
|||||||
@Component({
|
@Component({
|
||||||
templateUrl: './settings-syspref.component.html',
|
templateUrl: './settings-syspref.component.html',
|
||||||
})
|
})
|
||||||
export class SettingsSysprefComponent implements OnInit, OnChanges {
|
export class SettingsSysprefComponent implements OnInit {
|
||||||
render = true;
|
render = true;
|
||||||
preferences: SysPreferenceResponse[] = [];
|
preferences: SysPreferenceResponse[] = [];
|
||||||
|
|
||||||
@@ -32,10 +32,6 @@ export class SettingsSysprefComponent implements OnInit, OnChanges {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
|
||||||
console.log('cahnges', changes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private compareFlatObjectArray(a: any[], b: any[]): boolean {
|
private compareFlatObjectArray(a: any[], b: any[]): boolean {
|
||||||
if (a.length !== b.length) {
|
if (a.length !== b.length) {
|
||||||
return false;
|
return false;
|
||||||
|
@@ -32,12 +32,12 @@ export class SettingsUsersComponent implements OnInit {
|
|||||||
return this.updateSubject
|
return this.updateSubject
|
||||||
.pipe(throttleTime(500, undefined, { leading: true, trailing: true }))
|
.pipe(throttleTime(500, undefined, { leading: true, trailing: true }))
|
||||||
.subscribe(async (pageEvent: PageEvent) => {
|
.subscribe(async (pageEvent: PageEvent) => {
|
||||||
let amount = await this.fetchUsers(
|
let success = await this.fetchUsers(
|
||||||
pageEvent.pageSize,
|
pageEvent.pageSize,
|
||||||
pageEvent.pageIndex
|
pageEvent.pageIndex
|
||||||
);
|
);
|
||||||
if (amount === 0) {
|
if (!success) {
|
||||||
if ( pageEvent.previousPageIndex === pageEvent.pageIndex - 1){
|
if (pageEvent.previousPageIndex === pageEvent.pageIndex - 1) {
|
||||||
this.paginator.previousPage();
|
this.paginator.previousPage();
|
||||||
} else {
|
} else {
|
||||||
this.paginator.firstPage();
|
this.paginator.firstPage();
|
||||||
@@ -49,12 +49,15 @@ export class SettingsUsersComponent implements OnInit {
|
|||||||
private async fetchUsers(
|
private async fetchUsers(
|
||||||
pageSize: number,
|
pageSize: number,
|
||||||
pageIndex: number
|
pageIndex: number
|
||||||
): Promise<number> {
|
): Promise<boolean> {
|
||||||
const result = await this.userManageService.getUsers(pageSize, pageIndex);
|
const result = await this.userManageService.getUsers(pageSize, pageIndex);
|
||||||
if (HasFailed(result)) return 0;
|
if (HasFailed(result)) return false;
|
||||||
|
|
||||||
this.dataSubject.next(result);
|
if (result.length > 0) {
|
||||||
|
this.dataSubject.next(result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return result.length;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,8 @@ import { ClassConstructor, plainToClass } from 'class-transformer';
|
|||||||
import { ApiResponse, ApiSuccessResponse } from 'picsur-shared/dist/dto/api';
|
import { ApiResponse, ApiSuccessResponse } from 'picsur-shared/dist/dto/api';
|
||||||
import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types';
|
import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types';
|
||||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { ApiError } from 'src/app/models/api-error';
|
||||||
import { MultiPartRequest } from '../../models/multi-part-request';
|
import { MultiPartRequest } from '../../models/multi-part-request';
|
||||||
import { KeyService } from './key.service';
|
import { KeyService } from './key.service';
|
||||||
|
|
||||||
@@ -12,6 +14,12 @@ import { KeyService } from './key.service';
|
|||||||
export class ApiService {
|
export class ApiService {
|
||||||
private readonly logger = console;
|
private readonly logger = console;
|
||||||
|
|
||||||
|
private errorSubject = new Subject<ApiError>();
|
||||||
|
|
||||||
|
public get networkErrors() {
|
||||||
|
return this.errorSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
constructor(private keyService: KeyService) {}
|
constructor(private keyService: KeyService) {}
|
||||||
|
|
||||||
public async get<T extends Object>(
|
public async get<T extends Object>(
|
||||||
@@ -128,9 +136,12 @@ export class ApiService {
|
|||||||
options.headers = headers;
|
options.headers = headers;
|
||||||
|
|
||||||
return await window.fetch(url, options);
|
return await window.fetch(url, options);
|
||||||
} catch (e: any) {
|
} catch (error: any) {
|
||||||
this.logger.warn(e);
|
this.errorSubject.next({
|
||||||
return Fail('Something went wrong');
|
error,
|
||||||
|
url,
|
||||||
|
});
|
||||||
|
return Fail('Network Error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -111,7 +111,6 @@ export class SysprefService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private sync() {
|
private sync() {
|
||||||
console.warn('System preferences have been flushed');
|
|
||||||
this.sysprefObservable.next(
|
this.sysprefObservable.next(
|
||||||
([] as SysPreferenceResponse[]).concat(this.snapshot)
|
([] as SysPreferenceResponse[]).concat(this.snapshot)
|
||||||
);
|
);
|
||||||
|
32
frontend/src/app/util/apierror.service.ts
Normal file
32
frontend/src/app/util/apierror.service.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||||
|
import { SnackBarType } from '../models/snack-bar-type';
|
||||||
|
import { ApiService } from '../services/api/api.service';
|
||||||
|
import { UtilService } from './util.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class ApiErrorService {
|
||||||
|
constructor(
|
||||||
|
private apiSerivce: ApiService,
|
||||||
|
private utilService: UtilService
|
||||||
|
) {
|
||||||
|
this.subscribeErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoUnsubscribe()
|
||||||
|
private subscribeErrors() {
|
||||||
|
return this.apiSerivce.networkErrors.subscribe((error) => {
|
||||||
|
let url = '';
|
||||||
|
if (typeof error.url === 'string') url = error.url;
|
||||||
|
else url = error.url.url;
|
||||||
|
|
||||||
|
if (url.startsWith('/api')) {
|
||||||
|
this.utilService.showSnackBar('Network Error', SnackBarType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(error.error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -1,24 +1,31 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { NgModule } from '@angular/core';
|
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
MatSnackBarModule,
|
MatSnackBarModule,
|
||||||
MAT_SNACK_BAR_DEFAULT_OPTIONS
|
MAT_SNACK_BAR_DEFAULT_OPTIONS
|
||||||
} from '@angular/material/snack-bar';
|
} from '@angular/material/snack-bar';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { UtilService } from './util.service';
|
import { ApiErrorService } from './apierror.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [],
|
|
||||||
providers: [
|
|
||||||
UtilService,
|
|
||||||
{
|
|
||||||
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
|
|
||||||
useValue: {
|
|
||||||
duration: 4000,
|
|
||||||
horizontalPosition: 'left',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
imports: [CommonModule, MatSnackBarModule, RouterModule],
|
imports: [CommonModule, MatSnackBarModule, RouterModule],
|
||||||
})
|
})
|
||||||
export class UtilModule {}
|
export class UtilModule {
|
||||||
|
static forRoot(): ModuleWithProviders<UtilModule> {
|
||||||
|
return {
|
||||||
|
ngModule: UtilModule,
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
|
||||||
|
useValue: {
|
||||||
|
duration: 4000,
|
||||||
|
horizontalPosition: 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start apiErrorService
|
||||||
|
constructor(private apiErrorService: ApiErrorService) {}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user