diff --git a/.docker/Viewer-v3.x/default.conf.template b/.docker/Viewer-v3.x/default.conf.template index bbee32449..2266e8a5c 100644 --- a/.docker/Viewer-v3.x/default.conf.template +++ b/.docker/Viewer-v3.x/default.conf.template @@ -7,7 +7,7 @@ server { location / { root /usr/share/nginx/html; index index.html index.htm; - try_files $uri $uri/ /index.html; + try_files $uri $uri/ ${PUBLIC_URL}index.html; add_header Cross-Origin-Resource-Policy same-origin; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/.docker/Viewer-v3.x/entrypoint.sh b/.docker/Viewer-v3.x/entrypoint.sh index c0801a0dd..3e0d73019 100644 --- a/.docker/Viewer-v3.x/entrypoint.sh +++ b/.docker/Viewer-v3.x/entrypoint.sh @@ -2,12 +2,11 @@ if [ -n "$SSL_PORT" ] then - envsubst '${SSL_PORT}:${PORT}' < /usr/src/default.ssl.conf.template > /etc/nginx/conf.d/default.conf + envsubst '${SSL_PORT}:${PORT}' < /usr/src/default.ssl.conf.template | envsubst '${PUBLIC_URL}' > /etc/nginx/conf.d/default.conf else - envsubst '${PORT}' < /usr/src/default.conf.template > /etc/nginx/conf.d/default.conf + envsubst '${PORT}:${PUBLIC_URL}' < /usr/src/default.conf.template > /etc/nginx/conf.d/default.conf fi - if [ -n "$APP_CONFIG" ]; then echo "$APP_CONFIG" > /usr/share/nginx/html${PUBLIC_URL}app-config.js echo "Using custom APP_CONFIG environment variable" diff --git a/Dockerfile b/Dockerfile index a3f8be304..1a313181a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -62,9 +62,6 @@ RUN bun pm cache rm RUN bun install # Copy the local directory COPY --link --exclude=yarn.lock --exclude=package.json --exclude=Dockerfile . . -# Do a second install to finalize things after the copy -RUN bun run show:config -RUN bun install # Build here # After install it should hopefully be stable until the local directory changes @@ -72,6 +69,7 @@ ENV QUICK_BUILD true # ENV GENERATE_SOURCEMAP=false ARG APP_CONFIG=config/default.js ARG PUBLIC_URL=/ +ENV PUBLIC_URL=${PUBLIC_URL} RUN bun run show:config RUN bun run build @@ -84,16 +82,19 @@ RUN ./.docker/compressDist.sh # which runs Nginx using Alpine Linux FROM nginxinc/nginx-unprivileged:1.27-alpine as final #RUN apk add --no-cache bash -ARG PORT=80 -ENV PORT=${PORT} ARG PUBLIC_URL=/ ENV PUBLIC_URL=${PUBLIC_URL} +ARG PORT=80 +ENV PORT=${PORT} RUN rm /etc/nginx/conf.d/default.conf USER nginx COPY --chown=nginx:nginx .docker/Viewer-v3.x /usr/src RUN chmod 777 /usr/src/entrypoint.sh COPY --from=builder /usr/src/app/platform/app/dist /usr/share/nginx/html${PUBLIC_URL} -COPY --from=builder /usr/src/app/platform/app/dist/index.html /usr/share/nginx/html +# Copy paths that are renamed/redirected generally +# Microscopy libraries depend on root level include, so must be copied +COPY --from=builder /usr/src/app/platform/app/dist/dicom-microscopy-viewer /usr/share/nginx/html/dicom-microscopy-viewer + # In entrypoint.sh, app-config.js might be overwritten, so chmod it to be writeable. # The nginx user cannot chmod it, so change to root. USER root diff --git a/bun.lock b/bun.lock index 55f826d8d..74a3c3084 100644 --- a/bun.lock +++ b/bun.lock @@ -33,7 +33,7 @@ }, "addOns/externals/devDependencies": { "name": "@externals/devDependencies", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@kitware/vtk.js": "32.12.0", @@ -121,14 +121,14 @@ }, "addOns/externals/dicom-microscopy-viewer": { "name": "@externals/dicom-microscopy-viewer", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "dicom-microscopy-viewer": "^0.46.1", }, }, "extensions/cornerstone": { "name": "@ohif/extension-cornerstone", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^3.7.16", @@ -153,8 +153,8 @@ "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/dicom-image-loader": "^3.7.16", - "@ohif/core": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "dcmjs": "*", "dicom-parser": "^1.8.21", "hammerjs": "^2.0.8", @@ -166,7 +166,7 @@ }, "extensions/cornerstone-dicom-pmap": { "name": "@ohif/extension-cornerstone-dicom-pmap", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^3.7.16", @@ -175,10 +175,10 @@ "react-color": "^2.19.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/i18n": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/i18n": "3.10.0-beta.139", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -189,16 +189,16 @@ }, "extensions/cornerstone-dicom-rt": { "name": "@ohif/extension-cornerstone-dicom-rt", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "react-color": "^2.19.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/i18n": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/i18n": "3.10.0-beta.139", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -209,7 +209,7 @@ }, "extensions/cornerstone-dicom-seg": { "name": "@ohif/extension-cornerstone-dicom-seg", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^3.7.16", @@ -218,10 +218,10 @@ "react-color": "^2.19.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/i18n": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/i18n": "3.10.0-beta.139", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -232,7 +232,7 @@ }, "extensions/cornerstone-dicom-sr": { "name": "@ohif/extension-cornerstone-dicom-sr", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^3.7.16", @@ -241,10 +241,10 @@ "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-measurement-tracking": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-measurement-tracking": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "dcmjs": "*", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -254,7 +254,7 @@ }, "extensions/cornerstone-dynamic-volume": { "name": "@ohif/extension-cornerstone-dynamic-volume", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/core": "^3.7.16", @@ -262,11 +262,11 @@ "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/i18n": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/i18n": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "dcmjs": "*", "dicom-parser": "^1.8.21", "hammerjs": "^2.0.8", @@ -276,7 +276,7 @@ }, "extensions/default": { "name": "@ohif/extension-default", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/calculate-suv": "^1.1.0", @@ -284,8 +284,8 @@ "lodash.uniqby": "^4.7.0", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/i18n": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/i18n": "3.10.0-beta.139", "dcmjs": "*", "dicomweb-client": "^0.10.4", "prop-types": "^15.6.2", @@ -299,7 +299,7 @@ }, "extensions/dicom-microscopy": { "name": "@ohif/extension-dicom-microscopy", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -310,10 +310,10 @@ "mathjs": "^12.4.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/i18n": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/i18n": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -324,14 +324,14 @@ }, "extensions/dicom-pdf": { "name": "@ohif/extension-dicom-pdf", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "dcmjs": "*", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -341,14 +341,14 @@ }, "extensions/dicom-video": { "name": "@ohif/extension-dicom-video", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "dcmjs": "*", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -358,20 +358,20 @@ }, "extensions/measurement-tracking": { "name": "@ohif/extension-measurement-tracking", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/ui": "3.10.0-beta.139", "@xstate/react": "^3.2.2", "xstate": "^4.10.0", }, "peerDependencies": { "@cornerstonejs/core": "^3.7.16", "@cornerstonejs/tools": "^3.7.16", - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "classnames": "^2.3.2", "dcmjs": "*", "lodash.debounce": "^4.0.8", @@ -384,14 +384,14 @@ }, "extensions/test-extension": { "name": "@ohif/extension-test", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "dcmjs": "0.38.0", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -401,14 +401,14 @@ }, "extensions/tmtv": { "name": "@ohif/extension-tmtv", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", "dcmjs": "*", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -418,7 +418,7 @@ }, "modes/basic-dev-mode": { "name": "@ohif/mode-basic-dev-mode", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -428,17 +428,17 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/extension-dicom-pdf": "3.10.0-beta.138", - "@ohif/extension-dicom-video": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/extension-dicom-pdf": "3.10.0-beta.139", + "@ohif/extension-dicom-video": "3.10.0-beta.139", }, }, "modes/basic-test-mode": { "name": "@ohif/mode-test", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -448,19 +448,19 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/extension-dicom-pdf": "3.10.0-beta.138", - "@ohif/extension-dicom-video": "3.10.0-beta.138", - "@ohif/extension-measurement-tracking": "3.10.0-beta.138", - "@ohif/extension-test": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/extension-dicom-pdf": "3.10.0-beta.139", + "@ohif/extension-dicom-video": "3.10.0-beta.139", + "@ohif/extension-measurement-tracking": "3.10.0-beta.139", + "@ohif/extension-test": "3.10.0-beta.139", }, }, "modes/longitudinal": { "name": "@ohif/mode-longitudinal", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -470,32 +470,32 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/extension-dicom-pdf": "3.10.0-beta.138", - "@ohif/extension-dicom-video": "3.10.0-beta.138", - "@ohif/extension-measurement-tracking": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/extension-dicom-pdf": "3.10.0-beta.139", + "@ohif/extension-dicom-video": "3.10.0-beta.139", + "@ohif/extension-measurement-tracking": "3.10.0-beta.139", }, }, "modes/microscopy": { "name": "@ohif/mode-microscopy", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-dicom-microscopy": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-dicom-microscopy": "3.10.0-beta.139", }, }, "modes/preclinical-4d": { "name": "@ohif/mode-preclinical-4d", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", }, @@ -504,17 +504,17 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dynamic-volume": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/extension-tmtv": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dynamic-volume": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/extension-tmtv": "3.10.0-beta.139", }, }, "modes/segmentation": { "name": "@ohif/mode-segmentation", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -546,19 +546,19 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/extension-dicom-pdf": "3.10.0-beta.138", - "@ohif/extension-dicom-video": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/extension-dicom-pdf": "3.10.0-beta.139", + "@ohif/extension-dicom-video": "3.10.0-beta.139", }, }, "modes/tmtv": { "name": "@ohif/mode-tmtv", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -568,18 +568,18 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/extension-dicom-pdf": "3.10.0-beta.138", - "@ohif/extension-dicom-video": "3.10.0-beta.138", - "@ohif/extension-measurement-tracking": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/extension-dicom-pdf": "3.10.0-beta.139", + "@ohif/extension-dicom-video": "3.10.0-beta.139", + "@ohif/extension-measurement-tracking": "3.10.0-beta.139", }, }, "platform/app": { "name": "@ohif/app", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -588,23 +588,23 @@ "@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/dicom-image-loader": "^3.7.16", "@emotion/serialize": "^1.1.3", - "@ohif/core": "3.10.0-beta.138", - "@ohif/extension-cornerstone": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.138", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.138", - "@ohif/extension-default": "3.10.0-beta.138", - "@ohif/extension-dicom-microscopy": "3.10.0-beta.138", - "@ohif/extension-dicom-pdf": "3.10.0-beta.138", - "@ohif/extension-dicom-video": "3.10.0-beta.138", - "@ohif/extension-test": "3.10.0-beta.138", - "@ohif/i18n": "3.10.0-beta.138", - "@ohif/mode-basic-dev-mode": "3.10.0-beta.138", - "@ohif/mode-longitudinal": "3.10.0-beta.138", - "@ohif/mode-microscopy": "3.10.0-beta.138", - "@ohif/mode-test": "3.10.0-beta.138", - "@ohif/ui": "3.10.0-beta.138", - "@ohif/ui-next": "3.10.0-beta.138", + "@ohif/core": "3.10.0-beta.139", + "@ohif/extension-cornerstone": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.139", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139", + "@ohif/extension-default": "3.10.0-beta.139", + "@ohif/extension-dicom-microscopy": "3.10.0-beta.139", + "@ohif/extension-dicom-pdf": "3.10.0-beta.139", + "@ohif/extension-dicom-video": "3.10.0-beta.139", + "@ohif/extension-test": "3.10.0-beta.139", + "@ohif/i18n": "3.10.0-beta.139", + "@ohif/mode-basic-dev-mode": "3.10.0-beta.139", + "@ohif/mode-longitudinal": "3.10.0-beta.139", + "@ohif/mode-microscopy": "3.10.0-beta.139", + "@ohif/mode-test": "3.10.0-beta.139", + "@ohif/ui": "3.10.0-beta.139", + "@ohif/ui-next": "3.10.0-beta.139", "@svgr/webpack": "^8.1.0", "@types/react": "^18.3.3", "classnames": "^2.3.2", @@ -645,7 +645,7 @@ }, "platform/cli": { "name": "@ohif/cli", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "bin": { "ohif-cli": "src/index.js", }, @@ -669,7 +669,7 @@ }, "platform/core": { "name": "@ohif/core", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "dcmjs": "*", @@ -695,14 +695,14 @@ "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/dicom-image-loader": "^3.7.16", - "@ohif/ui": "3.10.0-beta.138", + "@ohif/ui": "3.10.0-beta.139", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21", }, }, "platform/i18n": { "name": "@ohif/i18n", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@babel/runtime": "^7.20.13", "i18next-locize-backend": "^2.0.0", @@ -727,7 +727,7 @@ }, "platform/ui": { "name": "@ohif/ui", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@testing-library/react": "^13.1.0", "browser-detect": "^0.2.28", @@ -787,7 +787,7 @@ }, "platform/ui-next": { "name": "@ohif/ui-next", - "version": "3.10.0-beta.138", + "version": "3.10.0-beta.139", "dependencies": { "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-checkbox": "^1.1.1", diff --git a/extensions/default/src/ViewerLayout/ViewerHeader.tsx b/extensions/default/src/ViewerLayout/ViewerHeader.tsx index 65ecce4da..e2dce512d 100644 --- a/extensions/default/src/ViewerLayout/ViewerHeader.tsx +++ b/extensions/default/src/ViewerLayout/ViewerHeader.tsx @@ -7,7 +7,7 @@ import { useSystem } from '@ohif/core'; import { Toolbar } from '../Toolbar/Toolbar'; import HeaderPatientInfo from './HeaderPatientInfo'; import { PatientInfoVisibility } from './HeaderPatientInfo/HeaderPatientInfo'; -import { preserveQueryParameters, publicUrl } from '@ohif/app'; +import { preserveQueryParameters } from '@ohif/app'; function ViewerHeader({ appConfig }: withAppTypes<{ appConfig: AppTypes.Config }>) { const { servicesManager, extensionManager, commandsManager } = useSystem(); @@ -30,7 +30,7 @@ function ViewerHeader({ appConfig }: withAppTypes<{ appConfig: AppTypes.Config } preserveQueryParameters(searchQuery); navigate({ - pathname: publicUrl, + pathname: '/', search: decodeURIComponent(searchQuery.toString()), }); }; diff --git a/platform/app/.webpack/webpack.pwa.js b/platform/app/.webpack/webpack.pwa.js index 1d11c0dff..1a127a208 100644 --- a/platform/app/.webpack/webpack.pwa.js +++ b/platform/app/.webpack/webpack.pwa.js @@ -153,6 +153,12 @@ module.exports = (env, argv) => { }, proxy: { '/dicomweb': 'http://localhost:5000', + '/dicom-microscopy-viewer': { + target: 'http://localhost:3000', + pathRewrite: { + '^/dicom-microscopy-viewer': `/${PUBLIC_URL}/dicom-microscopy-viewer`, + }, + }, }, static: [ { diff --git a/platform/app/.webpack/writePluginImportsFile.js b/platform/app/.webpack/writePluginImportsFile.js index 29accd913..ad02e63f0 100644 --- a/platform/app/.webpack/writePluginImportsFile.js +++ b/platform/app/.webpack/writePluginImportsFile.js @@ -1,7 +1,6 @@ const pluginConfig = require('../pluginConfig.json'); const fs = require('fs'); const os = require('os'); -const glob = require('glob'); const autogenerationDisclaimer = ` // THIS FILE IS AUTOGENERATED AS PART OF THE EXTENSION AND MODE PLUGIN PROCESS. @@ -9,6 +8,12 @@ const autogenerationDisclaimer = ` const extractName = val => (typeof val === 'string' ? val : val.packageName); +const publicURL = process.env.PUBLIC_URL || '/'; + +function isAbsolutePath(path) { + return path.startsWith('http') || path.startsWith('/'); +} + function constructLines(input, categoryName) { let pluginCount = 0; @@ -72,7 +77,7 @@ function getRuntimeLoadModesExtensions(modules) { if (module.importPath) { dynamicLoad.push( ` if( module==="${packageName}") {`, - ` const imported = await window.browserImportFunction('${module.importPath}');`, + ` const imported = await window.browserImportFunction('${isAbsolutePath(module.importPath) ? '' : publicURL}${module.importPath}');`, ' return ' + (module.globalName ? `window["${module.globalName}"];` diff --git a/platform/app/public/config/aws.js b/platform/app/public/config/aws.js index be11fa859..5cd5f27d8 100644 --- a/platform/app/public/config/aws.js +++ b/platform/app/public/config/aws.js @@ -1,7 +1,7 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: [], showStudyList: true, diff --git a/platform/app/public/config/customization.js b/platform/app/public/config/customization.js index aee6a23ee..b1467b5cd 100644 --- a/platform/app/public/config/customization.js +++ b/platform/app/public/config/customization.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: ['@ohif/mode-test'], showStudyList: true, diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index 3da8ed66d..f612dc978 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -2,7 +2,7 @@ window.config = { name: 'config/default.js', - routerBasename: '/', + routerBasename: null, // whiteLabeling: {}, extensions: [], modes: [], diff --git a/platform/app/public/config/default_16bit.js b/platform/app/public/config/default_16bit.js index 6c08bd24b..1dfb9a829 100644 --- a/platform/app/public/config/default_16bit.js +++ b/platform/app/public/config/default_16bit.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, // whiteLabeling: {}, extensions: [], modes: [], diff --git a/platform/app/public/config/demo.js b/platform/app/public/config/demo.js index 791a5c3b7..4d780b698 100644 --- a/platform/app/public/config/demo.js +++ b/platform/app/public/config/demo.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, modes: [], extensions: [], showStudyList: true, diff --git a/platform/app/public/config/deprecated/docker_openresty-orthanc-keycloak.js b/platform/app/public/config/deprecated/docker_openresty-orthanc-keycloak.js index d93a853d1..d9d5b62ce 100644 --- a/platform/app/public/config/deprecated/docker_openresty-orthanc-keycloak.js +++ b/platform/app/public/config/deprecated/docker_openresty-orthanc-keycloak.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, showStudyList: true, extensions: [], modes: [], diff --git a/platform/app/public/config/deprecated/docker_openresty-orthanc.js b/platform/app/public/config/deprecated/docker_openresty-orthanc.js index 1acdff504..0694cbb42 100644 --- a/platform/app/public/config/deprecated/docker_openresty-orthanc.js +++ b/platform/app/public/config/deprecated/docker_openresty-orthanc.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, showStudyList: true, extensions: [], modes: [], diff --git a/platform/app/public/config/dicomweb-server.js b/platform/app/public/config/dicomweb-server.js index 874e7507d..e08fae42d 100644 --- a/platform/app/public/config/dicomweb-server.js +++ b/platform/app/public/config/dicomweb-server.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: [], showStudyList: true, diff --git a/platform/app/public/config/dicomweb_relative.js b/platform/app/public/config/dicomweb_relative.js index a814ac9cb..115f5bd87 100644 --- a/platform/app/public/config/dicomweb_relative.js +++ b/platform/app/public/config/dicomweb_relative.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: [], showStudyList: true, diff --git a/platform/app/public/config/docker-nginx-dcm4chee.js b/platform/app/public/config/docker-nginx-dcm4chee.js index b44f35788..9f8ed6ecf 100644 --- a/platform/app/public/config/docker-nginx-dcm4chee.js +++ b/platform/app/public/config/docker-nginx-dcm4chee.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, showStudyList: true, extensions: [], modes: [], diff --git a/platform/app/public/config/docker-nginx-orthanc.js b/platform/app/public/config/docker-nginx-orthanc.js index f4be9f944..90abe162e 100644 --- a/platform/app/public/config/docker-nginx-orthanc.js +++ b/platform/app/public/config/docker-nginx-orthanc.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, showStudyList: true, extensions: [], modes: [], diff --git a/platform/app/public/config/e2e.js b/platform/app/public/config/e2e.js index 0173175f4..9ec0095c4 100644 --- a/platform/app/public/config/e2e.js +++ b/platform/app/public/config/e2e.js @@ -17,7 +17,7 @@ if (window.location.search === '?today') { /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: ['@ohif/mode-test'], showStudyList: true, diff --git a/platform/app/public/config/google.js b/platform/app/public/config/google.js index 08799ff84..ea2e7637f 100644 --- a/platform/app/public/config/google.js +++ b/platform/app/public/config/google.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, enableGoogleCloudAdapter: false, // below flag is for performance reasons, but it might not work for all servers showWarningMessageForCrossOrigin: true, diff --git a/platform/app/public/config/idc.js b/platform/app/public/config/idc.js index 3a4e55038..a99f5315d 100644 --- a/platform/app/public/config/idc.js +++ b/platform/app/public/config/idc.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, enableGoogleCloudAdapter: true, // below flag is for performance reasons, but it might not work for all servers showWarningMessageForCrossOrigin: true, diff --git a/platform/app/public/config/kheops.js b/platform/app/public/config/kheops.js index d700b961c..1c32f20e2 100644 --- a/platform/app/public/config/kheops.js +++ b/platform/app/public/config/kheops.js @@ -2,7 +2,7 @@ window.config = { name: 'config/kheops.js', - routerBasename: '/', + routerBasename: null, extensions: [], modes: ['@ohif/mode-test'], customizationService: {}, diff --git a/platform/app/public/config/local_dcm4chee.js b/platform/app/public/config/local_dcm4chee.js index 1e223a4b9..054c12b73 100644 --- a/platform/app/public/config/local_dcm4chee.js +++ b/platform/app/public/config/local_dcm4chee.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, showStudyList: true, extensions: [], modes: [], diff --git a/platform/app/public/config/local_orthanc.js b/platform/app/public/config/local_orthanc.js index 68d3b9b02..838ee8816 100644 --- a/platform/app/public/config/local_orthanc.js +++ b/platform/app/public/config/local_orthanc.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: [], showStudyList: true, diff --git a/platform/app/public/config/local_static.js b/platform/app/public/config/local_static.js index 696632ddb..32f3b3540 100644 --- a/platform/app/public/config/local_static.js +++ b/platform/app/public/config/local_static.js @@ -1,6 +1,6 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, customizationService: ['@ohif/extension-default.customizationModule.helloPage'], extensions: [], modes: [], diff --git a/platform/app/public/config/multiple.js b/platform/app/public/config/multiple.js index 762c14c73..a20601be8 100644 --- a/platform/app/public/config/multiple.js +++ b/platform/app/public/config/multiple.js @@ -3,7 +3,7 @@ window.config = { // Activate the new HP mode.... isNewHP: true, - routerBasename: '/', + routerBasename: null, customizationService: [ '@ohif/extension-default.customizationModule.datasources', { diff --git a/platform/app/public/config/netlify.js b/platform/app/public/config/netlify.js index 6b4e3b9cf..a7eec5684 100644 --- a/platform/app/public/config/netlify.js +++ b/platform/app/public/config/netlify.js @@ -1,7 +1,7 @@ /** @type {AppTypes.Config} */ window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: [], showStudyList: true, diff --git a/platform/app/public/config/public_dicomweb.js b/platform/app/public/config/public_dicomweb.js index 9f1eb764d..76c803d6a 100644 --- a/platform/app/public/config/public_dicomweb.js +++ b/platform/app/public/config/public_dicomweb.js @@ -1,5 +1,5 @@ window.config = { - routerBasename: '/', + routerBasename: null, showStudyList: true, // below flag is for performance reasons, but it might not work for all servers showWarningMessageForCrossOrigin: true, diff --git a/platform/app/src/App.tsx b/platform/app/src/App.tsx index 851582860..2160ea539 100644 --- a/platform/app/src/App.tsx +++ b/platform/app/src/App.tsx @@ -53,7 +53,7 @@ function App({ * Hosted at: https://ohif.org/where-i-host-the/viewer/ * Value: `/where-i-host-the/viewer/` * */ - routerBaseName: '/', + routerBasename: '/', /** * */ diff --git a/platform/app/src/index.js b/platform/app/src/index.js index 4600014b8..14230134d 100644 --- a/platform/app/src/index.js +++ b/platform/app/src/index.js @@ -17,15 +17,16 @@ import React from 'react'; */ import { modes as defaultModes, extensions as defaultExtensions } from './pluginImports'; import loadDynamicConfig from './loadDynamicConfig'; +import { publicUrl } from './utils/publicUrl'; export { history } from './utils/history'; export { preserveQueryParameters, preserveQueryStrings } from './utils/preserveQueryParameters'; -export { publicUrl } from './utils/publicUrl'; loadDynamicConfig(window.config).then(config_json => { // Reset Dynamic config if defined if (config_json !== null) { window.config = config_json; } + window.config.routerBasename ||= publicUrl; /** * Combine our appConfiguration with installed extensions and modes. diff --git a/platform/app/src/routes/WorkList/WorkList.tsx b/platform/app/src/routes/WorkList/WorkList.tsx index 685342ac9..5d5fbe772 100644 --- a/platform/app/src/routes/WorkList/WorkList.tsx +++ b/platform/app/src/routes/WorkList/WorkList.tsx @@ -11,7 +11,7 @@ import filtersMeta from './filtersMeta.js'; import { useAppConfig } from '@state'; import { useDebounce, useSearchParams } from '@hooks'; import { utils } from '@ohif/core'; -import publicUrl from '../../utils/publicUrl'; +import { routerBasename } from '../../utils/publicUrl'; import { StudyListExpandedRow, @@ -209,7 +209,7 @@ function WorkList({ skipEmptyString: true, }); navigate({ - pathname: publicUrl, + pathname: '/', search: search ? `?${search}` : undefined, }); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -417,7 +417,7 @@ function WorkList({ { // In case any event bubbles up for an invalid mode, prevent the navigation. // For example, the event bubbles up when the icon embedded in the disabled button is clicked. diff --git a/platform/app/src/routes/buildModeRoutes.tsx b/platform/app/src/routes/buildModeRoutes.tsx index 2e60d42a4..6dca1896a 100644 --- a/platform/app/src/routes/buildModeRoutes.tsx +++ b/platform/app/src/routes/buildModeRoutes.tsx @@ -1,6 +1,5 @@ import React from 'react'; import ModeRoute from '@routes/Mode'; -import publicUrl from '../utils/publicUrl'; /* Routes uniquely define an entry point to: @@ -43,7 +42,7 @@ export default function buildModeRoutes({ modes.forEach(mode => { // todo: for each route. add route to path. dataSourceNames.forEach(dataSourceName => { - const path = `${publicUrl}${mode.routeName}/${dataSourceName}`; + const path = `${mode.routeName}/${dataSourceName}`; // TODO move up. const children = () => ( @@ -66,7 +65,7 @@ export default function buildModeRoutes({ // Add active DataSource route. // This is the DataSource route for the active data source defined in ExtensionManager.getActiveDataSource - const path = `${publicUrl}${mode.routeName}`; + const path = `${mode.routeName}`; // TODO move up. const children = () => ( diff --git a/platform/app/src/routes/index.tsx b/platform/app/src/routes/index.tsx index 1dd0c634f..138642a4d 100644 --- a/platform/app/src/routes/index.tsx +++ b/platform/app/src/routes/index.tsx @@ -11,7 +11,7 @@ import NotFound from './NotFound'; import buildModeRoutes from './buildModeRoutes'; import PrivateRoute from './PrivateRoute'; import PropTypes from 'prop-types'; -import publicUrl from '../utils/publicUrl'; +import { routerBase, routerBasename } from '../utils/publicUrl'; const NotFoundServer = ({ message = 'Unable to query for studies at this time. Check your data source configuration or network connection', @@ -55,23 +55,23 @@ NotFoundStudy.propTypes = { // TODO: Include "routes" debug route if dev build const bakedInRoutes = [ { - path: `${publicUrl}notfoundserver`, + path: `/notfoundserver`, children: NotFoundServer, }, { - path: `${publicUrl}notfoundstudy`, + path: `/notfoundstudy`, children: NotFoundStudy, }, { - path: `${publicUrl}debug`, + path: `/debug`, children: Debug, }, { - path: `${publicUrl}local`, + path: `/local`, children: Local.bind(null, { modePath: '' }), // navigate to the worklist }, { - path: `${publicUrl}localbasic`, + path: `/localbasic`, children: Local.bind(null, { modePath: 'viewer/dicomlocal' }), }, ]; @@ -86,7 +86,6 @@ const createRoutes = ({ servicesManager, commandsManager, hotkeysManager, - routerBasename, showStudyList, }: withAppTypes) => { const routes = @@ -101,8 +100,15 @@ const createRoutes = ({ const { customizationService } = servicesManager.services; + const path = + routerBasename.length > 1 && routerBasename.endsWith('/') + ? routerBasename.substring(0, routerBasename.length - 1) + : routerBasename; + + console.log('Registering worklist route', routerBasename, path); + const WorkListRoute = { - path: publicUrl, + path: '/', children: DataSourceWrapper, private: true, props: { children: WorkList, servicesManager, extensionManager }, @@ -113,7 +119,6 @@ const createRoutes = ({ const allRoutes = [ ...routes, ...(showStudyList ? [WorkListRoute] : []), - ...(publicUrl !== '/' && showStudyList ? [{ ...WorkListRoute, path: publicUrl }] : []), ...(customRoutes?.routes || []), ...bakedInRoutes, customRoutes?.notFoundRoute || notFoundRoute, diff --git a/platform/app/src/utils/preserveQueryParameters.ts b/platform/app/src/utils/preserveQueryParameters.ts index 405e9b93a..f50e978ad 100644 --- a/platform/app/src/utils/preserveQueryParameters.ts +++ b/platform/app/src/utils/preserveQueryParameters.ts @@ -5,7 +5,7 @@ function preserve(query, current, key) { } } -export const preserveKeys = ['configUrl', 'multimonitor', 'screenNumber']; +export const preserveKeys = ['configUrl', 'multimonitor', 'screenNumber', 'hangingProtocolId']; export function preserveQueryParameters( query, diff --git a/platform/app/src/utils/publicUrl.ts b/platform/app/src/utils/publicUrl.ts index 47ed7c697..489319ad5 100644 --- a/platform/app/src/utils/publicUrl.ts +++ b/platform/app/src/utils/publicUrl.ts @@ -1,4 +1,6 @@ const publicUrl = (window as any).PUBLIC_URL || '/'; +const routerBasename = (window as any).config?.routerBasename || publicUrl; + +export { publicUrl, routerBasename }; export default publicUrl; -export { publicUrl }; diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index db24e8da9..d3289dbb0 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -28,7 +28,7 @@ The simplest way is to update the existing default config: ```js title="platform/app/public/config/default.js" window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: [], showStudyList: true, @@ -81,7 +81,7 @@ window.config = ({ servicesManager } = {}) => { } }, }, - routerBasename: '/', + routerBasename: null, dataSources: [ { namespace: '@ohif/extension-default.dataSourcesModule.dicomweb', diff --git a/platform/docs/docs/configuration/dataSources/dicom-web.md b/platform/docs/docs/configuration/dataSources/dicom-web.md index 82fb703a1..2707370fe 100644 --- a/platform/docs/docs/configuration/dataSources/dicom-web.md +++ b/platform/docs/docs/configuration/dataSources/dicom-web.md @@ -123,7 +123,7 @@ configuration looks like: ```js window.config = { - routerBasename: '/', + routerBasename: null, extensions: [], modes: [], showStudyList: true, diff --git a/platform/docs/docs/deployment/custom-url-access.md b/platform/docs/docs/deployment/custom-url-access.md index dfb1ddd61..c4639aedf 100644 --- a/platform/docs/docs/deployment/custom-url-access.md +++ b/platform/docs/docs/deployment/custom-url-access.md @@ -4,62 +4,113 @@ title: Custom URL Access/Build --- -## Build for non-root path +# Hosting the Web Viewer on a Custom URL Path -Sometimes it is desired to access the viewer from a non-root path (e.g., `/my-awesome-viewer` instead of `/`). -You can achieve so by using the `PUBLIC_URL` environment variable AND the `routerBasename` configuration option. - -1. use a config (e.g. `config/myConfig.js`) file that is using the `routerBasename` of your choice `/my-awesome-viewer` (note there is only one / - it is not /my-awesome-viewer/). -2. build the viewer with `PUBLIC_URL=/my-awesome-viewer/` (note there are two / - it is not /my-awesome-viewer). +You can host the viewer on a subpath like `/abc` instead of the root `/`. There are **two levels** of customization depending on how you want to serve your static assets. -:::tip -The PUBLIC_URL tells the application where to find the static assets and the routerBasename will tell the application how to handle the routes -::: +## Simple Setup (Recommended for Most Use Cases) +If you want to make the viewer accessible from a custom path (e.g. `/abc`) and **don’t care where the assets are loaded from** (they’ll be fetched from the root `/`), this setup is for you. -### Testing in Development -For testing the build locally, you can use the following command: +### What You Get + +- Viewer available at `https://yourdomain.com/abc` +- All assets (JS, WASM, etc.) still loaded from the root (`/app.js`, `/viewer.wasm`, etc.) + +### How To Set It Up + +1. Set `routerBasename` in your config file (e.g., `config/myConfig.js`) to `/abc` +2. Build the viewer with: ```bash -# we use default config file, so we assume you have already set the routerBasename to /my-awesome-viewer in the default config as an example -PUBLIC_URL=/my-awesome-viewer/ APP_CONFIG=config/default.js yarn dev +APP_CONFIG=config/myConfig.js yarn build ``` - -### Testing in Build (production) -You need to build the viewer with the following command: +### Local Development ```bash -PUBLIC_URL=/my-awesome-viewer/ APP_CONFIG=config/default.js yarn build +APP_CONFIG=config/myConfig.js yarn dev ``` -We can use the `npx serve` to serve the build folder. There are two things you need to consider however, -1. You need to change the `public/serve.json` file to reflect the new routerBasename in the destination (see the example below) +--- +## Advanced Setup (Custom Asset Path) -```json -// final serve.json -{ - "rewrites": [{ "source": "*", "destination": "my-awesome-viewer/index.html" }], +If you want to host the viewer at `/abc` **and** serve static assets from a different location (e.g. `/my-private-assets`), this is a more advanced scenario. + +### What You Get + +- Viewer accessible from `https://yourdomain.com/abc` +- All assets loaded from `https://yourdomain.com/my-private-assets/` + +### Why This is Tricky + +Some libraries (especially ones using WASM) load assets using **relative paths**, which can break if not handled carefully. To solve this: + +- Set `routerBasename` to `/abc` +- Set `PUBLIC_URL` to `/my-private-assets/` +- Webpack will load assets from the specified public URL. + +### Local Development Notes + +In development, use proxy rewrites to handle relative asset paths. Example for `dicom-microscopy-viewer`: + +```js +proxy: { + '/dicom-microscopy-viewer': { + target: 'http://localhost:3000', + pathRewrite: { + '^/dicom-microscopy-viewer': `/${PUBLIC_URL}/dicom-microscopy-viewer`, + }, + }, } ``` +This ensures local development can find assets even when libraries expect them at certain paths. + + +### Building and Serving in Production + +To build the viewer for production: + ```bash -cd platform/app; - -# rename the dist folder to my-awesome-viewer -mv dist my-awesome-viewer - -# serve the folder with custom json, note that we are using ../public/serve.json and NOT public/serve.json -npx serve -c ./public/serve.json +PUBLIC_URL=/my-private-assets/ APP_CONFIG=config/myConfig.js yarn build ``` +If you're using `npx serve`, make sure to update `serve.json`: -:::note -When you want to authenticate against a sub path, there are a few things you should keep in mind: +```json +{ + "rewrites": [{ "source": "*", "destination": "/abc/index.html" }] +} +``` -1. Set the `routerBasename` to the sub path and also update the `PUBLIC_URL` to match the sub path. -2. Don't forget to modify the `serve.json` file as mentioned earlier. -3. Ensure that the sub path is included in the list of allowed callback URLs. For example, in the Google Cloud dashboard, you can set it in the `Authorized redirect URIs` field under the `Credentials` section of the `APIs & Services` menu. -::: +Serve the viewer like this: + +```bash +cd platform/app +mv dist abc # Rename dist folder to match your viewer route +npx serve -c ./public/serve.json +``` + +--- + +### 🐳 Using Docker? You're Covered + +If you’re using our Dockerfile, you’re all set — it already handles copying specific asset folders (like `dicom-microscopy-viewer`) to the root: + +```Dockerfile +COPY --from=builder /usr/src/app/platform/app/dist/dicom-microscopy-viewer /usr/share/nginx/html/dicom-microscopy-viewer +``` + +Keep an eye on the browser network tab for any assets that might fail to load — if any other libraries require similar treatment, you’ll need to handle those as well. + +--- + +## Summary + +| Goal | routerBasename | PUBLIC_URL | Assets Load From | +|-----------------------------------|----------------|-----------------------|--------------------------| +| Viewer at `/abc`, assets from `/` | `/abc` | default | Root `/` | +| Viewer at `/abc`, assets from `/my-private-assets` | `/abc` | `/my-private-assets/` | `/my-private-assets/` | diff --git a/platform/docs/docs/platform/environment-variables.md b/platform/docs/docs/platform/environment-variables.md index 1b08d5492..df5da9e03 100644 --- a/platform/docs/docs/platform/environment-variables.md +++ b/platform/docs/docs/platform/environment-variables.md @@ -12,6 +12,7 @@ NODE_ENV=< production | development > DEBUG=< true | false > APP_CONFIG=< relative path to application configuration file > PUBLIC_URL=< relative path to application root - default / > +ROUTER_BASENAME=< relative path to application root - default PUBLIC_URL > VERSION_NUMBER= BUILD_NUM= # i18n diff --git a/platform/docs/docs/platform/services/customization-service/customizationService.md b/platform/docs/docs/platform/services/customization-service/customizationService.md index cda486984..afb57f2ff 100644 --- a/platform/docs/docs/platform/services/customization-service/customizationService.md +++ b/platform/docs/docs/platform/services/customization-service/customizationService.md @@ -172,7 +172,7 @@ Customizations can be declared at three different scopes, each with its own prio ```jsx window.config = { name: 'config/default.js', - routerBasename: '/', + routerBasename: null, customizationService: [ { 'studyBrowser.sortFunctions': { @@ -194,7 +194,7 @@ Customizations can be declared at three different scopes, each with its own prio ```jsx window.config = { name: 'config/default.js', - routerBasename: '/', + routerBasename: null, customizationService: [ '@ohif/extension-cornerstone.customizationModule.newCustomization', ],