diff --git a/deploy/saneUrl/index.js b/deploy/saneUrl/index.js index 4bfcf3740c70b47b9f746f9fcda2170c5461643a..2e9ab0b76528b999720781f7ff9cc913891f478d 100644 --- a/deploy/saneUrl/index.js +++ b/deploy/saneUrl/index.js @@ -27,6 +27,8 @@ const passthrough = (_, __, next) => next() const acceptHtmlProg = /text\/html/i +const REAL_HOSTNAME = `${HOSTNAME}${HOST_PATHNAME || ''}/` + router.get('/:name', async (req, res) => { const { name } = req.params const { headers } = req @@ -34,7 +36,6 @@ router.get('/:name', async (req, res) => { const redirectFlag = acceptHtmlProg.test(headers['accept']) try { - const REAL_HOSTNAME = `${HOSTNAME}${HOST_PATHNAME || ''}/` const json = await NotExactlyPromiseAny([ ProxyStore.StaticGet(depStore, req, name), diff --git a/src/atlasComponents/userAnnotations/singleAnnotationUnit/singleAnnotationUnit.component.ts b/src/atlasComponents/userAnnotations/singleAnnotationUnit/singleAnnotationUnit.component.ts index 956f23c080c1929b07fc62159a42024c68334490..8c9a11566b9f7f27350a684cc9ffc3976525c32e 100644 --- a/src/atlasComponents/userAnnotations/singleAnnotationUnit/singleAnnotationUnit.component.ts +++ b/src/atlasComponents/userAnnotations/singleAnnotationUnit/singleAnnotationUnit.component.ts @@ -48,8 +48,8 @@ export class SingleAnnotationUnit implements OnDestroy, AfterViewInit{ this.chSubs.push( this.formGrp.valueChanges.subscribe(value => { const { name, desc, spaceId } = value - this.managedAnnotation.setName(name) - this.managedAnnotation.setDesc(desc) + this.managedAnnotation.name = name + this.managedAnnotation.desc = desc }) ) diff --git a/src/atlasComponents/userAnnotations/tools/line.ts b/src/atlasComponents/userAnnotations/tools/line.ts index 606c155f3e995bbf3bba85d6b82cb4040ae7a76e..bea53cdf42b49e494e9f3419813f4b9178dc3b99 100644 --- a/src/atlasComponents/userAnnotations/tools/line.ts +++ b/src/atlasComponents/userAnnotations/tools/line.ts @@ -45,7 +45,7 @@ export class Line extends IAnnotationGeometry{ }) if (!this.points[0]) this.points[0] = point else this.points[1] = point - this.sendUpdateSignal() + this.changed() return point } @@ -172,11 +172,7 @@ export class Line extends IAnnotationGeometry{ for (const p of this.points){ p.translate(x, y, z) } - this.sendUpdateSignal() - } - - private sendUpdateSignal(){ - this.updateSignal$.next(this.toString()) + this.changed() } } @@ -244,7 +240,7 @@ export class ToolLine extends AbsToolClass<Line> implements IAnnotationTools, On * it only has a single point, and should be removed */ if (this.selectedLine) { - this.removeAnnotation(this.selectedLine.id) + this.removeAnnotation(this.selectedLine) } this.selectedLine = null }), @@ -311,14 +307,4 @@ export class ToolLine extends AbsToolClass<Line> implements IAnnotationTools, On ngOnDestroy(){ this.subs.forEach(s => s.unsubscribe()) } - - removeAnnotation(id: string){ - const idx = this.managedAnnotations.findIndex(ann => ann.id === id) - if (idx < 0) { - return - } - this.managedAnnotations.splice(idx, 1) - this.managedAnnotations$.next(this.managedAnnotations) - } - } diff --git a/src/atlasComponents/userAnnotations/tools/point.ts b/src/atlasComponents/userAnnotations/tools/point.ts index af1543fed9b100ecabda6373bf4055b685c580f7..1db473a6713ed78b82c0d12c4a34acf65f13bb84 100644 --- a/src/atlasComponents/userAnnotations/tools/point.ts +++ b/src/atlasComponents/userAnnotations/tools/point.ts @@ -95,7 +95,7 @@ export class Point extends IAnnotationGeometry { this.x += x this.y += y this.z += z - this.updateSignal$.next(this.toString()) + this.changed() } } @@ -177,20 +177,6 @@ export class ToolPoint extends AbsToolClass<Point> implements IAnnotationTools, ) } - /** - * @description remove managed annotation via id - * @param id id of annotation - */ - removeAnnotation(id: string) { - const idx = this.managedAnnotations.findIndex(ann => id === ann.id) - if (idx < 0){ - throw new Error(`cannot find point idx ${idx}`) - return - } - this.managedAnnotations.splice(idx, 1) - this.managedAnnotations$.next(this.managedAnnotations) - } - onMouseMoveRenderPreview(pos: [number, number, number]) { return [{ id: `${ToolPoint.PREVIEW_ID}_0`, diff --git a/src/atlasComponents/userAnnotations/tools/poly.ts b/src/atlasComponents/userAnnotations/tools/poly.ts index 2cd9285b256119f8ec112825b96fc615a6eea407..b7929b5dfe77e378ae6a52c2f5c67d5333547025 100644 --- a/src/atlasComponents/userAnnotations/tools/poly.ts +++ b/src/atlasComponents/userAnnotations/tools/poly.ts @@ -37,7 +37,7 @@ export class Polygon extends IAnnotationGeometry{ this.edges = this.edges.filter(([ idx1, idx2 ]) => idx1 !== ptIdx && idx2 !== ptIdx) this.points.splice(ptIdx, 1) - this.sendUpdateSignal() + this.changed() } public addPoint(p: Point | {x: number, y: number, z: number}, linkTo?: Point): Point { @@ -56,7 +56,7 @@ export class Polygon extends IAnnotationGeometry{ if (!this.hasPoint(pointToBeAdded)) { this.points.push(pointToBeAdded) const sub = pointToBeAdded.updateSignal$.subscribe( - () => this.sendUpdateSignal() + () => this.changed() ) this.ptWkMp.set(pointToBeAdded, { onremove: () => { @@ -71,7 +71,7 @@ export class Polygon extends IAnnotationGeometry{ ] as [number, number] this.edges.push(newEdge) } - this.sendUpdateSignal() + this.changed() return pointToBeAdded } @@ -209,15 +209,11 @@ export class Polygon extends IAnnotationGeometry{ this.edges = edges } - private sendUpdateSignal(){ - this.updateSignal$.next(this.toString()) - } - public translate(x: number, y: number, z: number) { for (const p of this.points){ p.translate(x, y, z) } - this.sendUpdateSignal() + this.changed() } } @@ -307,7 +303,7 @@ export class ToolPolygon extends AbsToolClass<Polygon> implements IAnnotationToo * if edges < 3, discard poly */ if (edges.length < 3) { - this.removeAnnotation(this.selectedPoly.id) + this.removeAnnotation(this.selectedPoly) } } @@ -404,15 +400,6 @@ export class ToolPolygon extends AbsToolClass<Polygon> implements IAnnotationToo ) } - removeAnnotation(id: string) { - const idx = this.managedAnnotations.findIndex(ann => ann.id === id) - if (idx < 0) { - return - } - this.managedAnnotations.splice(idx, 1) - this.managedAnnotations$.next(this.managedAnnotations) - } - ngOnDestroy(){ if (this.subs.length > 0) this.subs.pop().unsubscribe() } diff --git a/src/atlasComponents/userAnnotations/tools/service.ts b/src/atlasComponents/userAnnotations/tools/service.ts index 8185ed4b6177cb3688ca381c87a4c7a05961ada4..b459ad65f7ae3f64afb99ba5346a14481ffba8f2 100644 --- a/src/atlasComponents/userAnnotations/tools/service.ts +++ b/src/atlasComponents/userAnnotations/tools/service.ts @@ -697,8 +697,8 @@ export class ModularUserAnnotationToolService implements OnDestroy{ // potentially overwriting existing name and desc... // maybe should show warning? - existingAnn.setName(json.name) - existingAnn.setDesc(json.desc) + existingAnn.name = json.name + existingAnn.desc = json.desc return existingAnn } else { const { id, name, desc } = json @@ -708,8 +708,8 @@ export class ModularUserAnnotationToolService implements OnDestroy{ } else { const metadata = this.metadataMap.get(returnObj.id) if (returnObj && metadata) { - returnObj.setName(metadata?.name || null) - returnObj.setDesc(metadata?.desc || null) + returnObj.name = metadata?.name || null + returnObj.desc = metadata?.desc || null this.metadataMap.delete(returnObj.id) } } diff --git a/src/atlasComponents/userAnnotations/tools/type.spec.ts b/src/atlasComponents/userAnnotations/tools/type.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4b28738913465c7eda8ee898f28fdc724dbf016 --- /dev/null +++ b/src/atlasComponents/userAnnotations/tools/type.spec.ts @@ -0,0 +1,166 @@ +import { Subject, Subscription } from "rxjs" +import { AbsToolClass, IAnnotationEvents, IAnnotationGeometry, TAnnotationEvent } from "./type" + +class TmpCls extends IAnnotationGeometry{ + getNgAnnotationIds(){ + return [] + } + toNgAnnotation() { + return [] + } + toJSON() { + return {} + } + toString() { + return '' + } + toSands(){ + return {} as any + } +} + +class TmpToolCls extends AbsToolClass<TmpCls> { + iconClass = '' + name: 'tmplClsTool' + subs = [] + onMouseMoveRenderPreview() { + return [] + } + + protected managedAnnotations: TmpCls[] = [] + public managedAnnotations$ = new Subject<TmpCls[]>() +} + +describe('> types.ts', () => { + describe('> AbsToolClass', () => { + let tool: TmpToolCls + let ann: TmpCls + let managedAnn: jasmine.Spy + const subs: Subscription[] = [] + + beforeEach(() => { + const ev$ = new Subject<TAnnotationEvent<keyof IAnnotationEvents>>() + tool = new TmpToolCls(ev$, () => {}) + ann = new TmpCls() + managedAnn = jasmine.createSpy('managedannspy') + subs.push( + tool.managedAnnotations$.subscribe(managedAnn) + ) + }) + + afterEach(() => { + managedAnn.calls.reset() + while(subs.length) subs.pop().unsubscribe() + }) + + it('> shuld init just fine', () => { + expect(true).toEqual(true) + }) + describe('> managedAnnotations$', () => { + describe('> on point add', () => { + it('> should emit new managedannotations', () => { + tool.addAnnotation(ann) + expect(managedAnn).toHaveBeenCalled() + expect(managedAnn).toHaveBeenCalledTimes(1) + const firstCallArgs = managedAnn.calls.allArgs()[0] + const firstArg = firstCallArgs[0] + expect(firstArg).toEqual([ann]) + }) + }) + describe('> on point update', () => { + it('> should emit new managedannotations', () => { + tool.addAnnotation(ann) + ann.name = 'blabla' + expect(managedAnn).toHaveBeenCalledTimes(2) + const firstCallArgs = managedAnn.calls.allArgs()[0] + const secondCallArgs = managedAnn.calls.allArgs()[1] + expect(firstCallArgs).toEqual(secondCallArgs) + }) + }) + describe('> on point rm', () => { + it('> managed annotation === 0', () => { + tool.addAnnotation(ann) + + const firstCallArgs = managedAnn.calls.allArgs()[0] + const subManagedAnn0 = firstCallArgs[0] + expect(subManagedAnn0.length).toEqual(1) + + ann.remove() + expect(managedAnn).toHaveBeenCalledTimes(2) + + const secondCallArgs = managedAnn.calls.allArgs()[1] + const subManagedAnn1 = secondCallArgs[0] + expect(subManagedAnn1.length).toEqual(0) + }) + it('> does not trigger after rm', () => { + tool.addAnnotation(ann) + ann.remove() + ann.name = 'blabla' + expect(managedAnn).toHaveBeenCalledTimes(2) + }) + }) + }) + }) + + describe('> IAnnotationGeometry', () => { + it('> can be init fine', () => { + new TmpCls() + expect(true).toBe(true) + }) + + describe('> updateSignal$', () => { + class TmpCls extends IAnnotationGeometry{ + getNgAnnotationIds(){ + return [] + } + toNgAnnotation() { + return [] + } + toJSON() { + return {} + } + toString() { + return `${this.name || ''}:${this.desc || ''}` + } + toSands(){ + return {} as any + } + } + + let tmp: TmpCls + let subs: Subscription[] = [] + let updateStub: jasmine.Spy + beforeEach(() => { + tmp = new TmpCls() + updateStub = jasmine.createSpy('updateSpy') + subs.push( + tmp.updateSignal$.subscribe( + val => updateStub(val) + ) + ) + }) + afterEach(() => { + while(subs.length) subs.pop().unsubscribe() + updateStub.calls.reset() + }) + it('> is fired on setting name', () => { + tmp.name = 'test' + expect(updateStub).toHaveBeenCalled() + expect(updateStub).toHaveBeenCalledTimes(1) + }) + + it('> is fired on setting desc', () => { + tmp.desc = 'testdesc' + expect(updateStub).toHaveBeenCalled() + expect(updateStub).toHaveBeenCalledTimes(1) + }) + + it('> should be fired even if same string', () => { + + tmp.name = null + tmp.name = undefined + expect(updateStub).toHaveBeenCalledTimes(2) + }) + }) + }) +}) diff --git a/src/atlasComponents/userAnnotations/tools/type.ts b/src/atlasComponents/userAnnotations/tools/type.ts index e74f0ca8ee389775b93f49836a4f504ab88ccfec..85a4c2e0f6783a024017a34fc0b50588a89ccfcd 100644 --- a/src/atlasComponents/userAnnotations/tools/type.ts +++ b/src/atlasComponents/userAnnotations/tools/type.ts @@ -18,9 +18,8 @@ export abstract class AbsToolClass<T extends IAnnotationGeometry> { public abstract name: string public abstract iconClass: string - public abstract removeAnnotation(id: string): void public abstract managedAnnotations$: Subject<T[]> - protected abstract managedAnnotations: T[] = [] + protected managedAnnotations: T[] = [] abstract subs: Subscription[] protected space: TBaseAnnotationGeomtrySpec['space'] @@ -158,10 +157,26 @@ export abstract class AbsToolClass<T extends IAnnotationGeometry> { public addAnnotation(geom: T) { const found = this.managedAnnotations.find(ann => ann.id === geom.id) if (found) found.remove() - geom.remove = () => this.removeAnnotation(geom.id) + const sub = geom.updateSignal$.subscribe(() => { + this.managedAnnotations$.next(this.managedAnnotations) + }) + geom.remove = () => { + this.removeAnnotation(geom) + sub.unsubscribe() + } this.managedAnnotations.push(geom) this.managedAnnotations$.next(this.managedAnnotations) } + + public removeAnnotation(geom: T) { + const idx = this.managedAnnotations.findIndex(ann => ann.id === geom.id) + if (idx < 0) { + console.warn(`removeAnnotation error: cannot annotation with id: ${geom.id}`) + return + } + this.managedAnnotations.splice(idx, 1) + this.managedAnnotations$.next(this.managedAnnotations) + } } export type TToolType = 'selecting' | 'drawing' | 'deletion' @@ -276,8 +291,25 @@ export abstract class Highlightable { export abstract class IAnnotationGeometry extends Highlightable { public id: string - public name: string - public desc: string + private _name: string + set name(val: string) { + if (val === this._name) return + this._name = val + this.changed() + } + get name(): string { + return this._name + } + + private _desc: string + set desc(val: string) { + if (val === this._desc) return + this._desc = val + this.changed() + } + get desc(): string { + return this._desc + } public space: TBaseAnnotationGeomtrySpec['space'] @@ -290,7 +322,13 @@ export abstract class IAnnotationGeometry extends Highlightable { public remove() { throw new Error(`The remove method needs to be overwritten by the tool manager`) } - public updateSignal$ = new Subject() + + private _updateSignal$ = new Subject() + + public updateSignal$ = this._updateSignal$.asObservable() + protected changed(){ + this._updateSignal$.next(Date.now()) + } constructor(spec?: TBaseAnnotationGeomtrySpec){ super() @@ -299,15 +337,6 @@ export abstract class IAnnotationGeometry extends Highlightable { this.name = spec?.name this.desc = spec?.desc } - - setName(name: string) { - this.name = name - this.updateSignal$.next(this.toString()) - } - setDesc(desc: string) { - this.desc = desc - this.updateSignal$.next(this.toString()) - } } export interface IAnnotationTools {