diff --git a/cypress/e2e/integration/bldrs-inside-iframe.cy.js b/cypress/e2e/integration/bldrs-inside-iframe.cy.js index c94e83718..79257ba00 100644 --- a/cypress/e2e/integration/bldrs-inside-iframe.cy.js +++ b/cypress/e2e/integration/bldrs-inside-iframe.cy.js @@ -66,6 +66,25 @@ describe('bldrs inside iframe', () => { // cy.get('#messagesCount').contains('2') //Second loaded message received }) + it('should load model from external http source when LoadModel-message emitted', () => { + const model = 'raw.githubusercontent.com/Swiss-Property-AG/Momentum-Public/main/Momentum.ifc' + const modelRootNodeName = 'Proxy with extruded box' + cy.get('@iframe').trigger('keydown', {keyCode: KEYCODE_ESC}) + + cy.get('#txtSendMessageType').clear().type('ai.bldrs-share.LoadModel') + const msg = { + srcPath: model, + } + + cy.intercept('GET', REMOTE_IFC_URL, {fixture: REMOTE_IFC_FIXTURE}).as('loadModel') + + cy.get('#txtSendMessagePayload').clear() + .type(JSON.stringify(msg), {parseSpecialCharSequences: false}) + cy.get('#btnSendMessage').click() + cy.wait('@loadModel').its('response.statusCode').should('eq', REQUEST_SUCCESS_CODE) + cy.get('@iframe').contains('span', modelRootNodeName).should('exist') + }) + it('should select element when SelectElements-message emitted', () => { cy.get('@iframe').trigger('keydown', {keyCode: KEYCODE_ESC}) cy.get('#lastMessageReceivedAction').contains(/ModelLoaded/i) diff --git a/package.json b/package.json index 2700bc22d..2d60eaff2 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "eslint-plugin-cypress": "^2.12.1", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jest-dom": "^4.0.3", - "eslint-plugin-jsdoc": "^39.3.6", + "eslint-plugin-jsdoc": "^46.2.6", "eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", diff --git a/src/Containers/CadView.jsx b/src/Containers/CadView.jsx index f61d08c21..ccb9f732d 100644 --- a/src/Containers/CadView.jsx +++ b/src/Containers/CadView.jsx @@ -288,6 +288,12 @@ export default function CadView({ window.addEventListener('beforeunload', handleBeforeUnload) } + if (uploadedFile && filepath.endsWith('index')) { + // todo(zein): this is obviously an invalid state and should be fixed at the level of URL change handling + // meanwhile we prevent the application from throwing errors at the user + return + } + const loadingMessageBase = `Loading ${filepath}` setLoadingMessage(loadingMessageBase) setIsLoading(true) diff --git a/src/ShareRoutes.jsx b/src/ShareRoutes.jsx index b2a0bee89..26fad4dd6 100644 --- a/src/ShareRoutes.jsx +++ b/src/ShareRoutes.jsx @@ -73,11 +73,59 @@ export default function ShareRoutes({installPrefix, appPrefix}) { /> } /> + + } + /> ) } +/** + * Fetches an IFC file from a remote URL (https only) and then loads it as a local file. + * + * Example: + * A file located at https://example.org/pathto/myfile.ifc can be loaded into Bldrs via + * the following URL http://bldrs.ai/share/v/src/example.org%2Fpathto%2Fmyfile.ifc + * + * @param {string} appPrefix e.g. /share is the prefix for this component. + * @return {(null)} + */ +function FetchFromUrl({appPrefix}) { + const location = useLocation() + const navigate = useNavigate() + + useEffect(() => { + const fetchFromUrlAndRedirect = async () => { + const locationParts = location.pathname.split('/') + const srcIndex = locationParts.indexOf('src') + if (srcIndex >= 0) { + const urlIndex = srcIndex + 1 + if (urlIndex < locationParts.length) { + const encodedUrl = locationParts.slice(urlIndex).join('/') + const decodedUrl = decodeURIComponent(encodedUrl) + const fullUrl = `//${decodedUrl}` + const fetchResponse = await fetch(fullUrl) + const blob = await fetchResponse.blob() + + let localBlobUrl = URL.createObjectURL(blob) + const parts = localBlobUrl.split('/') + localBlobUrl = parts[parts.length - 1] + + window.removeEventListener('beforeunload', handleBeforeUnload) + navigate(`${appPrefix}/v/new/${localBlobUrl}.ifc`) + } + } + } + fetchFromUrlAndRedirect() + }) + + return (null) +} + /** * Forward page from /share to /share/v/p per spect at: diff --git a/src/WidgetApi/event-handlers/LoadModelEventHandler.js b/src/WidgetApi/event-handlers/LoadModelEventHandler.js index ab343d73d..c009e84c9 100644 --- a/src/WidgetApi/event-handlers/LoadModelEventHandler.js +++ b/src/WidgetApi/event-handlers/LoadModelEventHandler.js @@ -27,10 +27,15 @@ class LoadModelEventHandler extends ApiEventHandler { * @return {object} the response of the API call */ handler(data) { - if (!('githubIfcPath' in data)) { - return this.apiConnection.missingArgumentResponse('githubIfcPath') + if (!('githubIfcPath' in data) && !('srcPath' in data)) { + return this.apiConnection.missingArgumentResponse('githubIfcPath or srcPath') } - this.navigation(`/share/v/gh/${data.githubIfcPath}`) + if ('githubIfcPath' in data) { + this.navigation(`/share/v/gh/${data.githubIfcPath}`) + } else if ('srcPath' in data) { + this.navigation(`/share/v/src/${data.srcPath}`) + } + return this.apiConnection.successfulResponse({}) } } diff --git a/src/utils/debug.js b/src/utils/debug.js index 3b6cbcd77..a334e3973 100644 --- a/src/utils/debug.js +++ b/src/utils/debug.js @@ -5,7 +5,7 @@ const WARN = 2 // Use this as default for prod. Should never see these messages const INFO = 1 const DEBUG = 0 /* eslint-enable no-unused-vars */ -let DEBUG_LEVEL = WARN +let DEBUG_LEVEL = OFF /** diff --git a/src/utils/navigate.js b/src/utils/navigate.js index dd17a4e89..c5ef557e7 100644 --- a/src/utils/navigate.js +++ b/src/utils/navigate.js @@ -1,3 +1,9 @@ +/** + * BLDRS, when inserted in an iframe, is modifying the parent window's + * history. This is a workaround to prevent that. + */ +window.history.pushState = window.history.replaceState; + /** * Helper for calling navigate that will append search query to path, * if present, before appending an optional hash. diff --git a/yarn.lock b/yarn.lock index f7b5c9cd6..90fe87d71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1621,14 +1621,14 @@ resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== -"@es-joy/jsdoccomment@~0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz" - integrity sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ== +"@es-joy/jsdoccomment@~0.39.4": + version "0.39.4" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz#6b8a62e9b3077027837728818d3c4389a898b392" + integrity sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg== dependencies: comment-parser "1.3.1" - esquery "^1.4.0" - jsdoc-type-pratt-parser "~3.1.0" + esquery "^1.5.0" + jsdoc-type-pratt-parser "~4.0.0" "@esbuild/linux-loong64@0.15.5": version "0.15.5" @@ -3427,6 +3427,11 @@ arch@^2.2.0: resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== +are-docs-informative@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963" + integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig== + are-we-there-yet@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" @@ -3920,6 +3925,11 @@ buffer@^5.5.0, buffer@^5.6.0: base64-js "^1.3.1" ieee754 "^1.1.13" +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + bytes@3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" @@ -5313,17 +5323,19 @@ eslint-plugin-jest-dom@^4.0.3: "@testing-library/dom" "^8.11.1" requireindex "^1.2.0" -eslint-plugin-jsdoc@^39.3.6: - version "39.3.6" - resolved "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.6.tgz" - integrity sha512-R6dZ4t83qPdMhIOGr7g2QII2pwCjYyKP+z0tPOfO1bbAbQyKC20Y2Rd6z1te86Lq3T7uM8bNo+VD9YFpE8HU/g== +eslint-plugin-jsdoc@^46.2.6: + version "46.2.6" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.2.6.tgz#f25590d371859f20691d65b5dcd4cbe370d65564" + integrity sha512-zIaK3zbSrKuH12bP+SPybPgcHSM6MFzh3HFeaODzmsF1N8C1l8dzJ22cW1aq4g0+nayU1VMjmNf7hg0dpShLrA== dependencies: - "@es-joy/jsdoccomment" "~0.31.0" + "@es-joy/jsdoccomment" "~0.39.4" + are-docs-informative "^0.0.2" comment-parser "1.3.1" debug "^4.3.4" escape-string-regexp "^4.0.0" - esquery "^1.4.0" - semver "^7.3.7" + esquery "^1.5.0" + is-builtin-module "^3.2.1" + semver "^7.5.1" spdx-expression-parse "^3.0.1" eslint-plugin-jsx-a11y@^6.6.1: @@ -5476,6 +5488,13 @@ esquery@^1.4.0: dependencies: estraverse "^5.1.0" +esquery@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" @@ -6496,6 +6515,13 @@ is-buffer@~1.1.6: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.4: version "1.2.4" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz" @@ -7274,10 +7300,10 @@ jsbn@~0.1.0: resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== -jsdoc-type-pratt-parser@~3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz" - integrity sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw== +jsdoc-type-pratt-parser@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" + integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== jsdom@^20.0.0: version "20.0.0" @@ -9559,6 +9585,13 @@ semver@^7.3.5: dependencies: lru-cache "^6.0.0" +semver@^7.5.1: + version "7.5.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb" + integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ== + dependencies: + lru-cache "^6.0.0" + send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz"