Skip to content
Snippets Groups Projects
Commit 34053909 authored by Xiao Gui's avatar Xiao Gui
Browse files

feat: added no. ann badge

feat: delete all ann btn
feat: loading ann feedback
parent 2033d7aa
No related branches found
No related tags found
No related merge requests found
......@@ -70,7 +70,8 @@
USER_ANNOTATION_HIDE: 'user annotations hide',
USER_ANNOTATION_DELETE: 'Delete annotation',
GOTO_ANNOTATION_ROI: 'Navigate to annotation location of interest',
EXIT_ANNOTATION_MODE: 'Exit annotation mode'
EXIT_ANNOTATION_MODE: 'Exit annotation mode',
BULK_DELETE_ANNOTATIONS: 'Delete all user annotations'
}
exports.IDS = {
......@@ -79,6 +80,8 @@
}
exports.CONST = {
LOADING_TXT: `Loading ...`,
CANNOT_DECIPHER_HEMISPHERE: 'Cannot decipher region hemisphere.',
DOES_NOT_SUPPORT_MULTI_REGION_SELECTION: `Please only select a single region.`,
MULTI_REGION_SELECTION: `Multi region selection`,
......@@ -103,6 +106,9 @@
QUICKTOUR_OK: `Start`,
QUICKTOUR_NEXTTIME: `Not now`,
QUICKTOUR_CANCEL: `Dismiss`,
DELETE_ALL_ANNOTATION_CONFIRMATION_MSG: `Are you sure you want to delete all annotations?`,
LOADING_ANNOTATION_MSG: `Loading annotations... Please wait...`
}
exports.QUICKTOUR_DESC ={
......
# v2.4.8
## Enhancements
- Added badges to annotation tab button to show number of annotations added (#1007)
- Added some feedbacks when annotations are being loaded
- Added delete all annotation button
## Bugfixes
## Under the hood stuff
......
import {Component, ViewChild} from "@angular/core";
import {ARIA_LABELS} from "common/constants";
import { Component, Optional, ViewChild } from "@angular/core";
import { ARIA_LABELS, CONST } from "common/constants";
import { ModularUserAnnotationToolService } from "../tools/service";
import { IAnnotationGeometry, TExportFormats } from "../tools/type";
import { ComponentStore } from "src/viewerModule/componentStore";
import { map, shareReplay, startWith } from "rxjs/operators";
import { Observable } from "rxjs";
import { Observable, Subscription } from "rxjs";
import { TZipFileConfig } from "src/zipFilesOutput/type";
import { TFileInputEvent } from "src/getFileInput/type";
import { FileInputDirective } from "src/getFileInput/getFileInput.directive";
import { MatSnackBar } from "@angular/material/snack-bar";
import { unzip } from "src/zipFilesOutput/zipFilesOutput.directive";
import { DialogService } from "src/services/dialogService.service";
const README = `{id}.sands.json file contains the data of annotations. {id}.desc.json contains the metadata of annotations.`
......@@ -26,12 +27,17 @@ export class AnnotationList {
public ARIA_LABELS = ARIA_LABELS
@ViewChild(FileInputDirective)
fileInput: FileInputDirective
private subs: Subscription[] = []
private managedAnnotations: IAnnotationGeometry[] = []
public managedAnnotations$ = this.annotSvc.spaceFilteredManagedAnnotations$
public badge$ = this.managedAnnotations$.pipe(
map(mann => mann.length > 0 ? mann.length : null)
)
public manAnnExists$ = this.managedAnnotations$.pipe(
map(arr => !!arr && arr.length > 0),
startWith(false)
......@@ -64,10 +70,15 @@ export class AnnotationList {
private annotSvc: ModularUserAnnotationToolService,
private snackbar: MatSnackBar,
cStore: ComponentStore<{ useFormat: TExportFormats }>,
@Optional() private dialogSvc: DialogService,
) {
cStore.setState({
useFormat: 'sands'
})
this.subs.push(
this.managedAnnotations$.subscribe(anns => this.managedAnnotations = anns)
)
}
public hiddenAnnotations$ = this.annotSvc.hiddenAnnotations$
......@@ -82,6 +93,11 @@ export class AnnotationList {
}
async handleImportEvent(ev: TFileInputEvent<'text' | 'file'>){
const { abort } = this.dialogSvc.blockUserInteraction({
title: CONST.LOADING_TXT,
markdown: CONST.LOADING_ANNOTATION_MSG,
})
try {
const clearFileInputAndInform = () => {
if (this.fileInput) {
......@@ -135,6 +151,31 @@ export class AnnotationList {
this.snackbar.open(`Error importing: ${e.toString()}`, 'Dismiss', {
duration: 3000
})
} finally {
abort()
}
}
async deleteAllAnnotation(){
if (this.dialogSvc) {
try {
await this.dialogSvc.getUserConfirm({
markdown: CONST.DELETE_ALL_ANNOTATION_CONFIRMATION_MSG
})
for (const ann of this.managedAnnotations) {
ann.remove()
}
} catch (e) {
// aborted
}
} else {
if (window.confirm(CONST.DELETE_ALL_ANNOTATION_CONFIRMATION_MSG)) {
for (const ann of this.managedAnnotations) {
ann.remove()
}
}
}
}
}
......@@ -33,6 +33,15 @@
[disabled]="!(manAnnExists$ | async)">
<i class="fas fa-download"></i>
</button>
<!-- delete all annotations -->
<button mat-icon-button
color="warn"
(click)="deleteAllAnnotation()"
[matTooltip]="ARIA_LABELS.BULK_DELETE_ANNOTATIONS"
[disabled]="!(manAnnExists$ | async)">
<i class="fas fa-trash"></i>
</button>
</mat-card-subtitle>
</div>
......
......@@ -25,12 +25,15 @@ export class ConfirmDialogComponent {
@Input()
public markdown: string
public hideActionBar = false
constructor(@Inject(MAT_DIALOG_DATA) data: any) {
const { title = null, message = null, markdown, okBtnText, cancelBtnText} = data || {}
const { title = null, message = null, markdown, okBtnText, cancelBtnText, hideActionBar} = data || {}
if (title) this.title = title
if (message) this.message = message
if (markdown) this.markdown = markdown
if (okBtnText) this.okBtnText = okBtnText
if (cancelBtnText) this.cancelBtnText = cancelBtnText
if (hideActionBar) this.hideActionBar = hideActionBar
}
}
......@@ -17,7 +17,7 @@
<mat-divider></mat-divider>
<mat-dialog-actions class="justify-content-start flex-row-reverse">
<mat-dialog-actions *ngIf="!hideActionBar" class="justify-content-start flex-row-reverse">
<button [mat-dialog-close]="true" mat-raised-button color="primary">{{ okBtnText }}</button>
<button [mat-dialog-close]="false" mat-button>{{ cancelBtnText }}</button>
</mat-dialog-actions>
......@@ -3,6 +3,10 @@ import { ConfirmDialogComponent } from "src/components/confirmDialog/confirmDial
import { DialogComponent } from "src/components/dialog/dialog.component";
import {MatDialog, MatDialogRef} from "@angular/material/dialog";
type TCancellable = {
abort: () => void
}
@Injectable({
providedIn: 'root',
})
......@@ -16,13 +20,26 @@ export class DialogService {
}
public blockUserInteraction(config: Partial<DialogConfig>): TCancellable {
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
data: {
...config,
hideActionBar: true
},
hasBackdrop: true,
disableClose: true
})
const abort = () => dialogRef.close()
return { abort }
}
public getUserConfirm(config: Partial<DialogConfig> = {}): Promise<string> {
this.confirmDialogRef = this.dialog.open(ConfirmDialogComponent, {
data: config,
})
return new Promise((resolve, reject) => this.confirmDialogRef.afterClosed()
.subscribe(val => {
if (val) { resolve() } else { reject('User cancelled') }
if (val) { resolve('') } else { reject('User cancelled') }
},
reject,
() => this.confirmDialogRef = null))
......
......@@ -16,7 +16,7 @@
[autoFocus]="false"
[disableClose]="true"
class="p-0 pe-all col-10 col-sm-10 col-md-5 col-lg-4 col-xl-3 col-xxl-2">
<annotation-list></annotation-list>
<annotation-list #annListCmp="annotationListCmp"></annotation-list>
</mat-drawer>
<mat-drawer-content class="visible position-relative pe-none">
......@@ -30,7 +30,8 @@
matColor: 'primary',
fontIcon: 'fa-list',
tooltip: 'Annotation list',
click: annotationDrawer.toggle.bind(annotationDrawer)
click: annotationDrawer.toggle.bind(annotationDrawer),
badge: annListCmp?.badge$ | async
}">
</ng-container>
</div>
......@@ -58,7 +59,6 @@
</mat-drawer-content>
</mat-drawer-container>
<!-- <annotation-message></annotation-message> -->
</div>
<!-- top drawer -->
......@@ -390,6 +390,8 @@
let-customColor="customColor"
let-customColorDarkmode="customColorDarkmode"
let-tooltip="tooltip"
let-badge="badge"
let-badgeColor="badgeColor"
let-click="click">
<!-- (click)="sideNavMasterSwitch.toggle()" -->
<button mat-raised-button
......@@ -402,7 +404,9 @@
}"
(click)="click && click()"
[style.backgroundColor]="customColor"
[color]="(!customColor && matColor) ? matColor : null">
[color]="(!customColor && matColor) ? matColor : null"
[matBadge]="badge"
[matBadgeColor]="badgeColor || 'warn'">
<span [ngClass]="{'iv-custom-comp text': !!customColor}">
<i class="fas" [ngClass]="fontIcon || 'fa-question'"></i>
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment