split up utilservice, and change error behaviour
This commit is contained in:
parent
e96c24a669
commit
c57ae98f2c
|
@ -10,7 +10,7 @@ import {
|
|||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { RouteTransitionAnimations } from './app.animation';
|
||||
import { PRouteData } from './models/dto/picsur-routes.dto';
|
||||
import { BootstrapService } from './util/util-module/bootstrap.service';
|
||||
import { BootstrapService } from './util/bootstrap.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
|
|
@ -9,7 +9,9 @@ import { AppRoutingModule } from './app.routing.module';
|
|||
import { FooterModule } from './components/footer/footer.module';
|
||||
import { HeaderModule } from './components/header/header.module';
|
||||
import { GuardsModule } from './guards/guards.module';
|
||||
import { UtilModule } from './util/util-module/util.module';
|
||||
import { ApiErrorManagerModule } from './util/api-error-manager/api-error-manager.module';
|
||||
import { CompatibilityManagerModule } from './util/compatibilitiy-manager/compatibility-manager.module';
|
||||
import { SnackBarManagerModule } from './util/snackbar-manager/snackbar-manager.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
|
@ -19,7 +21,10 @@ import { UtilModule } from './util/util-module/util.module';
|
|||
PortalModule,
|
||||
MatSidenavModule,
|
||||
|
||||
UtilModule.forRoot(),
|
||||
SnackBarManagerModule.forRoot(),
|
||||
CompatibilityManagerModule,
|
||||
ApiErrorManagerModule,
|
||||
|
||||
GuardsModule,
|
||||
AppRoutingModule,
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Clipboard } from '@angular/cdk/clipboard';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { Fail, FT } from 'picsur-shared/dist/types';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
|
||||
@Component({
|
||||
selector: 'copy-field',
|
||||
|
@ -9,6 +10,8 @@ import { UtilService } from 'src/app/util/util-module/util.service';
|
|||
styleUrls: ['./copy-field.component.scss'],
|
||||
})
|
||||
export class CopyFieldComponent {
|
||||
private readonly logger = new Logger(CopyFieldComponent.name);
|
||||
|
||||
// Two parameters: name, value
|
||||
@Input() label: string = 'Loading...';
|
||||
@Input() value: string = 'Loading...';
|
||||
|
@ -20,20 +23,20 @@ export class CopyFieldComponent {
|
|||
@Output('hide') onHide = new EventEmitter<boolean>();
|
||||
|
||||
constructor(
|
||||
private readonly utilService: UtilService,
|
||||
private readonly clipboard: Clipboard,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
public copy() {
|
||||
if (this.clipboard.copy(this.value)) {
|
||||
this.utilService.showSnackBar(`Copied ${this.label}!`, SnackBarType.Info);
|
||||
this.errorService.info(`Copied ${this.label}!`);
|
||||
this.onCopy.emit(this.value);
|
||||
return;
|
||||
}
|
||||
|
||||
return this.utilService.showSnackBar(
|
||||
'Copying to clipboard failed',
|
||||
SnackBarType.Error,
|
||||
return this.errorService.showFailure(
|
||||
Fail(FT.Internal, 'Copying to clipboard failed'),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,14 @@ import { NgModule } from '@angular/core';
|
|||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { CopyFieldComponent } from './copy-field.component';
|
||||
@NgModule({
|
||||
declarations: [CopyFieldComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
|
||||
MatInputModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
|
|
|
@ -12,10 +12,10 @@ import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
|||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
import { UserService } from 'src/app/services/api/user.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
|
@ -24,12 +24,14 @@ import { UtilService } from 'src/app/util/util-module/util.service';
|
|||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class HeaderComponent implements OnInit {
|
||||
private readonly logger = new Logger(HeaderComponent.name);
|
||||
|
||||
constructor(
|
||||
private readonly router: Router,
|
||||
private readonly userService: UserService,
|
||||
private readonly permissionService: PermissionService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly changeDetector: ChangeDetectorRef,
|
||||
private readonly errorService: ErrorService
|
||||
) {}
|
||||
|
||||
@Input('enableHamburger') public set enableHamburger(value: boolean) {
|
||||
|
@ -90,12 +92,10 @@ export class HeaderComponent implements OnInit {
|
|||
|
||||
async doLogout() {
|
||||
const user = await this.userService.logout();
|
||||
if (HasFailed(user)) {
|
||||
this.utilService.showSnackBar(user.getReason(), SnackBarType.Error);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(user))
|
||||
return this.errorService.showFailure(user, this.logger);
|
||||
|
||||
this.utilService.showSnackBar('Logout successful', SnackBarType.Success);
|
||||
this.errorService.success('Logout successful');
|
||||
}
|
||||
|
||||
doSettings() {
|
||||
|
|
|
@ -6,11 +6,14 @@ import { MatMenuModule } from '@angular/material/menu';
|
|||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { HeaderComponent } from './header.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
|
||||
MatToolbarModule,
|
||||
MatButtonModule,
|
||||
RouterModule,
|
||||
|
|
|
@ -7,9 +7,9 @@ import {
|
|||
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Required } from 'src/app/models/decorators/required.decorator';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { Throttle } from 'src/app/util/throttle';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
|
||||
@Component({
|
||||
selector: 'pref-option',
|
||||
|
@ -17,6 +17,8 @@ import { UtilService } from 'src/app/util/util-module/util.service';
|
|||
styleUrls: ['./pref-option.component.scss'],
|
||||
})
|
||||
export class PrefOptionComponent implements OnInit {
|
||||
private readonly logger = new Logger(PrefOptionComponent.name);
|
||||
|
||||
@Input() @Required pref: DecodedPref;
|
||||
@Input('update') @Required updateFunction: (
|
||||
key: string,
|
||||
|
@ -28,7 +30,7 @@ export class PrefOptionComponent implements OnInit {
|
|||
|
||||
private updateSubject = new Subject<PrefValueType>();
|
||||
|
||||
constructor(private readonly utilService: UtilService) {}
|
||||
constructor(private readonly errorService: ErrorService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.subscribeUpdate();
|
||||
|
@ -87,12 +89,9 @@ export class PrefOptionComponent implements OnInit {
|
|||
? `Enabled ${this.name}`
|
||||
: `Disabled ${this.name}`
|
||||
: '';
|
||||
this.utilService.showSnackBar(message, SnackBarType.Success);
|
||||
this.errorService.success(message);
|
||||
} else {
|
||||
this.utilService.showSnackBar(
|
||||
`Failed to update ${this.name}`,
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.errorService.showFailure(result, this.logger);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,14 @@ import { NgModule } from '@angular/core';
|
|||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { PrefOptionComponent } from './pref-option.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatSlideToggleModule,
|
||||
|
|
|
@ -4,14 +4,11 @@ import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
|||
import { ImageFileType } from 'picsur-shared/dist/dto/mimes.dto';
|
||||
import { EImage } from 'picsur-shared/dist/entities/image.entity';
|
||||
import { HasFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { ImageService } from 'src/app/services/api/image.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import {
|
||||
BootstrapService,
|
||||
BSScreenSize
|
||||
} from 'src/app/util/util-module/bootstrap.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { BootstrapService, BSScreenSize } from 'src/app/util/bootstrap.service';
|
||||
import { DialogService } from 'src/app/util/dialog-manager/dialog.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './images.component.html',
|
||||
|
@ -30,8 +27,9 @@ export class ImagesComponent implements OnInit {
|
|||
private readonly route: ActivatedRoute,
|
||||
private readonly router: Router,
|
||||
private readonly bootstrapService: BootstrapService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly imageService: ImageService,
|
||||
private readonly errorService: ErrorService,
|
||||
private readonly dialogService: DialogService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -71,7 +69,8 @@ export class ImagesComponent implements OnInit {
|
|||
|
||||
getThumbnailUrl(image: EImage) {
|
||||
return (
|
||||
this.imageService.GetImageURL(image.id, ImageFileType.QOI) + '?height=480&shrinkonly=yes'
|
||||
this.imageService.GetImageURL(image.id, ImageFileType.QOI) +
|
||||
'?height=480&shrinkonly=yes'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -80,7 +79,7 @@ export class ImagesComponent implements OnInit {
|
|||
}
|
||||
|
||||
async deleteImage(image: EImage) {
|
||||
const pressedButton = await this.utilService.showDialog({
|
||||
const pressedButton = await this.dialogService.showDialog({
|
||||
title: `Are you sure you want to delete the image?`,
|
||||
description: 'This action cannot be undone.',
|
||||
buttons: [
|
||||
|
@ -98,15 +97,11 @@ export class ImagesComponent implements OnInit {
|
|||
|
||||
if (pressedButton === 'delete') {
|
||||
const result = await this.imageService.DeleteImage(image.id ?? '');
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to delete image',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
} else {
|
||||
this.utilService.showSnackBar('Image deleted', SnackBarType.Success);
|
||||
this.images = this.images?.filter((i) => i.id !== image.id) ?? null;
|
||||
}
|
||||
if (HasFailed(result))
|
||||
return this.errorService.showFailure(result, this.logger);
|
||||
|
||||
this.errorService.success('Image deleted');
|
||||
this.images = this.images?.filter((i) => i.id !== image.id) ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import { MasonryModule } from 'src/app/components/masonry/masonry.module';
|
|||
import { PaginatorModule } from 'src/app/components/paginator/paginator.module';
|
||||
import { PicsurImgModule } from 'src/app/components/picsur-img/picsur-img.module';
|
||||
import { PipesModule } from 'src/app/pipes/pipes.module';
|
||||
import { DialogManagerModule } from 'src/app/util/dialog-manager/dialog-manager.module';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { ImagesComponent } from './images.component';
|
||||
import { ImagesRoutingModule } from './images.routing.module';
|
||||
|
||||
|
@ -15,6 +17,9 @@ import { ImagesRoutingModule } from './images.routing.module';
|
|||
declarations: [ImagesComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
DialogManagerModule,
|
||||
|
||||
ImagesRoutingModule,
|
||||
MatCardModule,
|
||||
MatButtonModule,
|
||||
|
@ -23,7 +28,7 @@ import { ImagesRoutingModule } from './images.routing.module';
|
|||
PaginatorModule,
|
||||
PicsurImgModule,
|
||||
MomentModule,
|
||||
PipesModule
|
||||
PipesModule,
|
||||
],
|
||||
})
|
||||
export class ImagesRouteModule {}
|
||||
|
|
|
@ -1,32 +1,37 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { Fail, FT, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { ProcessingViewMeta } from 'src/app/models/dto/processing-view-meta.dto';
|
||||
import { ImageService } from 'src/app/services/api/image.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './processing.component.html',
|
||||
})
|
||||
export class ProcessingComponent implements OnInit {
|
||||
private readonly logger = new Logger(ProcessingComponent.name);
|
||||
|
||||
constructor(
|
||||
private readonly router: Router,
|
||||
private readonly imageService: ImageService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
const state = history.state as ProcessingViewMeta;
|
||||
if (!state) {
|
||||
return this.utilService.quitError('Error');
|
||||
return this.errorService.quitFailure(
|
||||
Fail(FT.UsrValidation, 'No state provided'),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
|
||||
history.replaceState(null, '');
|
||||
|
||||
const id = await this.imageService.UploadImage(state.imageFile);
|
||||
if (HasFailed(id)) {
|
||||
return this.utilService.quitError(id.getReason());
|
||||
}
|
||||
if (HasFailed(id))
|
||||
return this.errorService.quitFailure(id, this.logger);
|
||||
|
||||
this.router.navigate([`/view/`, id], { replaceUrl: true });
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { ProcessingComponent } from './processing.component';
|
||||
import { ProcessingRoutingModule } from './processing.routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProcessingComponent],
|
||||
imports: [CommonModule, ProcessingRoutingModule, MatProgressSpinnerModule],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
ProcessingRoutingModule,
|
||||
MatProgressSpinnerModule,
|
||||
],
|
||||
})
|
||||
export class ProcessingRouteModule {}
|
||||
|
|
|
@ -3,15 +3,15 @@ import { Component, OnInit, ViewChild } from '@angular/core';
|
|||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
||||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { EApiKey } from 'picsur-shared/dist/entities/apikey.entity';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { Fail, FT, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { ApiKeysService } from 'src/app/services/api/apikeys.service';
|
||||
import { UserService } from 'src/app/services/api/user.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { BootstrapService } from 'src/app/util/bootstrap.service';
|
||||
import { DialogService } from 'src/app/util/dialog-manager/dialog.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { Throttle } from 'src/app/util/throttle';
|
||||
import { BootstrapService } from 'src/app/util/util-module/bootstrap.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './settings-apikeys.component.html',
|
||||
|
@ -36,10 +36,11 @@ export class SettingsApiKeysComponent implements OnInit {
|
|||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
|
||||
constructor(
|
||||
private readonly utilService: UtilService,
|
||||
private readonly apikeysService: ApiKeysService,
|
||||
private readonly userService: UserService,
|
||||
private readonly clipboard: Clipboard,
|
||||
private readonly errorService: ErrorService,
|
||||
private readonly dialogService: DialogService,
|
||||
// Public because used in template
|
||||
public readonly bootstrapService: BootstrapService,
|
||||
) {}
|
||||
|
@ -52,13 +53,8 @@ export class SettingsApiKeysComponent implements OnInit {
|
|||
|
||||
public async addApiKey() {
|
||||
const result = await this.apikeysService.createApiKey();
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to create api key',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(result))
|
||||
return this.errorService.showFailure(result, this.logger);
|
||||
|
||||
const success = await this.fetchApiKeys(
|
||||
this.paginator.pageSize,
|
||||
|
@ -70,35 +66,29 @@ export class SettingsApiKeysComponent implements OnInit {
|
|||
|
||||
const clipboardResult = this.clipboard.copy(result.key);
|
||||
if (!clipboardResult) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to copy api key to clipboard',
|
||||
SnackBarType.Error,
|
||||
return this.errorService.showFailure(
|
||||
Fail(FT.Internal, 'Failed to copy api key to clipboard'),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
|
||||
this.utilService.showSnackBar(
|
||||
'Api key created and copied to clipboard',
|
||||
SnackBarType.Success,
|
||||
);
|
||||
this.errorService.success('Api key created and copied to clipboard');
|
||||
}
|
||||
|
||||
public copyKey(apikey: string) {
|
||||
const result = this.clipboard.copy(apikey);
|
||||
if (!result) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to copy api key to clipboard',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
} else {
|
||||
this.utilService.showSnackBar(
|
||||
'Api key copied to clipboard',
|
||||
SnackBarType.Success,
|
||||
return this.errorService.showFailure(
|
||||
Fail(FT.Internal, 'Failed to copy api key to clipboard'),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
|
||||
this.errorService.success('Api key copied to clipboard');
|
||||
}
|
||||
|
||||
public async deleteApiKey(apikeyId: string) {
|
||||
const pressedButton = await this.utilService.showDialog({
|
||||
const pressedButton = await this.dialogService.showDialog({
|
||||
title: `Are you sure you want to delete this api key?`,
|
||||
description: 'This action cannot be undone.',
|
||||
buttons: [
|
||||
|
@ -117,12 +107,9 @@ export class SettingsApiKeysComponent implements OnInit {
|
|||
if (pressedButton === 'delete') {
|
||||
const result = await this.apikeysService.deleteApiKey(apikeyId);
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to delete api key',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.errorService.showFailure(result, this.logger);
|
||||
} else {
|
||||
this.utilService.showSnackBar('Api key deleted', SnackBarType.Success);
|
||||
this.errorService.success('Api key deleted');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,18 +125,10 @@ export class SettingsApiKeysComponent implements OnInit {
|
|||
async updateKeyName(name: string, apikeyID: string) {
|
||||
const result = await this.apikeysService.updateApiKey(apikeyID, name);
|
||||
|
||||
if (HasFailed(result)) {
|
||||
this.logger.warn(result.print());
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to update api key name',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
} else {
|
||||
this.utilService.showSnackBar(
|
||||
'Api key name updated',
|
||||
SnackBarType.Success,
|
||||
);
|
||||
}
|
||||
if (HasFailed(result))
|
||||
return this.errorService.showFailure(result, this.logger);
|
||||
|
||||
this.errorService.success('Api key name updated');
|
||||
}
|
||||
|
||||
@AutoUnsubscribe()
|
||||
|
@ -180,13 +159,9 @@ export class SettingsApiKeysComponent implements OnInit {
|
|||
pageIndex,
|
||||
this.userService.snapshot?.id,
|
||||
);
|
||||
if (HasFailed(response)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to fetch api keys',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.logger.warn(response.print());
|
||||
return false;
|
||||
if (HasFailed(response)){
|
||||
this.errorService.showFailure(response, this.logger);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.dataSubject.next(response.results);
|
||||
|
|
|
@ -9,6 +9,8 @@ import { MatPaginatorModule } from '@angular/material/paginator';
|
|||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MomentModule } from 'ngx-moment';
|
||||
import { FabModule } from 'src/app/components/fab/fab.module';
|
||||
import { DialogManagerModule } from 'src/app/util/dialog-manager/dialog-manager.module';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { SettingsApiKeyEditorComponent } from './apikey-editor/apikey-editor.component';
|
||||
import { SettingsApiKeysComponent } from './settings-apikeys.component';
|
||||
import { SettingsApiKeysRoutingModule } from './settings-apikeys.routing.module';
|
||||
|
@ -17,6 +19,9 @@ import { SettingsApiKeysRoutingModule } from './settings-apikeys.routing.module'
|
|||
declarations: [SettingsApiKeysComponent, SettingsApiKeyEditorComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
DialogManagerModule,
|
||||
|
||||
SettingsApiKeysRoutingModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
|
|
|
@ -3,12 +3,11 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { UIFriendlyPermissions } from 'src/app/i18n/permissions.i18n';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { UpdateRoleControl } from 'src/app/models/forms/update-role.control';
|
||||
import { RolesService } from 'src/app/services/api/roles.service';
|
||||
import { StaticInfoService } from 'src/app/services/api/static-info.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
|
||||
enum EditMode {
|
||||
edit = 'edit',
|
||||
|
@ -37,9 +36,9 @@ export class SettingsRolesEditComponent implements OnInit {
|
|||
constructor(
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly router: Router,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly rolesService: RolesService,
|
||||
private readonly staticInfo: StaticInfoService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -60,10 +59,8 @@ export class SettingsRolesEditComponent implements OnInit {
|
|||
|
||||
// Fetch data and populate form
|
||||
const role = await this.rolesService.getRole(rolename);
|
||||
if (HasFailed(role)) {
|
||||
this.utilService.showSnackBar('Failed to get role', SnackBarType.Error);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(role))
|
||||
return this.errorService.showFailure(role, this.logger);
|
||||
this.model.putRoleName(role.name);
|
||||
this.model.putPermissions(role.permissions);
|
||||
}
|
||||
|
@ -78,26 +75,16 @@ export class SettingsRolesEditComponent implements OnInit {
|
|||
|
||||
if (this.adding) {
|
||||
const resultRole = await this.rolesService.createRole(data);
|
||||
if (HasFailed(resultRole)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to create role',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(resultRole))
|
||||
return this.errorService.showFailure(resultRole, this.logger);
|
||||
|
||||
this.utilService.showSnackBar('Role created', SnackBarType.Success);
|
||||
this.errorService.success('Role created');
|
||||
} else {
|
||||
const resultRole = await this.rolesService.updateRole(data);
|
||||
if (HasFailed(resultRole)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to update role',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(resultRole))
|
||||
return this.errorService.showFailure(resultRole, this.logger);
|
||||
|
||||
this.utilService.showSnackBar('Role updated', SnackBarType.Success);
|
||||
this.errorService.success('Role updated');
|
||||
}
|
||||
|
||||
this.router.navigate(['/settings/roles']);
|
||||
|
|
|
@ -6,12 +6,12 @@ import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
|||
import { ERole } from 'picsur-shared/dist/entities/role.entity';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { UIFriendlyPermissions } from 'src/app/i18n/permissions.i18n';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { RolesService } from 'src/app/services/api/roles.service';
|
||||
import { StaticInfoService } from 'src/app/services/api/static-info.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { BootstrapService } from 'src/app/util/util-module/bootstrap.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { BootstrapService } from 'src/app/util/bootstrap.service';
|
||||
import { DialogService } from 'src/app/util/dialog-manager/dialog.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './settings-roles.component.html',
|
||||
|
@ -37,10 +37,11 @@ export class SettingsRolesComponent implements OnInit, AfterViewInit {
|
|||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
|
||||
constructor(
|
||||
private readonly utilService: UtilService,
|
||||
private readonly rolesService: RolesService,
|
||||
private readonly staticInfo: StaticInfoService,
|
||||
private readonly router: Router,
|
||||
private readonly errorService: ErrorService,
|
||||
private readonly dialogService: DialogService,
|
||||
// Public because used in template
|
||||
public readonly bootstrapService: BootstrapService,
|
||||
) {}
|
||||
|
@ -62,7 +63,7 @@ export class SettingsRolesComponent implements OnInit, AfterViewInit {
|
|||
}
|
||||
|
||||
async deleteRole(role: ERole) {
|
||||
const pressedButton = await this.utilService.showDialog({
|
||||
const pressedButton = await this.dialogService.showDialog({
|
||||
title: `Are you sure you want to delete ${role.name}?`,
|
||||
description: 'This action cannot be undone.',
|
||||
buttons: [
|
||||
|
@ -81,12 +82,9 @@ export class SettingsRolesComponent implements OnInit, AfterViewInit {
|
|||
if (pressedButton === 'delete') {
|
||||
const result = await this.rolesService.deleteRole(role.name);
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to delete role',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.errorService.showFailure(result, this.logger);
|
||||
} else {
|
||||
this.utilService.showSnackBar('Role deleted', SnackBarType.Success);
|
||||
this.errorService.success('Role deleted');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,10 +111,8 @@ export class SettingsRolesComponent implements OnInit, AfterViewInit {
|
|||
this.UndeletableRolesList = specialRoles.UndeletableRoles;
|
||||
this.ImmutableRolesList = specialRoles.ImmutableRoles;
|
||||
|
||||
if (HasFailed(roles)) {
|
||||
this.utilService.showSnackBar('Failed to load roles', SnackBarType.Error);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(roles))
|
||||
return this.errorService.showFailure(roles, this.logger);
|
||||
this.dataSource.data = roles;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import { MatPaginatorModule } from '@angular/material/paginator';
|
|||
import { MatTableModule } from '@angular/material/table';
|
||||
import { FabModule } from 'src/app/components/fab/fab.module';
|
||||
import { ValuesPickerModule } from 'src/app/components/values-picker/values-picker.module';
|
||||
import { DialogManagerModule } from 'src/app/util/dialog-manager/dialog-manager.module';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { SettingsRolesEditComponent } from './settings-roles-edit/settings-roles-edit.component';
|
||||
import { SettingsRolesComponent } from './settings-roles.component';
|
||||
import { SettingsRolesRoutingModule } from './settings-roles.routing.module';
|
||||
|
@ -18,6 +20,9 @@ import { SettingsRolesRoutingModule } from './settings-roles.routing.module';
|
|||
declarations: [SettingsRolesComponent, SettingsRolesEditComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
DialogManagerModule,
|
||||
|
||||
SettingsRolesRoutingModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
|
|
|
@ -6,12 +6,11 @@ import { EApiKey } from 'picsur-shared/dist/entities/apikey.entity';
|
|||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { scan } from 'rxjs/operators';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { ApiKeysService } from 'src/app/services/api/apikeys.service';
|
||||
import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { SimpleUtilService } from 'src/app/util/util-module/simple-util.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { UtilService } from 'src/app/util/util.service';
|
||||
import { BuildShareX } from './sharex-builder';
|
||||
|
||||
@Component({
|
||||
|
@ -41,13 +40,13 @@ export class SettingsShareXComponent implements OnInit {
|
|||
|
||||
constructor(
|
||||
private readonly apikeysService: ApiKeysService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly simpleUtil: SimpleUtilService,
|
||||
private readonly permissionService: PermissionService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.formatOptions = this.simpleUtil.getBaseFormatOptions();
|
||||
this.formatOptions = this.utilService.getBaseFormatOptions();
|
||||
this.getNextBatch();
|
||||
}
|
||||
|
||||
|
@ -67,22 +66,19 @@ export class SettingsShareXComponent implements OnInit {
|
|||
}
|
||||
|
||||
const sharexConfig = BuildShareX(
|
||||
this.simpleUtil.getHost(),
|
||||
this.utilService.getHost(),
|
||||
this.key,
|
||||
'.' + ext,
|
||||
canUseDelete,
|
||||
);
|
||||
|
||||
this.simpleUtil.downloadBuffer(
|
||||
this.utilService.downloadBuffer(
|
||||
JSON.stringify(sharexConfig),
|
||||
'Pisur-ShareX-target.sxcu',
|
||||
'application/json',
|
||||
);
|
||||
|
||||
this.utilService.showSnackBar(
|
||||
'Exported ShareX config',
|
||||
SnackBarType.Success,
|
||||
);
|
||||
this.errorService.success('Exported ShareX config');
|
||||
}
|
||||
|
||||
async getNextBatch() {
|
||||
|
@ -90,10 +86,7 @@ export class SettingsShareXComponent implements OnInit {
|
|||
50,
|
||||
Math.floor(this.loaded / 50),
|
||||
);
|
||||
if (HasFailed(newApiKeys)) {
|
||||
this.utilService.showSnackBar(newApiKeys.getReason(), SnackBarType.Error);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(newApiKeys)) return this.errorService.showFailure(newApiKeys, this.logger);
|
||||
this.loaded += newApiKeys.results.length;
|
||||
this.available = newApiKeys.total;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import { MatInputModule } from '@angular/material/input';
|
|||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSelectInfiniteScrollModule } from 'ng-mat-select-infinite-scroll';
|
||||
import { UtilModule } from 'src/app/util/util-module/util.module';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { SettingsShareXComponent } from './settings-sharex.component';
|
||||
import { SettingsShareXRoutingModule } from './settings-sharex.routing.module';
|
||||
|
||||
|
@ -13,13 +13,14 @@ import { SettingsShareXRoutingModule } from './settings-sharex.routing.module';
|
|||
declarations: [SettingsShareXComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
|
||||
SettingsShareXRoutingModule,
|
||||
MatSelectModule,
|
||||
MatSelectInfiniteScrollModule,
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
MatProgressSpinnerModule,
|
||||
UtilModule,
|
||||
],
|
||||
})
|
||||
export class SettingsShareXRouteModule {}
|
||||
|
|
|
@ -4,13 +4,12 @@ import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
|||
import { ERole } from 'picsur-shared/dist/entities/role.entity';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { UIFriendlyPermissions } from 'src/app/i18n/permissions.i18n';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { UpdateUserControl } from 'src/app/models/forms/update-user.control';
|
||||
import { RolesService } from 'src/app/services/api/roles.service';
|
||||
import { StaticInfoService } from 'src/app/services/api/static-info.service';
|
||||
import { UserAdminService } from 'src/app/services/api/user-manage.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
|
||||
enum EditMode {
|
||||
edit = 'edit',
|
||||
|
@ -46,9 +45,9 @@ export class SettingsUsersEditComponent implements OnInit {
|
|||
private readonly route: ActivatedRoute,
|
||||
private readonly router: Router,
|
||||
private readonly userManageService: UserAdminService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly rolesService: RolesService,
|
||||
private readonly staticInfo: StaticInfoService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -80,10 +79,8 @@ export class SettingsUsersEditComponent implements OnInit {
|
|||
|
||||
// Fetch more data
|
||||
const user = await this.userManageService.getUser(uuid);
|
||||
if (HasFailed(user)) {
|
||||
this.utilService.showSnackBar('Failed to get user', SnackBarType.Error);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(user))
|
||||
return this.errorService.showFailure(user, this.logger);
|
||||
|
||||
// Set that data instead
|
||||
this.model.putUsername(user.username);
|
||||
|
@ -97,10 +94,8 @@ export class SettingsUsersEditComponent implements OnInit {
|
|||
|
||||
private async initRoles() {
|
||||
const roles = await this.rolesService.getRoles();
|
||||
if (HasFailed(roles)) {
|
||||
this.utilService.showSnackBar('Failed to get roles', SnackBarType.Error);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(roles))
|
||||
return this.errorService.showFailure(roles, this.logger);
|
||||
|
||||
this.allFullRoles = roles;
|
||||
}
|
||||
|
@ -131,29 +126,19 @@ export class SettingsUsersEditComponent implements OnInit {
|
|||
if (this.adding) {
|
||||
const data = this.model.getDataCreate();
|
||||
const resultUser = await this.userManageService.createUser(data);
|
||||
if (HasFailed(resultUser)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to create user',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(resultUser))
|
||||
return this.errorService.showFailure(resultUser, this.logger);
|
||||
|
||||
this.utilService.showSnackBar('User created', SnackBarType.Success);
|
||||
this.errorService.success('User created');
|
||||
} else {
|
||||
const data = this.model.getDataUpdate();
|
||||
if (!data.password) delete data.password;
|
||||
|
||||
const resultUser = await this.userManageService.updateUser(data);
|
||||
if (HasFailed(resultUser)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to update user',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(resultUser))
|
||||
return this.errorService.showFailure(resultUser, this.logger);
|
||||
|
||||
this.utilService.showSnackBar('User updated', SnackBarType.Success);
|
||||
this.errorService.success('User updated');
|
||||
}
|
||||
|
||||
this.router.navigate(['/settings/users']);
|
||||
|
|
|
@ -5,13 +5,13 @@ import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
|||
import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { StaticInfoService } from 'src/app/services/api/static-info.service';
|
||||
import { UserAdminService } from 'src/app/services/api/user-manage.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { BootstrapService } from 'src/app/util/bootstrap.service';
|
||||
import { DialogService } from 'src/app/util/dialog-manager/dialog.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { Throttle } from 'src/app/util/throttle';
|
||||
import { BootstrapService } from 'src/app/util/util-module/bootstrap.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './settings-users.component.html',
|
||||
|
@ -34,10 +34,11 @@ export class SettingsUsersComponent implements OnInit {
|
|||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
|
||||
constructor(
|
||||
private readonly utilService: UtilService,
|
||||
private readonly userManageService: UserAdminService,
|
||||
private readonly staticInfo: StaticInfoService,
|
||||
private readonly router: Router,
|
||||
private readonly errorService: ErrorService,
|
||||
private readonly dialogService: DialogService,
|
||||
// Public because used in template
|
||||
public readonly bootstrapService: BootstrapService,
|
||||
) {}
|
||||
|
@ -60,7 +61,7 @@ export class SettingsUsersComponent implements OnInit {
|
|||
}
|
||||
|
||||
public async deleteUser(user: EUser) {
|
||||
const pressedButton = await this.utilService.showDialog({
|
||||
const pressedButton = await this.dialogService.showDialog({
|
||||
title: `Are you sure you want to delete ${user.username}?`,
|
||||
description: 'This action cannot be undone.',
|
||||
buttons: [
|
||||
|
@ -79,12 +80,9 @@ export class SettingsUsersComponent implements OnInit {
|
|||
if (pressedButton === 'delete') {
|
||||
const result = await this.userManageService.deleteUser(user.id ?? '');
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to delete user',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.errorService.showFailure(result, this.logger);
|
||||
} else {
|
||||
this.utilService.showSnackBar('User deleted', SnackBarType.Success);
|
||||
this.errorService.success('User deleted');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,10 +120,7 @@ export class SettingsUsersComponent implements OnInit {
|
|||
): Promise<boolean> {
|
||||
const response = await this.userManageService.getUsers(pageSize, pageIndex);
|
||||
if (HasFailed(response)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to fetch users',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.errorService.showFailure(response, this.logger);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ import { MatPaginatorModule } from '@angular/material/paginator';
|
|||
import { MatTableModule } from '@angular/material/table';
|
||||
import { FabModule } from 'src/app/components/fab/fab.module';
|
||||
import { ValuesPickerModule } from 'src/app/components/values-picker/values-picker.module';
|
||||
import { DialogManagerModule } from 'src/app/util/dialog-manager/dialog-manager.module';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { SettingsUsersEditComponent } from './settings-users-edit/settings-users-edit.component';
|
||||
import { SettingsUsersComponent } from './settings-users.component';
|
||||
import { SettingsUsersRoutingModule } from './settings-users.routing.module';
|
||||
|
@ -18,6 +20,9 @@ import { SettingsUsersRoutingModule } from './settings-users.routing.module';
|
|||
declarations: [SettingsUsersComponent, SettingsUsersEditComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
DialogManagerModule,
|
||||
|
||||
SettingsUsersRoutingModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
|
|
|
@ -3,10 +3,11 @@ import { Router } from '@angular/router';
|
|||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { NgxDropzoneChangeEvent } from 'ngx-dropzone';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import { Fail, FT } from 'picsur-shared/dist/types';
|
||||
import { debounceTime } from 'rxjs';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { ProcessingViewMeta } from '../../models/dto/processing-view-meta.dto';
|
||||
|
||||
@Component({
|
||||
|
@ -14,12 +15,14 @@ import { ProcessingViewMeta } from '../../models/dto/processing-view-meta.dto';
|
|||
styleUrls: ['./upload.component.scss'],
|
||||
})
|
||||
export class UploadComponent implements OnInit {
|
||||
private readonly logger = new Logger(UploadComponent.name);
|
||||
|
||||
canUpload = true;
|
||||
|
||||
constructor(
|
||||
private readonly utilService: UtilService,
|
||||
private readonly permissionService: PermissionService,
|
||||
private readonly router: Router,
|
||||
private readonly permissionService: PermissionService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -36,11 +39,10 @@ export class UploadComponent implements OnInit {
|
|||
}
|
||||
|
||||
onSelect(event: NgxDropzoneChangeEvent) {
|
||||
if (event.addedFiles.length > 1) {
|
||||
this.utilService.showSnackBar(
|
||||
if (event.addedFiles.length > 1)
|
||||
this.errorService.log(
|
||||
'You uploaded multiple images, only one has been uploaded',
|
||||
);
|
||||
}
|
||||
|
||||
const metadata: ProcessingViewMeta = {
|
||||
imageFile: event.addedFiles[0],
|
||||
|
@ -51,36 +53,28 @@ export class UploadComponent implements OnInit {
|
|||
@HostListener('document:paste', ['$event'])
|
||||
onPaste(event: ClipboardEvent) {
|
||||
const items = event.clipboardData?.items;
|
||||
if (!items) {
|
||||
this.utilService.showSnackBar('Your clipboard is empty');
|
||||
return;
|
||||
}
|
||||
if (!items) return this.errorService.info('Your clipboard is empty');
|
||||
|
||||
const filteredItems = Array.from(items).filter(
|
||||
(item) => item.kind === 'file',
|
||||
);
|
||||
|
||||
if (filteredItems.length === 0) {
|
||||
this.utilService.showSnackBar(
|
||||
if (filteredItems.length === 0)
|
||||
return this.errorService.info(
|
||||
'Your clipboard does not contain any images',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = filteredItems[0].getAsFile();
|
||||
if (!blob) {
|
||||
this.utilService.showSnackBar(
|
||||
'Error getting image from clipboard',
|
||||
SnackBarType.Error,
|
||||
if (!blob)
|
||||
return this.errorService.showFailure(
|
||||
Fail(FT.Internal, 'Error getting image from clipboard'),
|
||||
this.logger,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (filteredItems.length > 1) {
|
||||
this.utilService.showSnackBar(
|
||||
if (filteredItems.length > 1)
|
||||
this.errorService.log(
|
||||
'You pasted multiple images, only one has been uploaded',
|
||||
);
|
||||
}
|
||||
|
||||
const metadata: ProcessingViewMeta = {
|
||||
imageFile: blob,
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgxDropzoneModule } from 'ngx-dropzone';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { UploadComponent } from './upload.component';
|
||||
import { UploadRoutingModule } from './upload.routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [UploadComponent],
|
||||
imports: [CommonModule, UploadRoutingModule, NgxDropzoneModule],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
UploadRoutingModule,
|
||||
NgxDropzoneModule,
|
||||
],
|
||||
})
|
||||
export class UploadRouteModule {}
|
||||
|
|
|
@ -3,12 +3,11 @@ import { Router } from '@angular/router';
|
|||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { UserPassModel } from 'src/app/models/forms-dto/userpass.dto';
|
||||
import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
import { UserService } from 'src/app/services/api/user.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { LoginControl } from '../../../models/forms/login.control';
|
||||
|
||||
@Component({
|
||||
|
@ -27,7 +26,7 @@ export class LoginComponent implements OnInit {
|
|||
private readonly userService: UserService,
|
||||
private readonly permissionService: PermissionService,
|
||||
private readonly router: Router,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -57,16 +56,10 @@ export class LoginComponent implements OnInit {
|
|||
const user = await this.userService.login(data.username, data.password);
|
||||
this.loading = false;
|
||||
|
||||
if (HasFailed(user)) {
|
||||
this.logger.error(user.getReason());
|
||||
this.utilService.showSnackBar(
|
||||
'Login failed, please try again',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (HasFailed(user))
|
||||
return this.errorService.showFailure(user, this.logger);
|
||||
|
||||
this.utilService.showSnackBar('Login successful', SnackBarType.Success);
|
||||
this.errorService.success('Login successful');
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,11 @@ import { Router } from '@angular/router';
|
|||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { UserPassModel } from 'src/app/models/forms-dto/userpass.dto';
|
||||
import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
import { UserService } from 'src/app/services/api/user.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { RegisterControl } from '../../../models/forms/register.control';
|
||||
|
||||
@Component({
|
||||
|
@ -27,7 +26,7 @@ export class RegisterComponent implements OnInit {
|
|||
private readonly userService: UserService,
|
||||
private readonly permissionService: PermissionService,
|
||||
private readonly router: Router,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -58,12 +57,7 @@ export class RegisterComponent implements OnInit {
|
|||
if (HasFailed(user)) {
|
||||
this.loading = false;
|
||||
|
||||
this.logger.error(user.getReason());
|
||||
this.utilService.showSnackBar(
|
||||
'Register failed, please try again',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
return;
|
||||
return this.errorService.showFailure(user, this.logger);
|
||||
}
|
||||
|
||||
if (!this.userService.isLoggedIn) {
|
||||
|
@ -72,22 +66,14 @@ export class RegisterComponent implements OnInit {
|
|||
data.password,
|
||||
);
|
||||
if (HasFailed(loginResult)) {
|
||||
this.logger.error(loginResult.getReason());
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to login after register',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.loading = false;
|
||||
|
||||
return this.errorService.showFailure(loginResult, this.logger);
|
||||
}
|
||||
|
||||
this.utilService.showSnackBar(
|
||||
'Register successful',
|
||||
SnackBarType.Success,
|
||||
);
|
||||
this.errorService.success('Register successful');
|
||||
} else {
|
||||
this.utilService.showSnackBar(
|
||||
'Register successful, did not log in',
|
||||
SnackBarType.Success,
|
||||
);
|
||||
this.errorService.success('Register successful, did not log in');
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
|
|
|
@ -4,6 +4,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { RegisterComponent } from './register/register.component';
|
||||
import { UserRoutingModule } from './user.routing.module';
|
||||
|
@ -12,6 +13,8 @@ import { UserRoutingModule } from './user.routing.module';
|
|||
declarations: [LoginComponent, RegisterComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
|
||||
UserRoutingModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
|
|
|
@ -4,7 +4,8 @@ import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
|||
import { ImageLinks } from 'picsur-shared/dist/dto/image-links.class';
|
||||
import {
|
||||
AnimFileType,
|
||||
FileType, ImageFileType,
|
||||
FileType,
|
||||
ImageFileType,
|
||||
SupportedFileTypeCategory
|
||||
} from 'picsur-shared/dist/dto/mimes.dto';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
|
@ -14,12 +15,15 @@ import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
|||
import { HasFailed, HasSuccess } from 'picsur-shared/dist/types';
|
||||
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
|
||||
import { ParseFileType } from 'picsur-shared/dist/util/parse-mime';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { ImageService } from 'src/app/services/api/image.service';
|
||||
import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
import { UserService } from 'src/app/services/api/user.service';
|
||||
import { SimpleUtilService } from 'src/app/util/util-module/simple-util.service';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { DialogService } from 'src/app/util/dialog-manager/dialog.service';
|
||||
import { DownloadService } from 'src/app/util/download-manager/download.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { UtilService } from 'src/app/util/util.service';
|
||||
|
||||
import {
|
||||
CustomizeDialogComponent,
|
||||
CustomizeDialogData
|
||||
|
@ -30,14 +34,19 @@ import {
|
|||
styleUrls: ['./view.component.scss'],
|
||||
})
|
||||
export class ViewComponent implements OnInit {
|
||||
private readonly logger = new Logger(ViewComponent.name);
|
||||
|
||||
constructor(
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly router: Router,
|
||||
private readonly imageService: ImageService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly simpleUtil: SimpleUtilService,
|
||||
private readonly permissionService: PermissionService,
|
||||
private readonly userService: UserService,
|
||||
|
||||
private readonly errorService: ErrorService,
|
||||
private readonly downloadService: DownloadService,
|
||||
private readonly dialogService: DialogService,
|
||||
private readonly utilService: UtilService,
|
||||
) {}
|
||||
|
||||
private id: string;
|
||||
|
@ -71,13 +80,13 @@ export class ViewComponent implements OnInit {
|
|||
|
||||
this.id = params.get('id') ?? '';
|
||||
if (!UUIDRegex.test(this.id)) {
|
||||
return this.utilService.quitError('Invalid image link');
|
||||
return this.errorService.quitError('Invalid image link', this.logger);
|
||||
}
|
||||
|
||||
// Get metadata
|
||||
const metadata = await this.imageService.GetImageMeta(this.id);
|
||||
if (HasFailed(metadata))
|
||||
return this.utilService.quitError(metadata.getReason());
|
||||
return this.errorService.quitFailure(metadata, this.logger);
|
||||
|
||||
// Get width of screen in pixels
|
||||
const width = window.innerWidth * window.devicePixelRatio;
|
||||
|
@ -126,11 +135,11 @@ export class ViewComponent implements OnInit {
|
|||
}
|
||||
|
||||
download() {
|
||||
this.utilService.downloadFile(this.imageLinks.source);
|
||||
this.downloadService.downloadFile(this.imageLinks.source);
|
||||
}
|
||||
|
||||
share() {
|
||||
this.utilService.shareFile(this.imageLinks.source);
|
||||
this.downloadService.shareFile(this.imageLinks.source);
|
||||
}
|
||||
|
||||
goBackHome() {
|
||||
|
@ -138,7 +147,7 @@ export class ViewComponent implements OnInit {
|
|||
}
|
||||
|
||||
async deleteImage() {
|
||||
const pressedButton = await this.utilService.showDialog({
|
||||
const pressedButton = await this.dialogService.showDialog({
|
||||
title: `Are you sure you want to delete the image?`,
|
||||
description: 'This action cannot be undone.',
|
||||
buttons: [
|
||||
|
@ -156,14 +165,10 @@ export class ViewComponent implements OnInit {
|
|||
|
||||
if (pressedButton === 'delete') {
|
||||
const result = await this.imageService.DeleteImage(this.id);
|
||||
if (HasFailed(result)) {
|
||||
return this.utilService.showSnackBar(
|
||||
'Failed to delete image',
|
||||
SnackBarType.Error,
|
||||
);
|
||||
}
|
||||
if (HasFailed(result))
|
||||
return this.errorService.showFailure(result, this.logger);
|
||||
|
||||
this.utilService.showSnackBar('Image deleted', SnackBarType.Success);
|
||||
this.errorService.success('Image deleted');
|
||||
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
@ -173,16 +178,20 @@ export class ViewComponent implements OnInit {
|
|||
const options: CustomizeDialogData = {
|
||||
imageID: this.id,
|
||||
selectedFormat: this.currentSelectedFormat,
|
||||
formatOptions: this.simpleUtil.getBaseFormatOptions(),
|
||||
formatOptions: this.utilService.getBaseFormatOptions(),
|
||||
};
|
||||
|
||||
if (options.selectedFormat === 'original') {
|
||||
options.selectedFormat = this.masterFileType.identifier;
|
||||
}
|
||||
|
||||
await this.utilService.showCustomDialog(CustomizeDialogComponent, options, {
|
||||
dismissable: false,
|
||||
});
|
||||
await this.dialogService.showCustomDialog(
|
||||
CustomizeDialogComponent,
|
||||
options,
|
||||
{
|
||||
dismissable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@AutoUnsubscribe()
|
||||
|
@ -224,7 +233,7 @@ export class ViewComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
newOptions = newOptions.concat(this.simpleUtil.getBaseFormatOptions());
|
||||
newOptions = newOptions.concat(this.utilService.getBaseFormatOptions());
|
||||
|
||||
this.formatOptions = newOptions;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { DialogModule } from '@angular/cdk/dialog';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
@ -13,6 +14,8 @@ import { CopyFieldModule } from 'src/app/components/copy-field/copy-field.module
|
|||
import { FabModule } from 'src/app/components/fab/fab.module';
|
||||
import { PicsurImgModule } from 'src/app/components/picsur-img/picsur-img.module';
|
||||
import { PipesModule } from 'src/app/pipes/pipes.module';
|
||||
import { DownloadManagerModule } from 'src/app/util/download-manager/dialog-manager.module';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { CustomizeDialogComponent } from './customize-dialog/customize-dialog.component';
|
||||
import { ViewComponent } from './view.component';
|
||||
import { ViewRoutingModule } from './view.routing.module';
|
||||
|
@ -20,6 +23,10 @@ import { ViewRoutingModule } from './view.routing.module';
|
|||
declarations: [ViewComponent, CustomizeDialogComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
DownloadManagerModule,
|
||||
DialogModule,
|
||||
|
||||
CopyFieldModule,
|
||||
ViewRoutingModule,
|
||||
MatButtonModule,
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
HasSuccess,
|
||||
Open
|
||||
} from 'picsur-shared/dist/types/failable';
|
||||
import { SimpleUtilService } from 'src/app/util/util-module/simple-util.service';
|
||||
import { UtilService } from 'src/app/util/util.service';
|
||||
import { ImageUploadRequest } from '../../models/dto/image-upload-request.dto';
|
||||
import { ApiService } from './api.service';
|
||||
import { UserService } from './user.service';
|
||||
|
@ -32,8 +32,7 @@ import { UserService } from './user.service';
|
|||
export class ImageService {
|
||||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly simpleUtil: SimpleUtilService,
|
||||
|
||||
private readonly util: UtilService,
|
||||
private readonly userService: UserService,
|
||||
) {}
|
||||
|
||||
|
@ -110,7 +109,7 @@ export class ImageService {
|
|||
// Non api calls
|
||||
|
||||
public GetImageURL(image: string, filetype: string | null): string {
|
||||
const baseURL = this.simpleUtil.getHost();
|
||||
const baseURL = this.util.getHost();
|
||||
const extension = FileType2Ext(filetype ?? '');
|
||||
|
||||
return `${baseURL}/i/${image}${
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import { Inject, Injectable } from '@angular/core';
|
||||
import { HISTORY } from '@ng-web-apis/common';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { InfoResponse } from 'picsur-shared/dist/dto/api/info.dto';
|
||||
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { SemVerRegex } from 'picsur-shared/dist/util/common-regex';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import pkg from '../../../../package.json';
|
||||
import { ServerInfo } from '../../models/dto/server-info.dto';
|
||||
import { Logger } from '../logger/logger.service';
|
||||
|
@ -23,13 +20,7 @@ export class InfoService {
|
|||
|
||||
private infoSubject = new BehaviorSubject<ServerInfo>(new ServerInfo());
|
||||
|
||||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly utilService: UtilService,
|
||||
@Inject(HISTORY) private readonly history: History,
|
||||
) {
|
||||
this.checkCompatibility().catch(this.logger.error);
|
||||
}
|
||||
constructor(private readonly api: ApiService) {}
|
||||
|
||||
public async pollInfo(): AsyncFailable<ServerInfo> {
|
||||
const response = await this.api.get(InfoResponse, '/api/info');
|
||||
|
@ -72,46 +63,4 @@ export class InfoService {
|
|||
return serverDecoded[0] === clientDecoded[0];
|
||||
}
|
||||
}
|
||||
|
||||
private async checkCompatibility() {
|
||||
const isCompatible = await this.isCompatibleWithServer();
|
||||
|
||||
if (HasFailed(isCompatible)) {
|
||||
this.utilService.showSnackBar(
|
||||
'There was an error checking compatibility',
|
||||
SnackBarType.Warning,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCompatible) {
|
||||
this.utilService
|
||||
.showDialog({
|
||||
title: 'Server is not compatible',
|
||||
description:
|
||||
'The server is not compatible with this version of the client. You can ignore this, but expect things to not work.',
|
||||
buttons: [
|
||||
{
|
||||
text: 'Back',
|
||||
name: 'back',
|
||||
color: 'accent',
|
||||
},
|
||||
{
|
||||
text: 'Ignore',
|
||||
name: 'ignore',
|
||||
color: 'warn',
|
||||
},
|
||||
],
|
||||
})
|
||||
.then((button) => {
|
||||
if (button === 'ignore') {
|
||||
this.logger.warn('Ignoring server compatibility');
|
||||
} else {
|
||||
this.checkCompatibility();
|
||||
// Go to previous page
|
||||
this.history.back();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,16 @@ import {
|
|||
DecodedPref,
|
||||
PrefValueType
|
||||
} from 'picsur-shared/dist/dto/preferences.dto';
|
||||
import { AsyncFailable, Fail, FT, HasFailed, Map } from 'picsur-shared/dist/types';
|
||||
import {
|
||||
AsyncFailable,
|
||||
Fail,
|
||||
FT,
|
||||
HasFailed,
|
||||
Map
|
||||
} from 'picsur-shared/dist/types';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { Throttle } from 'src/app/util/throttle';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { Logger } from '../logger/logger.service';
|
||||
import { ApiService } from './api.service';
|
||||
import { PermissionService } from './permission.service';
|
||||
|
@ -41,7 +46,7 @@ export class SysPrefService {
|
|||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly permissionsService: PermissionService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {
|
||||
this.subscribePermissions();
|
||||
}
|
||||
|
@ -49,10 +54,7 @@ export class SysPrefService {
|
|||
private async refresh() {
|
||||
const result = await this.getPreferences();
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
"Couldn't load system preferences",
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.errorService.showFailure(result, this.logger);
|
||||
this.flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,8 @@ import {
|
|||
Map
|
||||
} from 'picsur-shared/dist/types';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
import { Throttle } from 'src/app/util/throttle';
|
||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||
import { Logger } from '../logger/logger.service';
|
||||
import { ApiService } from './api.service';
|
||||
import { PermissionService } from './permission.service';
|
||||
|
@ -47,7 +46,7 @@ export class UsrPrefService {
|
|||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly permissionsService: PermissionService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {
|
||||
this.subscribePermissions();
|
||||
}
|
||||
|
@ -55,10 +54,7 @@ export class UsrPrefService {
|
|||
private async refresh() {
|
||||
const result = await this.getPreferences();
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
"Couldn't load user preferences",
|
||||
SnackBarType.Error,
|
||||
);
|
||||
this.errorService.showFailure(result, this.logger);
|
||||
this.flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SnackBarManagerModule } from '../snackbar-manager/snackbar-manager.module';
|
||||
import { ApiErrorService } from './api-error.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, SnackBarManagerModule.forRoot()],
|
||||
providers: [ApiErrorService],
|
||||
})
|
||||
export class ApiErrorManagerModule {
|
||||
// Start apiErrorService, the nothing function does nothing, but it silents the error.
|
||||
constructor(apiErrorService: ApiErrorService) {
|
||||
apiErrorService.nothing();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
|||
import { SnackBarType } from '../../models/dto/snack-bar-type.dto';
|
||||
import { ApiService } from '../../services/api/api.service';
|
||||
import { Logger } from '../../services/logger/logger.service';
|
||||
import { UtilService } from './util.service';
|
||||
import { SnackBarService } from '../snackbar-manager/snackbar.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
@ -13,7 +13,7 @@ export class ApiErrorService {
|
|||
|
||||
constructor(
|
||||
private readonly apiSerivce: ApiService,
|
||||
private readonly utilService: UtilService,
|
||||
private readonly snackbarService: SnackBarService,
|
||||
) {
|
||||
this.subscribeErrors();
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export class ApiErrorService {
|
|||
else url = error.url.url;
|
||||
|
||||
if (url.startsWith('/api')) {
|
||||
this.utilService.showSnackBar('Network Error', SnackBarType.Error);
|
||||
this.snackbarService.showSnackBar('Network Error', SnackBarType.Error);
|
||||
}
|
||||
|
||||
this.logger.error(error.error);
|
|
@ -11,6 +11,7 @@ export enum BSScreenSize {
|
|||
lg = 3,
|
||||
xl = 4,
|
||||
xxl = 5,
|
||||
xxxl = 6,
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
|
@ -24,6 +25,7 @@ export class BootstrapService {
|
|||
private lgObservable: Observable<boolean>;
|
||||
private xlObservable: Observable<boolean>;
|
||||
private xxlObservable: Observable<boolean>;
|
||||
private xxxlObservable: Observable<boolean>;
|
||||
|
||||
private screenSizeSubject: BehaviorSubject<BSScreenSize> =
|
||||
new BehaviorSubject<BSScreenSize>(BSScreenSize.xs);
|
||||
|
@ -34,6 +36,7 @@ export class BootstrapService {
|
|||
this.lgObservable = this.createObserver('(min-width: 992px)');
|
||||
this.xlObservable = this.createObserver('(min-width: 1200px)');
|
||||
this.xxlObservable = this.createObserver('(min-width: 1400px)');
|
||||
this.xxxlObservable = this.createObserver('(min-width: 1600px)');
|
||||
|
||||
this.subscribeObservables();
|
||||
}
|
||||
|
@ -52,8 +55,11 @@ export class BootstrapService {
|
|||
this.lgObservable,
|
||||
this.xlObservable,
|
||||
this.xxlObservable,
|
||||
]).subscribe(([sm, md, lg, xl, xxl]) => {
|
||||
const size = xxl
|
||||
this.xxxlObservable,
|
||||
]).subscribe(([sm, md, lg, xl, xxl, xxxl]) => {
|
||||
const size = xxxl
|
||||
? BSScreenSize.xxxl
|
||||
: xxl
|
||||
? BSScreenSize.xxl
|
||||
: xl
|
||||
? BSScreenSize.xl
|
|
@ -0,0 +1,15 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { DialogManagerModule } from '../dialog-manager/dialog-manager.module';
|
||||
import { ErrorManagerModule } from '../error-manager/error-manager.module';
|
||||
import { CompatibilityService } from './compatibility.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, DialogManagerModule, ErrorManagerModule],
|
||||
providers: [CompatibilityService],
|
||||
})
|
||||
export class CompatibilityManagerModule {
|
||||
constructor(compatibilityService: CompatibilityService) {
|
||||
compatibilityService.nothing();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
import { Inject, Injectable } from '@angular/core';
|
||||
import { HISTORY } from '@ng-web-apis/common';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { InfoService } from 'src/app/services/api/info.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { DialogService } from '../dialog-manager/dialog.service';
|
||||
import { ErrorService } from '../error-manager/error.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class CompatibilityService {
|
||||
private readonly logger = new Logger(CompatibilityService.name);
|
||||
|
||||
constructor(
|
||||
private readonly infoService: InfoService,
|
||||
private readonly errorService: ErrorService,
|
||||
private readonly dialogService: DialogService,
|
||||
@Inject(HISTORY) private readonly history: History,
|
||||
) {
|
||||
this.checkCompatibility().catch(this.logger.error);
|
||||
}
|
||||
|
||||
nothing() {}
|
||||
|
||||
private async checkCompatibility() {
|
||||
const isCompatible = await this.infoService.isCompatibleWithServer();
|
||||
|
||||
if (HasFailed(isCompatible)) {
|
||||
return this.errorService.showFailure(isCompatible, this.logger);
|
||||
}
|
||||
|
||||
if (!isCompatible) {
|
||||
this.dialogService
|
||||
.showDialog({
|
||||
title: 'Server is not compatible',
|
||||
description:
|
||||
'The server is not compatible with this version of the client. You can ignore this, but expect things to not work.',
|
||||
buttons: [
|
||||
{
|
||||
text: 'Back',
|
||||
name: 'back',
|
||||
color: 'accent',
|
||||
},
|
||||
{
|
||||
text: 'Ignore',
|
||||
name: 'ignore',
|
||||
color: 'warn',
|
||||
},
|
||||
],
|
||||
})
|
||||
.then((button) => {
|
||||
if (button === 'ignore') {
|
||||
this.logger.warn('Ignoring server compatibility');
|
||||
} else {
|
||||
this.checkCompatibility();
|
||||
// Go to previous page
|
||||
this.history.back();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { ConfirmDialogComponent } from './confirm-dialog/confirm-dialog.component';
|
||||
import { DialogService } from './dialog.service';
|
||||
import { DownloadDialogComponent } from './download-dialog/download-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
MatProgressBarModule,
|
||||
],
|
||||
declarations: [ConfirmDialogComponent, DownloadDialogComponent],
|
||||
providers: [DialogService],
|
||||
})
|
||||
export class DialogManagerModule {}
|
|
@ -0,0 +1,45 @@
|
|||
import { ComponentType } from '@angular/cdk/portal';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { ConfirmDialogComponent, ConfirmDialogData } from './confirm-dialog/confirm-dialog.component';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'any',
|
||||
})
|
||||
export class DialogService {
|
||||
private readonly logger = new Logger(DialogService.name);
|
||||
|
||||
constructor(
|
||||
private readonly dialog: MatDialog,
|
||||
) {}
|
||||
|
||||
public async showCustomDialog<T>(
|
||||
component: ComponentType<T>,
|
||||
data: any,
|
||||
options?: {
|
||||
dismissable?: boolean;
|
||||
},
|
||||
): Promise<any | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ref = this.dialog.open(component, {
|
||||
data,
|
||||
panelClass: 'small-dialog-padding',
|
||||
...(options?.dismissable === false
|
||||
? {}
|
||||
: { disableClose: true, closeOnNavigation: false }),
|
||||
maxHeight: '90vh',
|
||||
});
|
||||
const subscription = ref.beforeClosed().subscribe((result) => {
|
||||
subscription.unsubscribe();
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async showDialog(
|
||||
options: ConfirmDialogData,
|
||||
): Promise<string | undefined> {
|
||||
return this.showCustomDialog(ConfirmDialogComponent, options);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { ErrorManagerModule } from '../error-manager/error-manager.module';
|
||||
import { DownloadService } from './download.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, MatDialogModule, ErrorManagerModule],
|
||||
providers: [DownloadService],
|
||||
})
|
||||
export class DownloadManagerModule {}
|
|
@ -0,0 +1,117 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Fail, FT, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { ApiService } from 'src/app/services/api/api.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { DownloadDialogComponent } from '../dialog-manager/download-dialog/download-dialog.component';
|
||||
import { ErrorService } from '../error-manager/error.service';
|
||||
import { UtilService } from '../util.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'any',
|
||||
})
|
||||
export class DownloadService {
|
||||
private readonly logger = new Logger(DownloadService.name);
|
||||
|
||||
constructor(
|
||||
private readonly dialog: MatDialog,
|
||||
private readonly api: ApiService,
|
||||
private readonly util: UtilService,
|
||||
private readonly errorService: ErrorService,
|
||||
) {}
|
||||
|
||||
public showDownloadDialog(filename: string): () => void {
|
||||
const ref = this.dialog.open(DownloadDialogComponent, {
|
||||
data: { name: filename },
|
||||
disableClose: true,
|
||||
closeOnNavigation: false,
|
||||
});
|
||||
|
||||
return () => ref.close();
|
||||
}
|
||||
|
||||
public async downloadFile(url: string) {
|
||||
const closeDialog = this.showDownloadDialog('image');
|
||||
|
||||
const file = await this.api.getBuffer(url);
|
||||
if (HasFailed(file))
|
||||
return this.errorService.showFailure(file, this.logger);
|
||||
|
||||
this.util.downloadBuffer(file.buffer, file.name, file.mimeType);
|
||||
|
||||
closeDialog();
|
||||
|
||||
this.errorService.info('Image downloaded');
|
||||
}
|
||||
|
||||
public canShare(): boolean {
|
||||
if (navigator.canShare === undefined || navigator.share === undefined)
|
||||
return false;
|
||||
|
||||
const testShare = navigator.canShare({
|
||||
url: 'https://www.example.com',
|
||||
});
|
||||
|
||||
return testShare;
|
||||
}
|
||||
|
||||
public canShareFiles(): boolean {
|
||||
if (!this.canShare()) return false;
|
||||
|
||||
const testFile = new File([], 'test.txt');
|
||||
const testShare = navigator.canShare({
|
||||
files: [testFile],
|
||||
});
|
||||
|
||||
return testShare;
|
||||
}
|
||||
|
||||
public async shareFile(url: string) {
|
||||
if (!this.canShare())
|
||||
return this.errorService.warn(
|
||||
'Sharing is not supported on your device',
|
||||
this.logger,
|
||||
);
|
||||
|
||||
let shareObject: ShareData;
|
||||
|
||||
if (!this.canShareFiles()) {
|
||||
shareObject = {
|
||||
url,
|
||||
};
|
||||
} else {
|
||||
const image = await this.api.getBuffer(url);
|
||||
if (HasFailed(image))
|
||||
return this.errorService.showFailure(image, this.logger);
|
||||
|
||||
this.logger.log(image.name, image.mimeType);
|
||||
|
||||
const imageFile = new File([image.buffer], image.name, {
|
||||
type: image.mimeType,
|
||||
});
|
||||
|
||||
shareObject = {
|
||||
files: [imageFile],
|
||||
};
|
||||
}
|
||||
|
||||
const canShare = navigator.canShare(shareObject);
|
||||
if (!canShare)
|
||||
return this.errorService.warn(
|
||||
'Sharing is not supported on your device',
|
||||
this.logger,
|
||||
);
|
||||
|
||||
try {
|
||||
await navigator.share(shareObject);
|
||||
} catch (e) {
|
||||
if (e instanceof DOMException && e.message === 'Share canceled') {
|
||||
} else {
|
||||
this.errorService.showFailure(
|
||||
Fail(FT.Internal, 'Sharing failed!', e),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { SnackBarManagerModule } from '../snackbar-manager/snackbar-manager.module';
|
||||
import { ErrorService } from './error.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, SnackBarManagerModule.forRoot(), RouterModule],
|
||||
providers: [ErrorService],
|
||||
})
|
||||
export class ErrorManagerModule {}
|
|
@ -0,0 +1,66 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Failure } from 'picsur-shared/dist/types';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { SnackBarService } from '../snackbar-manager/snackbar.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'any',
|
||||
})
|
||||
export class ErrorService {
|
||||
constructor(
|
||||
private readonly snackbar: SnackBarService,
|
||||
private readonly router: Router,
|
||||
) {}
|
||||
|
||||
public showFailure(error: Failure, logger: Logger): void {
|
||||
if (error.isImportant()) {
|
||||
logger.error(error.print());
|
||||
} else {
|
||||
logger.warn(error.print());
|
||||
}
|
||||
|
||||
this.snackbar.showSnackBar(
|
||||
error.getReason(),
|
||||
error.isImportant() ? SnackBarType.Error : SnackBarType.Warning,
|
||||
);
|
||||
}
|
||||
|
||||
public quitFailure(error: Failure, logger: Logger): void {
|
||||
this.showFailure(error, logger);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
||||
public warn(warning: string, logger: Logger): void {
|
||||
logger.warn(warning);
|
||||
this.snackbar.showSnackBar(warning, SnackBarType.Warning);
|
||||
}
|
||||
|
||||
public error(error: string, logger: Logger): void {
|
||||
logger.error(error);
|
||||
this.snackbar.showSnackBar(error, SnackBarType.Error);
|
||||
}
|
||||
|
||||
public info(info: string) {
|
||||
this.snackbar.showSnackBar(info, SnackBarType.Info);
|
||||
}
|
||||
|
||||
public success(success: string) {
|
||||
this.snackbar.showSnackBar(success, SnackBarType.Success);
|
||||
}
|
||||
|
||||
public log(log: string) {
|
||||
this.snackbar.showSnackBar(log, SnackBarType.Default);
|
||||
}
|
||||
|
||||
public quitWarn(warning: string, logger: Logger): void {
|
||||
this.warn(warning, logger);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
||||
public quitError(error: string, logger: Logger): void {
|
||||
this.error(error, logger);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import {
|
||||
MatSnackBarModule,
|
||||
MAT_SNACK_BAR_DEFAULT_OPTIONS
|
||||
} from '@angular/material/snack-bar';
|
||||
import { SnackBarService } from './snackbar.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, MatSnackBarModule],
|
||||
providers: [SnackBarService],
|
||||
})
|
||||
export class SnackBarManagerModule {
|
||||
static forRoot(): ModuleWithProviders<SnackBarManagerModule> {
|
||||
return {
|
||||
ngModule: SnackBarManagerModule,
|
||||
providers: [
|
||||
{
|
||||
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
|
||||
useValue: {
|
||||
duration: 4000,
|
||||
horizontalPosition: 'left',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { BootstrapService, BSScreenSize } from '../bootstrap.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'any',
|
||||
})
|
||||
export class SnackBarService {
|
||||
private readonly logger = new Logger(SnackBarService.name);
|
||||
|
||||
constructor(
|
||||
private readonly snackBar: MatSnackBar,
|
||||
private readonly bootstrap: BootstrapService,
|
||||
) {}
|
||||
|
||||
public showSnackBar(
|
||||
message: string,
|
||||
type: SnackBarType = SnackBarType.Default,
|
||||
duration: number | undefined | null = null,
|
||||
) {
|
||||
let ref = this.snackBar.open(message, '', {
|
||||
panelClass: ['mat-toolbar', 'snackbar', type],
|
||||
verticalPosition:
|
||||
this.bootstrap.screenSizeSnapshot() > BSScreenSize.xs
|
||||
? 'bottom'
|
||||
: 'top',
|
||||
...(duration !== null ? { duration } : {}),
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import {
|
||||
MatSnackBarModule,
|
||||
MAT_SNACK_BAR_DEFAULT_OPTIONS
|
||||
} from '@angular/material/snack-bar';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ApiErrorService } from './api-error.service';
|
||||
import { ConfirmDialogComponent } from './confirm-dialog/confirm-dialog.component';
|
||||
import { DownloadDialogComponent } from './download-dialog/download-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatSnackBarModule,
|
||||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
MatProgressBarModule,
|
||||
RouterModule,
|
||||
],
|
||||
declarations: [ConfirmDialogComponent, DownloadDialogComponent],
|
||||
})
|
||||
export class UtilModule {
|
||||
static forRoot(): ModuleWithProviders<UtilModule> {
|
||||
return {
|
||||
ngModule: UtilModule,
|
||||
providers: [
|
||||
{
|
||||
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
|
||||
useValue: {
|
||||
duration: 4000,
|
||||
horizontalPosition: 'left',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// Start apiErrorService, the nothing function does nothing, but it silents the error.
|
||||
constructor(apiErrorService: ApiErrorService) {
|
||||
apiErrorService.nothing();
|
||||
}
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
import { ComponentType } from '@angular/cdk/portal';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Router } from '@angular/router';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { ApiService } from 'src/app/services/api/api.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { SnackBarType } from '../../models/dto/snack-bar-type.dto';
|
||||
import { BootstrapService, BSScreenSize } from './bootstrap.service';
|
||||
import {
|
||||
ConfirmDialogComponent,
|
||||
ConfirmDialogData
|
||||
} from './confirm-dialog/confirm-dialog.component';
|
||||
import { DownloadDialogComponent } from './download-dialog/download-dialog.component';
|
||||
import { SimpleUtilService } from './simple-util.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'any',
|
||||
})
|
||||
export class UtilService {
|
||||
private readonly logger = new Logger(UtilService.name);
|
||||
|
||||
constructor(
|
||||
private readonly simpleUtil: SimpleUtilService,
|
||||
private readonly snackBar: MatSnackBar,
|
||||
private readonly dialog: MatDialog,
|
||||
private readonly router: Router,
|
||||
private readonly api: ApiService,
|
||||
private readonly bootstrap: BootstrapService,
|
||||
) {}
|
||||
|
||||
public quitError(message: string) {
|
||||
this.showSnackBar(message, SnackBarType.Error);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
||||
public showSnackBar(
|
||||
message: string,
|
||||
type: SnackBarType = SnackBarType.Default,
|
||||
duration: number | undefined | null = null,
|
||||
) {
|
||||
let ref = this.snackBar.open(message, '', {
|
||||
panelClass: ['mat-toolbar', 'snackbar', type],
|
||||
verticalPosition:
|
||||
this.bootstrap.screenSizeSnapshot() > BSScreenSize.xs
|
||||
? 'bottom'
|
||||
: 'top',
|
||||
...(duration !== null ? { duration } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
public async showCustomDialog<T>(
|
||||
component: ComponentType<T>,
|
||||
data: any,
|
||||
options?: {
|
||||
dismissable?: boolean;
|
||||
},
|
||||
): Promise<any | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ref = this.dialog.open(component, {
|
||||
data,
|
||||
panelClass: 'small-dialog-padding',
|
||||
...(options?.dismissable === false
|
||||
? {}
|
||||
: { disableClose: true, closeOnNavigation: false }),
|
||||
maxHeight: '90vh',
|
||||
});
|
||||
const subscription = ref.beforeClosed().subscribe((result) => {
|
||||
subscription.unsubscribe();
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async showDialog(
|
||||
options: ConfirmDialogData,
|
||||
): Promise<string | undefined> {
|
||||
return this.showCustomDialog(ConfirmDialogComponent, options);
|
||||
}
|
||||
|
||||
public showDownloadDialog(filename: string): () => void {
|
||||
const ref = this.dialog.open(DownloadDialogComponent, {
|
||||
data: { name: filename },
|
||||
disableClose: true,
|
||||
closeOnNavigation: false,
|
||||
});
|
||||
|
||||
return () => ref.close();
|
||||
}
|
||||
|
||||
public async downloadFile(url: string) {
|
||||
const closeDialog = this.showDownloadDialog('image');
|
||||
|
||||
const file = await this.api.getBuffer(url);
|
||||
if (HasFailed(file)) {
|
||||
closeDialog();
|
||||
this.logger.error(file.getReason());
|
||||
this.showSnackBar('Error while downloading image', SnackBarType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.simpleUtil.downloadBuffer(file.buffer, file.name, file.mimeType);
|
||||
|
||||
closeDialog();
|
||||
this.showSnackBar('Image downloaded', SnackBarType.Info);
|
||||
}
|
||||
|
||||
public canShare(): boolean {
|
||||
if (navigator.canShare === undefined || navigator.share === undefined)
|
||||
return false;
|
||||
|
||||
const testShare = navigator.canShare({
|
||||
url: 'https://www.example.com',
|
||||
});
|
||||
|
||||
return testShare;
|
||||
}
|
||||
|
||||
public canShareFiles(): boolean {
|
||||
if (!this.canShare()) return false;
|
||||
|
||||
const testFile = new File([], 'test.txt');
|
||||
const testShare = navigator.canShare({
|
||||
files: [testFile],
|
||||
});
|
||||
|
||||
return testShare;
|
||||
}
|
||||
|
||||
public async shareFile(url: string) {
|
||||
if (!this.canShare()) {
|
||||
this.showSnackBar(
|
||||
'Sharing is not supported on your device',
|
||||
SnackBarType.Warning,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let shareObject: ShareData;
|
||||
|
||||
if (!this.canShareFiles()) {
|
||||
shareObject = {
|
||||
url,
|
||||
};
|
||||
} else {
|
||||
const image = await this.api.getBuffer(url);
|
||||
if (HasFailed(image)) {
|
||||
this.logger.error(image.getReason());
|
||||
this.showSnackBar('Error while sharing image', SnackBarType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(image.name, image.mimeType);
|
||||
|
||||
const imageFile = new File([image.buffer], image.name, {
|
||||
type: image.mimeType,
|
||||
});
|
||||
|
||||
shareObject = {
|
||||
files: [imageFile],
|
||||
};
|
||||
}
|
||||
|
||||
const canShare = navigator.canShare(shareObject);
|
||||
if (!canShare) {
|
||||
this.showSnackBar(
|
||||
'Sharing is not supported on your device',
|
||||
SnackBarType.Warning,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.share(shareObject);
|
||||
} catch (e) {
|
||||
if (e instanceof DOMException && e.message === 'Share canceled') {
|
||||
} else {
|
||||
this.logger.error(e);
|
||||
this.showSnackBar('Could not share', SnackBarType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
|
@ -2,13 +2,13 @@ import { Inject, Injectable } from '@angular/core';
|
|||
import { LOCATION } from '@ng-web-apis/common';
|
||||
import { FileType2Ext, SupportedFileTypes } from 'picsur-shared/dist/dto/mimes.dto';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { Logger } from '../../services/logger/logger.service';
|
||||
import { Logger } from '../services/logger/logger.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'any',
|
||||
})
|
||||
export class SimpleUtilService {
|
||||
private readonly logger = new Logger(SimpleUtilService.name);
|
||||
export class UtilService {
|
||||
private readonly logger = new Logger(UtilService.name);
|
||||
|
||||
constructor(@Inject(LOCATION) private readonly location: Location) {}
|
||||
|
||||
|
@ -49,4 +49,8 @@ export class SimpleUtilService {
|
|||
|
||||
return newOptions;
|
||||
}
|
||||
|
||||
public async sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue