Update IFC Viewer with latest Xeokit updates (#9207)

* Bump @xeokit/xeokit-gltf-to-xkt to version 1.0.0

* Bump Xeokit SDK and Xeokit BIM Viewer

* Overwrite XEOKIT orthogonal/perspective toggle icon

* Add styles for section tool and its menu

* Remove SAO deactivation for non default models.

Performance of SAO has improved ever since Xeokit's FastNavPlugin was created.

* bump xeokit sdk and bim viewer

* IFC viewer toolbar adoption for section plane tool.

* Fix spec after xeokit bump

* Feature 33880 Add Edit/Delete/Add model buttons in Models tab

* Paths to xeokit's bim viewer code changed

* Bumping xeokit packages

* Fix default_spec.rb for scopes
pull/9208/head
Wieland Lindenthal 4 years ago committed by GitHub
parent 6156d4b837
commit 33443c154e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      docker/prod/setup/preinstall-common.sh
  2. 204
      frontend/npm-shrinkwrap.json
  3. 4
      frontend/package.json
  4. 38
      frontend/src/app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.component.ts
  5. 42
      frontend/src/app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.service.ts
  6. 5
      frontend/src/app/modules/bim/ifc_models/pages/viewer/styles/tabs.sass
  7. 50
      frontend/src/app/modules/bim/ifc_models/pages/viewer/styles/toolbar.sass
  8. 2
      frontend/src/app/modules/bim/ifc_models/xeokit/xeokit.d.ts
  9. 12
      frontend/src/app/modules/common/path-helper/path-helper.service.ts
  10. 3
      modules/bim/app/helpers/ifc_models_helper.rb
  11. 2
      modules/bim/bin/setup_dev.sh
  12. 16
      modules/bim/lib/open_project/bim/engine.rb
  13. 24
      modules/bim/spec/features/model_viewer_spec.rb
  14. 15
      modules/bim/spec/support/components/xeokit_model_tree.rb
  15. 7
      modules/bim/spec/support/pages/ifc_models/show_default.rb
  16. 16
      spec/models/capabilities/scopes/default_spec.rb
  17. 4
      spec/requests/api/v3/action_resource_spec.rb

@ -33,7 +33,7 @@ tmpdir=$(mktemp -d)
cd $tmpdir
# Install XKT converter
npm install @xeokit/xeokit-gltf-to-xkt@0.0.3 -g
npm install @xeokit/xeokit-gltf-to-xkt@1.0.0 -g
# Install COLLADA2GLTF
wget --quiet https://github.com/KhronosGroup/COLLADA2GLTF/releases/download/v2.1.5/COLLADA2GLTF-v2.1.5-linux.zip

@ -49,8 +49,8 @@
"@uirouter/core": "^6.0.7",
"@uirouter/rx": "^0.6.5",
"@w11k/ngx-componentdestroyed": "^5.0.2",
"@xeokit/xeokit-bim-viewer": "^1.8.6",
"@xeokit/xeokit-sdk": "^1.3.91",
"@xeokit/xeokit-bim-viewer": "2.2.0-alpha.4",
"@xeokit/xeokit-sdk": "1.8.3-alpha.4",
"autoprefixer": "^9.6.1",
"browserslist": "^4.9.1",
"cdk-drag-scroll": "^0.0.6",
@ -3522,6 +3522,14 @@
"resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.4.tgz",
"integrity": "sha512-rPvqs+1hL/5hbES/0HTdUu4lvNmneiwKwccbWe7HGLWbnsLdqKnQHyWLg4Pj0AMO7PLHCwBM1Cs8orChdkDONg=="
},
"node_modules/@types/resolve": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
"integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/sizzle": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
@ -4069,22 +4077,58 @@
}
},
"node_modules/@xeokit/xeokit-bim-viewer": {
"version": "1.8.6",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-bim-viewer/-/xeokit-bim-viewer-1.8.6.tgz",
"integrity": "sha512-OLndzuRbayi8cCBOrd9QX95E+iTC818ZlS5nCCVsbtxqOxJgUdEV2rNj+YF/6xMGBLI4Vi+ew55U6zd+QSrEcg==",
"version": "2.2.0-alpha.4",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-bim-viewer/-/xeokit-bim-viewer-2.2.0-alpha.4.tgz",
"integrity": "sha512-p+WHjUcg3rG5qKW6CJHt+BMmPxg0CG45/BIDyfWbKZGf/ah8t+NPkHhDv5TAj/Oe2qBG0dTTz9CUceRAtpO2Aw==",
"dependencies": {
"@xeokit/xeokit-sdk": "1.3.9"
"@xeokit/xeokit-sdk": "1.8.3-alpha.3"
}
},
"node_modules/@xeokit/xeokit-bim-viewer/node_modules/@xeokit/xeokit-sdk": {
"version": "1.3.9",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-sdk/-/xeokit-sdk-1.3.9.tgz",
"integrity": "sha512-hNay1xtqOND7YBvMYlZnxban7p7nctMJKasN+j8bff1TaMVyAyJ4oyC8Rua5DznYB609SLzNlaHBPH4B5c15YA=="
"version": "1.8.3-alpha.3",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-sdk/-/xeokit-sdk-1.8.3-alpha.3.tgz",
"integrity": "sha512-zjFmDc/19Y/YcGoqVevgYur/C/sitF4PQsz4YCLuj5J0soCIOG/7+2hlzdn4nfsKMn3mBMbzVl3Ran6l0+9FMA==",
"dependencies": {
"rollup": "^2.46.0",
"rollup-plugin-node-resolve": "^5.2.0"
}
},
"node_modules/@xeokit/xeokit-bim-viewer/node_modules/rollup": {
"version": "2.46.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.46.0.tgz",
"integrity": "sha512-qPGoUBNl+Z8uNu0z7pD3WPTABWRbcOwIrO/5ccDJzmrtzn0LVf6Lj91+L5CcWhXl6iWf23FQ6m8Jkl2CmN1O7Q==",
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=10.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.1"
}
},
"node_modules/@xeokit/xeokit-sdk": {
"version": "1.3.91",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-sdk/-/xeokit-sdk-1.3.91.tgz",
"integrity": "sha512-HN2fp6twQMtpB/MyJ0n5i7AYxPUcQm5Koxb/gsUs92ylZwSsIEftRCqSXdYv52cyHYE89LpsU6Lfh1qkl1L6tQ=="
"version": "1.8.3-alpha.4",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-sdk/-/xeokit-sdk-1.8.3-alpha.4.tgz",
"integrity": "sha512-F3OqQmqaCJ5YXS5MdlwHYdM9kVOs/BpFfDSZP50iEYFgvUbAr3PWqoSYT2sD0UNxgJqQXq9BW6j3//nNHeTVjg==",
"dependencies": {
"rollup": "^2.46.0",
"rollup-plugin-node-resolve": "^5.2.0"
}
},
"node_modules/@xeokit/xeokit-sdk/node_modules/rollup": {
"version": "2.46.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.46.0.tgz",
"integrity": "sha512-qPGoUBNl+Z8uNu0z7pD3WPTABWRbcOwIrO/5ccDJzmrtzn0LVf6Lj91+L5CcWhXl6iWf23FQ6m8Jkl2CmN1O7Q==",
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=10.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.1"
}
},
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
@ -8508,6 +8552,11 @@
"node": ">=4.0"
}
},
"node_modules/estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="
},
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@ -10391,6 +10440,11 @@
"resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
"integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU="
},
"node_modules/is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE="
},
"node_modules/is-negative-zero": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
@ -15293,6 +15347,41 @@
"fsevents": "~2.3.1"
}
},
"node_modules/rollup-plugin-node-resolve": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
"integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
"deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-node-resolve.",
"dependencies": {
"@types/resolve": "0.0.8",
"builtin-modules": "^3.1.0",
"is-module": "^1.0.0",
"resolve": "^1.11.1",
"rollup-pluginutils": "^2.8.1"
},
"peerDependencies": {
"rollup": ">=1.11.0"
}
},
"node_modules/rollup-plugin-node-resolve/node_modules/builtin-modules": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
"integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/rollup-pluginutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
"dependencies": {
"estree-walker": "^0.6.1"
}
},
"node_modules/run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@ -22673,6 +22762,14 @@
"resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.4.tgz",
"integrity": "sha512-rPvqs+1hL/5hbES/0HTdUu4lvNmneiwKwccbWe7HGLWbnsLdqKnQHyWLg4Pj0AMO7PLHCwBM1Cs8orChdkDONg=="
},
"@types/resolve": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
"integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
"requires": {
"@types/node": "*"
}
},
"@types/sizzle": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
@ -23096,24 +23193,50 @@
}
},
"@xeokit/xeokit-bim-viewer": {
"version": "1.8.6",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-bim-viewer/-/xeokit-bim-viewer-1.8.6.tgz",
"integrity": "sha512-OLndzuRbayi8cCBOrd9QX95E+iTC818ZlS5nCCVsbtxqOxJgUdEV2rNj+YF/6xMGBLI4Vi+ew55U6zd+QSrEcg==",
"version": "2.2.0-alpha.4",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-bim-viewer/-/xeokit-bim-viewer-2.2.0-alpha.4.tgz",
"integrity": "sha512-p+WHjUcg3rG5qKW6CJHt+BMmPxg0CG45/BIDyfWbKZGf/ah8t+NPkHhDv5TAj/Oe2qBG0dTTz9CUceRAtpO2Aw==",
"requires": {
"@xeokit/xeokit-sdk": "1.3.9"
"@xeokit/xeokit-sdk": "1.8.3-alpha.3"
},
"dependencies": {
"@xeokit/xeokit-sdk": {
"version": "1.3.9",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-sdk/-/xeokit-sdk-1.3.9.tgz",
"integrity": "sha512-hNay1xtqOND7YBvMYlZnxban7p7nctMJKasN+j8bff1TaMVyAyJ4oyC8Rua5DznYB609SLzNlaHBPH4B5c15YA=="
"version": "1.8.3-alpha.3",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-sdk/-/xeokit-sdk-1.8.3-alpha.3.tgz",
"integrity": "sha512-zjFmDc/19Y/YcGoqVevgYur/C/sitF4PQsz4YCLuj5J0soCIOG/7+2hlzdn4nfsKMn3mBMbzVl3Ran6l0+9FMA==",
"requires": {
"rollup": "^2.46.0",
"rollup-plugin-node-resolve": "^5.2.0"
}
},
"rollup": {
"version": "2.46.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.46.0.tgz",
"integrity": "sha512-qPGoUBNl+Z8uNu0z7pD3WPTABWRbcOwIrO/5ccDJzmrtzn0LVf6Lj91+L5CcWhXl6iWf23FQ6m8Jkl2CmN1O7Q==",
"requires": {
"fsevents": "~2.3.1"
}
}
}
},
"@xeokit/xeokit-sdk": {
"version": "1.3.91",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-sdk/-/xeokit-sdk-1.3.91.tgz",
"integrity": "sha512-HN2fp6twQMtpB/MyJ0n5i7AYxPUcQm5Koxb/gsUs92ylZwSsIEftRCqSXdYv52cyHYE89LpsU6Lfh1qkl1L6tQ=="
"version": "1.8.3-alpha.4",
"resolved": "https://registry.npmjs.org/@xeokit/xeokit-sdk/-/xeokit-sdk-1.8.3-alpha.4.tgz",
"integrity": "sha512-F3OqQmqaCJ5YXS5MdlwHYdM9kVOs/BpFfDSZP50iEYFgvUbAr3PWqoSYT2sD0UNxgJqQXq9BW6j3//nNHeTVjg==",
"requires": {
"rollup": "^2.46.0",
"rollup-plugin-node-resolve": "^5.2.0"
},
"dependencies": {
"rollup": {
"version": "2.46.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.46.0.tgz",
"integrity": "sha512-qPGoUBNl+Z8uNu0z7pD3WPTABWRbcOwIrO/5ccDJzmrtzn0LVf6Lj91+L5CcWhXl6iWf23FQ6m8Jkl2CmN1O7Q==",
"requires": {
"fsevents": "~2.3.1"
}
}
}
},
"@xtuc/ieee754": {
"version": "1.2.0",
@ -26783,6 +26906,11 @@
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
},
"estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@ -28314,6 +28442,11 @@
"resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
"integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU="
},
"is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE="
},
"is-negative-zero": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
@ -32309,6 +32442,33 @@
"fsevents": "~2.3.1"
}
},
"rollup-plugin-node-resolve": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
"integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
"requires": {
"@types/resolve": "0.0.8",
"builtin-modules": "^3.1.0",
"is-module": "^1.0.0",
"resolve": "^1.11.1",
"rollup-pluginutils": "^2.8.1"
},
"dependencies": {
"builtin-modules": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
"integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA=="
}
}
},
"rollup-pluginutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
"requires": {
"estree-walker": "^0.6.1"
}
},
"run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",

