[#39184] Switching viewer dropdown fails to load (#9763)

* [#39184] Switching viewer dropdown fails to load

- https://community.openproject.org/work_packages/39184
- ifc viewer is now only initialized after view is initialized

* Fix bim nav spec to check for xoekit init

Co-authored-by: Wieland Lindenthal <w.lindenthal@forkmerge.com>
pull/9767/head
Eric Schubert 3 years ago committed by GitHub
parent 2ebe88176e
commit 0ab5b5a164
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      frontend/src/app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.component.html
  2. 78
      frontend/src/app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.component.ts
  3. 6
      modules/bim/spec/features/bim_navigation_spec.rb
  4. 8
      modules/bim/spec/support/pages/ifc_models/show_default.rb

@ -15,12 +15,14 @@
</div>
</div>
<div *ngIf="modelCount"
<div #viewerContainer
*ngIf="modelCount"
class="op-ifc-viewer--container xeokit-busy-modal-backdrop"
data-qa-selector="op-ifc-viewer--container">
<div class="op-ifc-viewer--toolbar op-ifc-viewer--model-canvas-overlay">
<div class="op-ifc-viewer--toolbar-container"
<div #toolbar
class="op-ifc-viewer--toolbar-container"
data-qa-selector="op-ifc-viewer--toolbar-container">
</div>
@ -46,11 +48,13 @@
</a>
</div>
<canvas class="op-ifc-viewer--nav-cube-canvas op-ifc-viewer--model-canvas-overlay"
<canvas #navCubeCanvas
class="op-ifc-viewer--nav-cube-canvas op-ifc-viewer--model-canvas-overlay"
data-qa-selector="op-ifc-viewer--nav-cube-canvas"></canvas>
</div>
<div class="op-ifc-viewer--inspector-container"
<div #inspectorPane
class="op-ifc-viewer--inspector-container"
[class.op-ifc-viewer--inspector-container-hidden]="!(inspectorVisible$ | async)"
data-qa-selector="op-ifc-viewer--inspector-container">
</div>

@ -27,6 +27,7 @@
//++
import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
ElementRef,
@ -40,18 +41,19 @@ import { IfcModelsDataService } from 'core-app/modules/bim/ifc_models/pages/view
import { I18nService } from 'core-app/modules/common/i18n/i18n.service';
import { CurrentUserService } from 'core-app/modules/current-user/current-user.service';
import { CurrentProjectService } from 'core-app/components/projects/current-project.service';
import { BehaviorSubject } from "rxjs";
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
import { take } from "rxjs/operators";
@Component({
selector: 'ifc-viewer',
selector: 'op-ifc-viewer',
templateUrl: './ifc-viewer.component.html',
styleUrls: ['./ifc-viewer.component.sass'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class IFCViewerComponent implements OnInit, OnDestroy {
private viewerUI:any;
export class IFCViewerComponent implements OnInit, OnDestroy, AfterViewInit {
private viewInitialized$ = new Subject();
modelCount:number;
modelCount:number = this.ifcData.models.length;
canManage = this.ifcData.allowed('manage_ifc_models');
@ -63,55 +65,67 @@ export class IFCViewerComponent implements OnInit, OnDestroy {
keyboardEnabled = false;
public inspectorVisible$:BehaviorSubject<boolean>;
inspectorVisible$:BehaviorSubject<boolean> = this.ifcViewerService.inspectorVisible$;
@ViewChild('outerContainer') outerContainer:ElementRef;
@ViewChild('viewerContainer') viewerContainer:ElementRef;
@ViewChild('modelCanvas') modelCanvas:ElementRef;
@ViewChild('navCubeCanvas') navCubeCanvas:ElementRef;
@ViewChild('toolbar') toolbarElement:ElementRef;
@ViewChild('inspectorPane') inspectorElement:ElementRef;
constructor(private I18n:I18nService,
private elementRef:ElementRef,
public ifcData:IfcModelsDataService,
private ifcViewerService:IFCViewerService,
private currentUserService:CurrentUserService,
private currentProjectService:CurrentProjectService) {
this.inspectorVisible$ = this.ifcViewerService.inspectorVisible$;
}
ngOnInit():void {
this.modelCount = this.ifcData.models.length;
if (this.modelCount === 0) {
return;
}
const element = jQuery(this.elementRef.nativeElement as HTMLElement);
this.currentUserService
.hasCapabilities$(
[
'ifc_models/create',
'ifc_models/update',
'ifc_models/destroy',
],
this.currentProjectService.id as string,
)
.subscribe((manageIfcModelsAllowed) => {
// we have to wait until view is initialized before constructing the ifc viewer,
// as it needs all view children ready and rendered
combineLatest(
this.currentUserService
.hasCapabilities$(
[
'ifc_models/create',
'ifc_models/update',
'ifc_models/destroy',
],
this.currentProjectService.id as string,
),
this.viewInitialized$,
)
.pipe(take(1))
.subscribe(([manageIfcModelsAllowed]) => {
this.ifcViewerService.newViewer(
{
canvasElement: this.modelCanvas.nativeElement, // WebGL canvas
explorerElement: jQuery('.op-ifc-viewer--tree-panel')[0], // Left panel
toolbarElement: element.find('[data-qa-selector="op-ifc-viewer--toolbar-container"]')[0], // Toolbar
inspectorElement: element.find('[data-qa-selector="op-ifc-viewer--inspector-container"]')[0], // Toolbar
navCubeCanvasElement: element.find('[data-qa-selector="op-ifc-viewer--nav-cube-canvas"]')[0],
busyModelBackdropElement: element.find('.xeokit-busy-modal-backdrop')[0],
canvasElement: this.modelCanvas.nativeElement as HTMLElement,
explorerElement: document.getElementsByClassName('op-ifc-viewer--tree-panel')[0] as HTMLElement, // Left panel
toolbarElement: this.toolbarElement.nativeElement as HTMLElement,
inspectorElement: this.inspectorElement.nativeElement as HTMLElement,
navCubeCanvasElement: this.navCubeCanvas.nativeElement as HTMLElement,
busyModelBackdropElement: this.viewerContainer.nativeElement as HTMLElement,
keyboardEventsElement: this.modelCanvas.nativeElement as HTMLElement,
enableEditModels: manageIfcModelsAllowed,
keyboardEventsElement: this.modelCanvas.nativeElement, // WebGL canvas
},
this.ifcData.projects,
);
});
}
ngAfterViewInit():void {
this.viewInitialized$.next();
}
ngOnDestroy():void {
@ -127,12 +141,12 @@ export class IFCViewerComponent implements OnInit, OnDestroy {
@HostListener('keydown', ['$event'])
@HostListener('keyup', ['$event'])
@HostListener('keypress', ['$event'])
cancelAllKeyEvents($event:KeyboardEvent) {
cancelAllKeyEvents($event:KeyboardEvent):void {
$event.stopPropagation();
}
@HostListener('mousedown')
enableKeyBoard() {
enableKeyBoard():void {
if (this.modelCount) {
this.keyboardEnabled = true;
this.ifcViewerService.setKeyboardEnabled(true);
@ -140,14 +154,14 @@ export class IFCViewerComponent implements OnInit, OnDestroy {
}
@HostListener('window:mousedown', ['$event.target'])
disableKeyboard(target:Element) {
disableKeyboard(target:Element):void {
if (this.modelCount && !this.outerContainer.nativeElement?.contains(target)) {
this.keyboardEnabled = false;
this.ifcViewerService.setKeyboardEnabled(false);
}
}
enableFromIcon(event:MouseEvent) {
enableFromIcon(event:MouseEvent):boolean {
this.enableKeyBoard();
// Focus on the canvas

@ -78,7 +78,7 @@ describe 'BIM navigation spec',
model_page.page_shows_a_toolbar true
model_tree.sidebar_shows_viewer_menu true
expect(page).to have_selector('.wp-cards-container')
card_view.expect_work_package_listed work_package
card_view.expect_work_package_listed(work_package)
end
it 'can switch between the different view modes' do
@ -100,7 +100,7 @@ describe 'BIM navigation spec',
details_view.go_back
details_view.expect_closed
card_view.expect_work_package_listed work_package
card_view.expect_work_package_listed(work_package)
# Go to viewer only
model_page.switch_view 'Viewer'
@ -113,7 +113,7 @@ describe 'BIM navigation spec',
model_page.model_viewer_visible false
expect(page).to have_selector('.wp-cards-container')
card_view.expect_work_package_listed work_package
card_view.expect_work_package_listed(work_package)
# Go to single view
card_view.open_full_screen_by_details(work_package)

@ -54,8 +54,12 @@ module Pages
end
def model_viewer_visible(visible)
selector = '.op-ifc-viewer--model-canvas'
expect(page).to (visible ? have_selector(selector, wait: 10) : have_no_selector(selector, wait: 10))
# Ensure the canvas is present
canvas_selector = '.op-ifc-viewer--model-canvas'
expect(page).to (visible ? have_selector(canvas_selector, wait: 10) : have_no_selector(canvas_selector, wait: 10))
# Ensure Xeokit is initialized. Only then the toolbar is generated.
toolbar_selector = '.xeokit-toolbar'
expect(page).to (visible ? have_selector(toolbar_selector, wait: 10) : have_no_selector(toolbar_selector, wait: 10))
end
def model_viewer_shows_a_toolbar(visible)

Loading…
Cancel
Save