Skip to content
Permalink
Browse files
feat(error): add file representation error message (DEV-791) (#729)
* fix(resource): show progress indicator until whole resource is loaded (DEV-638)

* refactor(message): delete message component

* refactor(error): update error message

* refactor(error): update error message

* refactor(admin): use app-error instead of app-message

* chore(gh): merge wrong created branch into correct one  (#728)

* test(error): add tests

* test(user): update tests

* test(user): update tests

* test(user): fix user form test

* feat(representation): error in case of missing still-image file

* feat(representation): new service to check if file exists

* style(error): refactor style

* feat(representation): possibility to disable av-timeline

* feat(representation): error handler document

* feat(representation): error handler still-image

* feat(representation): error handler moving-image

* refactor(representation): make lint happy

* style(representation): correct position of error message

* style(still-image): update osd header design

* style(still-image): update osd header design

* test(representation): fix tests

* chore(representation): prepare still-image error handler

* style(status): resolve style issues

* fix(resource): resolve issue with loading res

* feat(error): error message in representation handler

* feat(representation): check if file exists

* refactor(representation): display error handler in still-image

* refactor: clean up code

* style(status): resolve status position

* refactor(representation): display error handler in still-image

* fix(representation): check if whole still image exists

* style(representation): resolve responsive style issue

* refactor: add space between if and bracket

* refactor(representation): remove brackets
  • Loading branch information
kilchenmann committed May 18, 2022
1 parent ceebf7b commit 462771e9b5916cb0233b34f72dd19fcea32b24db
Show file tree
Hide file tree
Showing 28 changed files with 285 additions and 79 deletions.
@@ -45,7 +45,7 @@ export class DatadogRumService {
}

setActiveUser(identifier: any, identifierType: 'iri' | 'email' | 'username'): void {
if(datadogRum.getInternalContext().application_id) {
if (datadogRum.getInternalContext().application_id) {
datadogRum.setUser({
id: identifier,
identifierType: identifierType
@@ -54,7 +54,7 @@ export class DatadogRumService {
}

removeActiveUser(): void {
if(datadogRum.getInternalContext().application_id) {
if (datadogRum.getInternalContext().application_id) {
datadogRum.removeUser();
}
}
@@ -1,5 +1,4 @@
<div class="status-page">

<div class="status-page" [class.representation-error]="representation">
<div class="container" *ngIf="!refresh; else isLoading">
<div class="image">
<img class="error-image" [src]="'/assets/images/' + message?.image" />
@@ -20,13 +19,11 @@ <h2 class="mat-title">{{message.type | uppercase}} {{status}} | {{message?.messa
<p *ngSwitchCase="'reload'">
Please come back in a few minutes and try to <a (click)="reload()">reload the page</a>.
</p>
<p *ngSwitchCase="'goto'" [innerHtml]="url | appLinkify"></p>
<p *ngSwitchCase="'goto'" class="goto" [innerHtml]="url | appLinkify"></p>
</div>

</div>
</div>
<ng-template #isLoading>
<app-progress-indicator></app-progress-indicator>
</ng-template>

</div>
@@ -1,27 +1,29 @@
@import "../../../assets/style/responsive";
@import "../../../assets/style/config";

.status-page {
background: #fff;
height: 100%;
width: 100%;
z-index: 999;

.container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
align-items: stretch;
align-content: space-evenly;
padding-top: 120px;
width: 480px;
padding-top: 16px;
max-width: 480px;
margin: 0 auto;

.image,
.text {
justify-self: stretch;
align-self: stretch;
box-sizing: border-box;
max-height: 280px;
width: 360px;
min-height: 280px;
max-width: 360px;

&.status-message {
line-height: 1.5;
@@ -35,10 +37,24 @@
}
}
}

&.representation-error {
background: none;

.image {
display: none !important;
}
}
}

.action {
margin-top: 72px;
width: 360px;

p {
width: 100%;
word-wrap: break-word;
word-break: break-word;
}
}

// mobile device: phone
@@ -25,10 +25,10 @@ export class StatusComponent implements OnInit {

@Input() comment?: string;
@Input() url?: string;
@Input() representation?: 'archive' | 'audio' | 'document' | 'still-image' | 'video';

refresh = false;


// error message that will be shown in template
message: StatusMsg;

@@ -92,6 +92,7 @@ export class StatusComponent implements OnInit {
) { }

ngOnInit() {

// status is not defined in Input parameter
if (!this.status) {
// but status is defined in app.routing
@@ -100,12 +101,17 @@ export class StatusComponent implements OnInit {
});
}

// set the page title
this._titleService.setTitle('DSP | Error ' + this.status);

// get error message by status
this.message = this.getMsgByStatus(this.status);

if (this.representation) {
this.comment = `There was an error loading the ${this.representation} file representation. Try to open it directly by clicking on the file url below:`;
this.message.action = 'goto';
} else {
// set the page title only in case of main error
this._titleService.setTitle(`DSP | ${this.getTypeByStatus(this.status).toUpperCase()} ${this.status}`);
}

}

getMsgByStatus(status: number): StatusMsg {
@@ -311,7 +311,7 @@ export class ResourceClassFormComponent implements OnInit, AfterViewChecked {
this.lastModificationDate = classLabelResponse.lastModificationDate;
onto4Comment.lastModificationDate = this.lastModificationDate;

if(updateComment.comments.length) { // if the comments array is not empty, send a request to update the comments
if (updateComment.comments.length) { // if the comments array is not empty, send a request to update the comments
this._dspApiConnection.v2.onto.updateResourceClass(onto4Comment).subscribe(
(classCommentResponse: ResourceClassDefinitionWithAllLanguages) => {
this.lastModificationDate = classCommentResponse.lastModificationDate;
@@ -1,5 +1,8 @@
<div *ngIf="src && src.fileValue.fileUrl">
<button class="download" mat-button (click)="downloadArchive(src.fileValue.fileUrl)">
<!-- in case of an error -->
<app-status [status]="404" [url]="src.fileValue.fileUrl" [representation]="'audio'" *ngIf="failedToLoad"></app-status>

<button class="download" mat-button (click)="downloadArchive(src.fileValue.fileUrl)" [disabled]="failedToLoad">
<mat-icon>
file_download
</mat-icon>
@@ -18,6 +18,7 @@ import { DialogComponent } from 'src/app/main/dialog/dialog.component';
import { ErrorHandlerService } from 'src/app/main/services/error-handler.service';
import { EmitEvent, Events, UpdatedFileEventValue, ValueOperationEventService } from '../../services/value-operation-event.service';
import { FileRepresentation } from '../file-representation';
import { RepresentationService } from '../representation.service';

@Component({
selector: 'app-archive',
@@ -34,16 +35,20 @@ export class ArchiveComponent implements OnInit, AfterViewInit {

originalFilename: string;

failedToLoad = false;

constructor(
@Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection,
private readonly _http: HttpClient,
private _dialog: MatDialog,
private _errorHandler: ErrorHandlerService,
private _rs: RepresentationService,
private _valueOperationEventService: ValueOperationEventService
) { }

ngOnInit(): void {
this._getOriginalFilename();
this.failedToLoad = !this._rs.doesFileExist(this.src.fileValue.fileUrl);
}

ngAfterViewInit() {
@@ -1,6 +1,9 @@
<div class="controls">
<!-- in case of an error -->
<app-status [status]="404" [url]="src.fileValue.fileUrl" [representation]="'audio'" *ngIf="failedToLoad"></app-status>

<div class="audio-player">
<audio id="audio" controls preload="auto">
<audio id="audio" [controls]="!failedToLoad" preload="auto">
<source [src]="audio" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
@@ -18,6 +18,7 @@ import { DialogComponent } from 'src/app/main/dialog/dialog.component';
import { ErrorHandlerService } from 'src/app/main/services/error-handler.service';
import { EmitEvent, Events, UpdatedFileEventValue, ValueOperationEventService } from '../../services/value-operation-event.service';
import { FileRepresentation } from '../file-representation';
import { RepresentationService } from '../representation.service';


@Component({
@@ -33,18 +34,22 @@ export class AudioComponent implements OnInit, AfterViewInit {

@Output() loaded = new EventEmitter<boolean>();

failedToLoad = false;

audio: SafeUrl;

constructor(
@Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection,
private _sanitizer: DomSanitizer,
private _dialog: MatDialog,
private _errorHandler: ErrorHandlerService,
private _rs: RepresentationService,
private _valueOperationEventService: ValueOperationEventService
) { }

ngOnInit(): void {
this.audio = this._sanitizer.bypassSecurityTrustUrl(this.src.fileValue.fileUrl);
this.failedToLoad = !this._rs.doesFileExist(this.src.fileValue.fileUrl);
}

ngAfterViewInit() {
@@ -1,10 +1,16 @@
<div class="timeline-wrapper" #timeline>
<div class="timeline-wrapper" #timeline [class.disabled]="disabled">
<div class="progress-wrapper" #progress>
<div class="progress-background"></div>
<div class="progress-buffer"></div>
<div class="progress-fill"></div>
</div>
<div class="thumb" [class.dragging]="dragging" #thumb cdkDragLockAxis="x" cdkDrag
(cdkDragStarted)="toggleDragging()" (cdkDragEnded)="toggleDragging()" (cdkDragMoved)="dragAction($event)"
cdkDragBoundary=".timeline-wrapper"> </div>
<div class="thumb" #thumb cdkDrag
cdkDragLockAxis="x"
[class.dragging]="dragging"
[cdkDragDisabled]="disabled"
(cdkDragStarted)="toggleDragging()"
(cdkDragEnded)="toggleDragging()"
(cdkDragMoved)="dragAction($event)"
cdkDragBoundary=".timeline-wrapper">
</div>
</div>
@@ -60,4 +60,15 @@
border: 3px solid red;
}
}

&.disabled {
cursor: no-drop;
.progress-background,
.progress-fill,
.thumb {
background-color: grey !important;
cursor: no-drop;
}
}

}
@@ -37,6 +37,9 @@ export class AvTimelineComponent implements OnChanges {
// in case parent resized: Will be used in video player when switching between cinema and default view
@Input() resized: boolean;

// disable in case of missing file
@Input() disabled: boolean;

// send click position to parent
@Output() changed = new EventEmitter<number>();

@@ -184,17 +187,18 @@ export class AvTimelineComponent implements OnChanges {
* @param ev
*/
private _onMouseup(ev: MouseEvent) {
if (!this.disabled) {
const pos: number = (ev.clientX - this.timelineDimension.left);

const pos: number = (ev.clientX - this.timelineDimension.left);

this.updatePosition(pos);
this.updatePosition(pos);

const percentage: number = (pos / this.timelineDimension.width);
const percentage: number = (pos / this.timelineDimension.width);

// calc time value to submit to parent
const time: number = (percentage * this.max);
// calc time value to submit to parent
const time: number = (percentage * this.max);

this.changed.emit(time);
this.changed.emit(time);
}
}

/**
@@ -10,6 +10,7 @@
class="pdf-searchbox"
placeholder="Search in pdf..."
[value]="pdfQuery"
[disabled]="failedToLoad"
(input)="searchQueryChanged($event.target.value)"
(keyup.enter)="searchQueryChanged(queryInp.value)"
/>
@@ -18,13 +19,13 @@
<!-- image action tools e.g. zoom, rotate and flip -->
<span>
<!-- zoom buttons -->
<button mat-icon-button id="DSP_PDF_ZOOM_OUT" matTooltip="Zoom out" (click)="zoomFactor = zoomFactor - 0.2">
<button mat-icon-button id="DSP_PDF_ZOOM_OUT" matTooltip="Zoom out" (click)="zoomFactor = zoomFactor - 0.2" [disabled]="failedToLoad">
<mat-icon>remove_circle_outline</mat-icon>
</button>
<button mat-icon-button id="DSP_PDF_HOME" matTooltip="Reset zoom" (click)="zoomFactor = 1.0">
<button mat-icon-button id="DSP_PDF_HOME" matTooltip="Reset zoom" (click)="zoomFactor = 1.0" [disabled]="failedToLoad">
<mat-icon>adjust</mat-icon>
</button>
<button mat-icon-button id="DSP_PDF_ZOOM_IN" matTooltip="Zoom in" (click)="zoomFactor = zoomFactor + 0.2">
<button mat-icon-button id="DSP_PDF_ZOOM_IN" matTooltip="Zoom in" (click)="zoomFactor = zoomFactor + 0.2" [disabled]="failedToLoad">
<mat-icon>add_circle_outline</mat-icon>
</button>
<button mat-icon-button id="DSP_PDF_REPLACE_FILE" class="replace-file" matTooltip="Replace PDF file" (click)="openReplaceFileDialog()">
@@ -35,6 +36,8 @@
</a>
</span>
</div>
<!-- in case of an error -->
<app-status [status]="404" [url]="src.fileValue.fileUrl" [representation]="'document'" *ngIf="failedToLoad"></app-status>

<pdf-viewer [src]="src.fileValue.fileUrl" [original-size]="false" [autoresize]="true" [show-all]="true"
[show-borders]="true" [zoom]="zoomFactor" [zoom-scale]="'page-width'">
@@ -9,6 +9,19 @@ $osd-height: 460px;
:host {
border: 1px solid $black;

@media (max-height: 636px) {
height: 364px;
}

.mat-button-disabled {
color: $grey !important;
}

app-status {
margin-top: 64px;
display: inline-block;
}

.pdf-container {
color: $bright;
height: 100%;
@@ -18,6 +18,7 @@ import { DialogComponent } from 'src/app/main/dialog/dialog.component';
import { ErrorHandlerService } from 'src/app/main/services/error-handler.service';
import { EmitEvent, Events, UpdatedFileEventValue, ValueOperationEventService } from '../../services/value-operation-event.service';
import { FileRepresentation } from '../file-representation';
import { RepresentationService } from '../representation.service';

@Component({
selector: 'app-document',
@@ -38,15 +39,18 @@ export class DocumentComponent implements OnInit, AfterViewInit {

pdfQuery = '';

failedToLoad = false;

constructor(
@Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection,
private _dialog: MatDialog,
private _errorHandler: ErrorHandlerService,
private _rs: RepresentationService,
private _valueOperationEventService: ValueOperationEventService
) { }

ngOnInit(): void {

this.failedToLoad = !this._rs.doesFileExist(this.src.fileValue.fileUrl);
}

ngAfterViewInit() {

0 comments on commit 462771e

Please sign in to comment.