@ -71,8 +71,8 @@
"@uirouter/core": "^6.0.7",
"@uirouter/rx": "^0.6.5",
"@w11k/ngx-componentdestroyed": "^5.0.2",
"@xeokit/xeokit-bim-viewer": "^1.8.6",
"@xeokit/xeokit-sdk": "^1.3.91",
"@xeokit/xeokit-bim-viewer": "2.2.0-alpha.4",
"@xeokit/xeokit-sdk": "1.8.3-alpha.4",
"autoprefixer": "^9.6.1",
"browserslist": "^4.9.1",
"cdk-drag-scroll": "^0.0.6",

@ -38,6 +38,8 @@ import {
import { IFCViewerService } from "core-app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.service";
import { IfcModelsDataService } from "core-app/modules/bim/ifc_models/pages/viewer/ifc-models-data.service";
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";
@Component({
selector: 'ifc-viewer',
@ -64,7 +66,9 @@ export class IFCViewerComponent implements OnInit, OnDestroy {
constructor(private I18n:I18nService,
private elementRef:ElementRef,
public ifcData:IfcModelsDataService,
private ifcViewer:IFCViewerService) {
private ifcViewer:IFCViewerService,
private currentUserService:CurrentUserService,
private currentProjectService:CurrentProjectService) {
}
ngOnInit():void {
@ -76,16 +80,28 @@ export class IFCViewerComponent implements OnInit, OnDestroy {
const element = jQuery(this.elementRef.nativeElement as HTMLElement);
this.ifcViewer.newViewer(
{
canvasElement: element.find(".ifc-model-viewer--model-canvas")[0], // WebGL canvas
explorerElement: jQuery(".ifc-model-viewer--tree-panel")[0], // Left panel
toolbarElement: element.find(".ifc-model-viewer--toolbar-container")[0], // Toolbar
navCubeCanvasElement: element.find(".ifc-model-viewer--nav-cube-canvas")[0],
busyModelBackdropElement: element.find(".xeokit-busy-modal-backdrop")[0]
},
this.ifcData.projects
);
this.currentUserService
.hasCapabilities$(
[
'ifc_models/create',
'ifc_models/update',
'ifc_models/destroy'
],
this.currentProjectService.id as string
).subscribe((manageIfcModelsAllowed) => {
this.ifcViewer.newViewer(
{
canvasElement: element.find(".ifc-model-viewer--model-canvas")[0], // WebGL canvas
explorerElement: jQuery(".ifc-model-viewer--tree-panel")[0], // Left panel
toolbarElement: element.find(".ifc-model-viewer--toolbar-container")[0], // Toolbar
navCubeCanvasElement: element.find(".ifc-model-viewer--nav-cube-canvas")[0],
busyModelBackdropElement: element.find(".xeokit-busy-modal-backdrop")[0],
enableEditModels: manageIfcModelsAllowed
},
this.ifcData.projects
)
});
}
ngOnDestroy():void {

@ -8,7 +8,8 @@ import { PathHelperService } from "core-app/modules/common/path-helper/path-help
import { BcfApiService } from "core-app/modules/bim/bcf/api/bcf-api.service";
import { InjectField } from "core-app/helpers/angular/inject-field.decorator";
import { ViewpointsService } from "core-app/modules/bim/bcf/helper/viewpoints.service";
import { CurrentProjectService} from "core-app/components/projects/current-project.service";
import { HttpClient } from "@angular/common/http";
export interface XeokitElements {
@ -17,6 +18,7 @@ export interface XeokitElements {
toolbarElement:HTMLElement;
navCubeCanvasElement:HTMLElement;
busyModelBackdropElement:HTMLElement;
enableEditModels?:boolean;
}
export interface BCFCreationOptions {
@ -40,13 +42,15 @@ export class IFCViewerService extends ViewerBridgeService {
@InjectField() pathHelper:PathHelperService;
@InjectField() bcfApi:BcfApiService;
@InjectField() viewpointsService:ViewpointsService;
@InjectField() currentProjectService:CurrentProjectService;
@InjectField() httpClient:HttpClient;
constructor(readonly injector:Injector) {
super(injector);
}
public newViewer(elements:XeokitElements, projects:any[]) {
import('@xeokit/xeokit-bim-viewer/dist/main').then((XeokitViewerModule:any) => {
import('@xeokit/xeokit-bim-viewer/dist/xeokit-bim-viewer.es').then((XeokitViewerModule:any) => {
const server = new XeokitServer(this.pathHelper);
const viewerUI = new XeokitViewerModule.BIMViewer(server, elements);
@ -58,6 +62,40 @@ export class IFCViewerService extends ViewerBridgeService {
viewerUI.loadProject(projects[0]["id"]);
viewerUI.on("addModel", (event:Event) => { // "Add" selected in Models tab's context menu
window.location.href = this.pathHelper.ifcModelsNewPath(this.currentProjectService.identifier as string);
});
viewerUI.on("editModel", (event:{ modelId:number|string }) => { // "Edit" selected in Models tab's context menu
window.location.href = this.pathHelper.ifcModelsEditPath(this.currentProjectService.identifier as string, event.modelId);
});
viewerUI.on("deleteModel", (event:{ modelId:number|string }) => { // "Delete" selected in Models tab's context menu
// We don't have an API for IFC models yet. We need to use the normal Rails form posts for deletion.
const formData = new FormData();
formData.append(
'authenticity_token',
jQuery('meta[name=csrf-token]').attr('content') as string
);
formData.append(
'_method',
'delete'
);
this.httpClient.post(
this.pathHelper.ifcModelsDeletePath(
this.currentProjectService.identifier as string, event.modelId),
formData
)
.subscribe()
.add(() => {
// Ensure we reload after every request.
// We need to reload to get a fresh CSRF token for a successive
// model deletion placed as a META element into the HTML HEAD.
window.location.reload()
})
});
this.viewer = viewerUI;
});
}

@ -135,3 +135,8 @@ $pill-padding-left: 8px
&.disabled:hover
cursor: default
// Temporary fix until fixed upstream: The first two buttons in the "Models" tab are separate by a space character
// between the elements. There is no such space before the "Add model" button. We need to emulate it.
.xeokit-addModel
margin-left: 4px

@ -30,7 +30,53 @@
@include icon-mixin-rubber
.fa-mouse-pointer::before
@include icon-mixin-cursor
.fa-th::before
@include icon-mixin-menu
// -------------------------- XEOKIT Section tool ----------------------
.xeokit-section-counter
opacity: 1.0
padding: 1px
margin: 0
margin-left: 10px
width: 20px
height: 16px
float: right
.xeokit-section-menu-button
opacity: 1.0
border-radius: 5px
border: 0
padding: 1px
margin: 0
margin-left: 10px
width: 20px
height: 16px
float: right
.xeokit-arrow-up
width: 0
height: 0
display: inline-block
vertical-align: middle
border-left: 5px solid transparent
border-right: 5px solid transparent
border-bottom: 5px solid var(--button--font-color)
&.active
border-bottom-color: var(--button--active-font-color)
.xeokit-arrow-down
width: 0
height: 0
display: inline-block
vertical-align: middle
border-style: solid
border-width: 5px 5px 0 5px
border-color: var(--button--font-color) transparent transparent transparent
&.active
border-top-color: var(--button--active-font-color)
// -------------------------- XEOKIT specific --------------------------
// Move toolbar to the right
@ -39,10 +85,6 @@
flex-wrap: wrap
justify-content: flex-end
// Hide the counter for the time being until it is properly implemented.
.xeokit-section-counter
display: none
// -------------------------- MOBILE specific --------------------------
@media only screen and (max-width: 679px)

@ -1,2 +1,2 @@
declare module '@xeokit/xeokit-bim-viewer/node_modules/@xeokit/xeokit-sdk/src/viewer/scene/utils';
declare module '@xeokit/xeokit-bim-viewer/dist/main';
declare module '@xeokit/xeokit-bim-viewer/dist/xeokit-bim-viewer.es';

@ -112,6 +112,18 @@ export class PathHelperService {
return `${this.staticBase}/projects/${projectIdentifier}/ifc_models`;
}
public ifcModelsNewPath(projectIdentifier:string) {
return `${this.ifcModelsPath(projectIdentifier)}/new`;
}
public ifcModelsEditPath(projectIdentifier:string, modelId:number|string) {
return `${this.ifcModelsPath(projectIdentifier)}/${modelId}/edit`;
}
public ifcModelsDeletePath(projectIdentifier:string, modelId:number|string) {
return `${this.ifcModelsPath(projectIdentifier)}/${modelId}`;
}
public bimDetailsPath(projectIdentifier:string, workPackageId:string, viewpoint:number|string|null = null) {
let path = `${this.projectPath(projectIdentifier)}/bcf/split/details/${workPackageId}`;

@ -26,8 +26,7 @@ module IfcModelsHelper
{
id: ifc_model.id,
name: ifc_model.title,
default: ifc_model.is_default,
saoEnabled: ifc_model.is_default
default: ifc_model.is_default
}
end
end

@ -52,4 +52,4 @@ echo "✔ xeokit-metadata is in your path. (without .NET yet, see below)"
echo "DONE - Now execute the following as your development user:
$ # Install XKT converter
$ npm install @xeokit/xeokit-gltf-to-xkt@0.0.3 -g"
$ npm install @xeokit/xeokit-gltf-to-xkt@1.0.0 -g"

@ -48,20 +48,23 @@ module OpenProject::Bim
{
'bim/ifc_models/ifc_models': %i[index show defaults],
'bim/ifc_models/ifc_viewer': %i[show]
}
},
contract_actions: { ifc_models: %i[read] }
permission :manage_ifc_models,
{ 'bim/ifc_models/ifc_models': %i[index show destroy edit update create new] },
dependencies: %i[view_ifc_models]
dependencies: %i[view_ifc_models],
contract_actions: { ifc_models: %i[create update destroy] }
permission :view_linked_issues,
{ 'bim/bcf/issues': %i[index] },
dependencies: %i[view_work_packages]
dependencies: %i[view_work_packages],
contract_actions: { bcf: %i[read] }
permission :manage_bcf,
{ 'bim/bcf/issues': %i[index upload prepare_import configure_import perform_import] },
dependencies: %i[view_linked_issues
view_work_packages
add_work_packages
edit_work_packages]
edit_work_packages],
contract_actions: { bcf: %i[create update] }
permission :delete_bcf,
{},
dependencies: %i[view_linked_issues
@ -69,7 +72,8 @@ module OpenProject::Bim
view_work_packages
add_work_packages
edit_work_packages
delete_work_packages]
delete_work_packages],
contract_actions: { bcf: %i[destroy] }
end
OpenProject::AccessControl.permission(:view_work_packages).controller_actions << 'bim/bcf/issues/redirect_to_bcf_issues_list'

@ -58,8 +58,7 @@ describe 'model viewer',
before do
login_as(user)
work_package
show_model_page.visit!
show_model_page.finished_loading
show_model_page.visit_and_wait_until_finished_loading!
end
it 'loads and shows the viewer correctly' do
@ -67,12 +66,29 @@ describe 'model viewer',
show_model_page.model_viewer_shows_a_toolbar true
show_model_page.page_shows_a_toolbar true
model_tree.sidebar_shows_viewer_menu true
model_tree.expect_model_management_available visible: true
end
it 'shows a work package list as cards next to the viewer' do
show_model_page.model_viewer_visible true
card_view.expect_work_package_listed work_package
end
it 'can trigger creation, update and deletion of IFC models from within the model tree view' do
model_tree.click_add_model
expect(page).to have_current_path new_bcf_project_ifc_model_path(project)
show_model_page.visit_and_wait_until_finished_loading!
model_tree.select_model_menu_item(model.title, "Edit")
expect(page).to have_current_path edit_bcf_project_ifc_model_path(project, model.id)
show_model_page.visit_and_wait_until_finished_loading!
model_tree.select_model_menu_item(model.title, "Delete")
show_model_page.finished_loading
expect(page).to have_text(I18n.t('js.ifc_models.empty_warning'))
end
end
context 'in a project with no model' do
@ -94,8 +110,7 @@ describe 'model viewer',
before do
login_as(view_user)
show_model_page.visit!
show_model_page.finished_loading
show_model_page.visit_and_wait_until_finished_loading!
end
it 'loads and shows the viewer correctly, but has no possibility to edit the model' do
@ -103,6 +118,7 @@ describe 'model viewer',
show_model_page.model_viewer_shows_a_toolbar true
show_model_page.page_shows_a_toolbar false
model_tree.sidebar_shows_viewer_menu true
model_tree.expect_model_management_available visible: false
end
end

@ -42,6 +42,21 @@ module Components
end
end
def expect_model_management_available(visible: true)
selector = '.xeokit-btn.xeokit-addModel'
expect(page).to have_conditional_selector(visible, selector)
end
def click_add_model
selector = '.xeokit-btn.xeokit-addModel'
page.find(selector).click
end
def select_model_menu_item(model_name, item_label)
page.find('.xeokit-form-check span', text: model_name).right_click
page.find('.xeokit-context-menu-item', text: item_label).click
end
def select_sidebar_tab(tab)
selector = '.xeokit-tab'
page.find(selector, text: tab).click

@ -44,6 +44,11 @@ module Pages
defaults_bcf_project_ifc_models_path(project)
end
def visit_and_wait_until_finished_loading!
visit!
finished_loading
end
def finished_loading
expect(page).to have_selector('.xeokit-busy-modal', visible: false, wait: 30)
end
@ -58,7 +63,7 @@ module Pages
if visible
within ('.ifc-model-viewer--toolbar-container') do
expect(page).to have_selector(selector, count: 8)
expect(page).to have_selector(selector, count: 9)
end
else
expect(page).to have_no_selector(selector)

@ -222,7 +222,12 @@ describe Capabilities::Scopes::Default, type: :model do
it_behaves_like 'consists of contract actions' do
let(:expected) do
# This complicated and programmatic way is chosen so that the test can deal with additional actions being defined
item = ->(namespace, action, global) {
item = ->(namespace, action, global, module_name) {
# We only expect contract actions for project modules that are enabled by default. In the
# default edition the Bim module is not enabled by default for instance and thus it's contract
# actions are not expected to be part of the default capabilities.
return if module_name.present? && project.enabled_module_names.exclude?(module_name.to_s)
["#{API::Utilities::PropertyNameConverter.from_ar_name(namespace.to_s.singularize).pluralize.underscore}/#{action}",
user.id,
global ? nil : project.id]
@ -230,8 +235,9 @@ describe Capabilities::Scopes::Default, type: :model do
OpenProject::AccessControl
.contract_actions_map
.map { |_, v| v[:actions].map { |vk, vv| vv.map { |vvv| item.call(vk, vvv, v[:global]) } } }
.map { |_, v| v[:actions].map { |vk, vv| vv.map { |vvv| item.call(vk, vvv, v[:global], v[:module]) } } }
.flatten(2)
.compact
end
end
end
@ -246,8 +252,8 @@ describe Capabilities::Scopes::Default, type: :model do
it_behaves_like 'consists of contract actions' do
let(:expected) do
# This complicated and programmatic way is chosen so that the test can deal with additional actions being defined
item = ->(namespace, action, global) {
return if namespace == :work_packages
item = ->(namespace, action, global, module_name) {
return if module_name.present?
["#{API::Utilities::PropertyNameConverter.from_ar_name(namespace.to_s.singularize).pluralize.underscore}/#{action}",
user.id,
@ -256,7 +262,7 @@ describe Capabilities::Scopes::Default, type: :model do
OpenProject::AccessControl
.contract_actions_map
.map { |_, v| v[:actions].map { |vk, vv| vv.map { |vvv| item.call(vk, vvv, v[:global]) } } }
.map { |_, v| v[:actions].map { |vk, vv| vv.map { |vvv| item.call(vk, vvv, v[:global], v[:module]) } } }
.flatten(2)
.compact
end

@ -56,8 +56,8 @@ describe 'API v3 action resource', type: :request, content_type: :json do
.at_path('_embedded/elements/0/id')
expect(subject.body)
.to be_json_eql(Action.order(id: :asc).last.id.to_json)
.at_path("_embedded/elements/#{Action.count - 1}/id")
.to be_json_eql(Action.order(id: :asc).first.id.to_json)
.at_path("_embedded/elements/0/id")
end
end

Loading…
Cancel
Save