diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98ff32775c62db929d9bcd1087e89d60eaee393c..4f5aae140737373d936e7ac92d277f3389f8357b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,8 +39,8 @@ jobs: - run: | if [[ "$GITHUB_REF" = *hotfix* ]] then - export BS_REST_URL=https://siibra-api-rc.apps.hbp.eu/v2_0 - echo 'export const environment = { "BS_REST_URL": "https://siibra-api-rc.apps.hbp.eu/v2_0" }' > src/environments/environment.common.ts + export SIIBRA_API_ENDPOINTS=https://siibra-api-rc.apps.hbp.eu/v2_0 + echo 'export const environment = { "SIIBRA_API_ENDPOINTS": "https://siibra-api-rc.apps.hbp.eu/v2_0" }' > src/environments/environment.common.ts fi npm run test-ci diff --git a/.github/workflows/docker_img.yml b/.github/workflows/docker_img.yml index 47734fc27ba6540ee111646142553af53a365798..a25d30c92fe0636dc593c859e224eead06025d52 100644 --- a/.github/workflows/docker_img.yml +++ b/.github/workflows/docker_img.yml @@ -18,7 +18,7 @@ jobs: PRODUCTION: 'true' DOCKER_REGISTRY: 'docker-registry.ebrains.eu/siibra/' - SIIBRA_API_STABLE: 'https://siibra-api-stable.apps.hbp.eu/v2_0' + SIIBRA_API_STABLE: 'https://siibra-api-stable.apps.hbp.eu/v2_0,https://siibra-api-stable-ns.apps.hbp.eu/v2_0,https://siibra-api-stable.apps.jsc.hbp.eu/v2_0' SIIBRA_API_RC: 'https://siibra-api-rc.apps.hbp.eu/v2_0' SIIBRA_API_LATEST: 'https://siibra-api-latest.apps-dev.hbp.eu/v2_0' @@ -37,19 +37,19 @@ jobs: if [[ "$GITHUB_REF" == 'refs/heads/master' ]] then echo "Either master, using prod env..." - echo "BS_REST_URL=${{ env.SIIBRA_API_STABLE }}" >> $GITHUB_ENV + echo "SIIBRA_API_ENDPOINTS=${{ env.SIIBRA_API_STABLE }}" >> $GITHUB_ENV elif [[ "$GITHUB_REF" == 'refs/heads/staging' ]] then echo "Either staging, using staging env..." - echo "BS_REST_URL=${{ env.SIIBRA_API_RC }}" >> $GITHUB_ENV + echo "SIIBRA_API_ENDPOINTS=${{ env.SIIBRA_API_RC }}" >> $GITHUB_ENV else if [[ "$GITHUB_REF" == *hotfix* ]] then echo "Hotfix branch, using prod env..." - echo "BS_REST_URL=${{ env.SIIBRA_API_RC }}" >> $GITHUB_ENV + echo "SIIBRA_API_ENDPOINTS=${{ env.SIIBRA_API_RC }}" >> $GITHUB_ENV else echo "Using dev env..." - echo "BS_REST_URL=${{ env.SIIBRA_API_LATEST }}" >> $GITHUB_ENV + echo "SIIBRA_API_ENDPOINTS=${{ env.SIIBRA_API_LATEST }}" >> $GITHUB_ENV fi fi @@ -78,7 +78,7 @@ jobs: --build-arg VERSION=$VERSION \ --build-arg MATOMO_URL=$MATOMO_URL \ --build-arg MATOMO_ID=$MATOMO_ID \ - --build-arg BS_REST_URL=$BS_REST_URL \ + --build-arg SIIBRA_API_ENDPOINTS=$SIIBRA_API_ENDPOINTS \ --build-arg EXPERIMENTAL_FEATURE_FLAG=$EXPERIMENTAL_FEATURE_FLAG \ -t $DOCKER_BUILT_TAG \ . diff --git a/Dockerfile b/Dockerfile index 4269dcc5655ad6683086ed86057ac43248ef6dbb..8ad7624403cf18aa021e133e2926d1fc1f616b04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,8 @@ FROM node:14 as builder ARG BACKEND_URL ENV BACKEND_URL=${BACKEND_URL} -ARG BS_REST_URL -ENV BS_REST_URL=${BS_REST_URL:-https://siibra-api-stable.apps.hbp.eu/v1_0} +ARG SIIBRA_API_ENDPOINTS +ENV SIIBRA_API_ENDPOINTS=${SIIBRA_API_ENDPOINTS:-https://siibra-api-stable.apps.hbp.eu/v2_0,https://siibra-api-stable-ns.apps.hbp.eu/v2_0,https://siibra-api-stable.apps.jsc.hbp.eu/v2_0} ARG STRICT_LOCAL ENV STRICT_LOCAL=${STRICT_LOCAL:-false} diff --git a/build_env.md b/build_env.md index 1c29ea98614c3a40dbe91d7c620f9e6a5356b4e8..fa8ed9e3951cdabd2cfa2f26bd46c5904e74af14 100644 --- a/build_env.md +++ b/build_env.md @@ -7,7 +7,8 @@ As interactive atlas viewer uses [webpack define plugin](https://webpack.js.org/ | `VERSION` | printed in console on viewer startup | `GIT_HASH` \|\| unspecificed hash | v2.2.2 | | `PRODUCTION` | if the build is for production, toggles optimisations such as minification | `undefined` | true | | `BACKEND_URL` | backend that the viewer calls to fetch available template spaces, parcellations, plugins, datasets | `null` | https://interactive-viewer.apps.hbp.eu/ | -| `BS_REST_URL` | [siibra-api](https://github.com/FZJ-INM1-BDA/siibra-api) used to fetch different resources | https://siibra-api-stable.apps.hbp.eu/v1_0 | +| ~~`BS_REST_URL`~~ _deprecated. use `SIIBRA_API_ENDPOINTS` instead_ | [siibra-api](https://github.com/FZJ-INM1-BDA/siibra-api) used to fetch different resources | `https://siibra-api-stable.apps.hbp.eu/v1_0` | +| `SIIBRA_API_ENDPOINTS` | Comma separated endpoints of [siibra-api](https://github.com/FZJ-INM1-BDA/siibra-api) used to fetch different resources | `https://siibra-api-stable.apps.hbp.eu/v2_0,https://siibra-api-stable-ns.apps.hbp.eu/v2_0,https://siibra-api-stable.apps.jsc.hbp.eu/v2_0` | | `MATOMO_URL` | base url for matomo analytics | `null` | https://example.com/matomo/ | | `MATOMO_ID` | application id for matomo analytics | `null` | 6 | | `STRICT_LOCAL` | hides **Explore** and **Download** buttons. Useful for offline demo's | `false` | `true` | diff --git a/docs/releases/v2.7.3.md b/docs/releases/v2.7.3.md index 8034c954c4ebb722ce7f074f13a8cb48fef08d43..9758f42e555828325155789ec99f724dde136b42 100644 --- a/docs/releases/v2.7.3.md +++ b/docs/releases/v2.7.3.md @@ -7,3 +7,4 @@ ## Under the hood - minor refactor of unused code +- added mirrors to siibra-api diff --git a/src/atlasComponents/sapi/module.ts b/src/atlasComponents/sapi/module.ts index a64cc8bc817f05c801cde40d58a95d93c1d198a1..6d0757bb5e771b5bb18e9009bc9032f399fa0c38 100644 --- a/src/atlasComponents/sapi/module.ts +++ b/src/atlasComponents/sapi/module.ts @@ -1,4 +1,4 @@ -import { NgModule } from "@angular/core"; +import { APP_INITIALIZER, NgModule } from "@angular/core"; import { SAPI } from "./sapi.service"; import { CommonModule } from "@angular/common"; import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http"; @@ -21,6 +21,11 @@ import { MatSnackBarModule } from "@angular/material/snack-bar"; provide: HTTP_INTERCEPTORS, useClass: PriorityHttpInterceptor, multi: true + }, + { + provide: APP_INITIALIZER, + useValue: () => SAPI.SetBsEndPoint(), + multi: true } ] }) diff --git a/src/atlasComponents/sapi/sapi.service.spec.ts b/src/atlasComponents/sapi/sapi.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..297105f3fc148a1b6a1f3fb01f39d88ec0983cfb --- /dev/null +++ b/src/atlasComponents/sapi/sapi.service.spec.ts @@ -0,0 +1,78 @@ +import * as env from "src/environments/environment" +import { SAPI } from "./sapi.service" + +describe("> sapi.service.ts", () => { + describe("> SAPI", () => { + describe("#SetBsEndPoint", () => { + let fetchSpy: jasmine.Spy + let environmentSpy: jasmine.Spy + + const endpt1 = 'foo-bar' + const endpt2 = 'buzz-bizz' + + const atlas1 = 'foo' + const atlas2 = 'bar' + + + beforeEach(() => { + fetchSpy = spyOn(window, 'fetch') + fetchSpy.and.rejectWith("foo-bar") + + environmentSpy = spyOnProperty(env, 'environment') + environmentSpy.and.returnValue({ + SIIBRA_API_ENDPOINTS: `${endpt1},${endpt2}` + }) + }) + + afterEach(() => { + fetchSpy.calls.reset() + environmentSpy.calls.reset() + }) + + describe("> first passes", () => { + beforeEach(() => { + const resp = new Response(JSON.stringify([atlas1]), { headers: { 'content-type': 'application/json' }, status: 200 }) + fetchSpy.and.resolveTo(resp) + }) + it("> should call fetch once", async () => { + await SAPI.SetBsEndPoint() + expect(fetchSpy).toHaveBeenCalledTimes(1) + expect(fetchSpy).toHaveBeenCalledOnceWith(`${endpt1}/atlases`) + }) + + it("> endpoint should be set", async () => { + await SAPI.SetBsEndPoint() + expect(SAPI.bsEndpoint).toBe(endpt1) + }) + }) + + describe("> first fails", () => { + beforeEach(() => { + let counter = 0 + fetchSpy.and.callFake(async () => { + if (counter === 0) { + counter ++ + throw new Error(`bla`) + } + const resp = new Response(JSON.stringify([atlas1]), { headers: { 'content-type': 'application/json' }, status: 200 }) + return resp + }) + }) + + it("> should call twice", async () => { + await SAPI.SetBsEndPoint() + expect(fetchSpy).toHaveBeenCalledTimes(2) + expect(fetchSpy.calls.allArgs()).toEqual([ + [`${endpt1}/atlases`], + [`${endpt2}/atlases`], + ]) + }) + + it('> should set endpt2', async () => { + await SAPI.SetBsEndPoint() + expect(SAPI.bsEndpoint).toBe(endpt2) + }) + }) + }) + }) +}) diff --git a/src/atlasComponents/sapi/sapi.service.ts b/src/atlasComponents/sapi/sapi.service.ts index 0600ef2978744509aacbd555e1ae9c5472df89ec..a3b20176f9aabd68c948d811c6582178d7b2a261 100644 --- a/src/atlasComponents/sapi/sapi.service.ts +++ b/src/atlasComponents/sapi/sapi.service.ts @@ -3,7 +3,8 @@ import { HttpClient } from '@angular/common/http'; import { map, shareReplay } from "rxjs/operators"; import { SAPIAtlas, SAPISpace } from './core' import { - SapiAtlasModel, SapiModalityModel, + SapiAtlasModel, + SapiModalityModel, SapiParcellationModel, SapiQueryPriorityArg, SapiRegionalFeatureModel, @@ -24,14 +25,34 @@ import { SAPIFeature } from "./features"; import { environment } from "src/environments/environment" export const SIIBRA_API_VERSION_HEADER_KEY='x-siibra-api-version' -export const SIIBRA_API_VERSION = '0.2.1' +export const SIIBRA_API_VERSION = '0.2.2' type RegistryType = SAPIAtlas | SAPISpace | SAPIParcellation @Injectable() export class SAPI{ - static bsEndpoint = environment.BS_REST_URL || `https://siibra-api-latest.apps-dev.hbp.eu/v2_0` + static async SetBsEndPoint() { + let idx = 0 + const siibraApiEndpts = environment.SIIBRA_API_ENDPOINTS.split(',') + while (idx < siibraApiEndpts.length) { + const url = siibraApiEndpts[idx] + try { + const resp = await fetch(`${url}/atlases`) + const atlases = await resp.json() + if (atlases.length > 0) { + SAPI.bsEndpoint = url + return + } + } catch (e) { + idx ++ + } + } + SAPI.ErrorMessage = `It appears all of our mirrors are not working. The viewer may not be working properly...` + } + + static ErrorMessage = null + static bsEndpoint = `https://siibra-api-stable.apps.hbp.eu/v2_0` public bsEndpoint = SAPI.bsEndpoint registry = { @@ -133,6 +154,9 @@ export class SAPI{ private snackbar: MatSnackBar, private workerSvc: AtlasWorkerService, ){ + if (SAPI.ErrorMessage) { + this.snackbar.open(SAPI.ErrorMessage, 'Dismiss', { duration: 5000 }) + } this.atlases$.subscribe(atlases => { for (const atlas of atlases) { for (const space of atlas.spaces) { diff --git a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts index 3889c4c3f20621280a66f92f3e37f2a4521414d0..b1efcd694501bd33796a961449fbb3fec244b28c 100644 --- a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts +++ b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts @@ -6,7 +6,6 @@ import {CUSTOM_ELEMENTS_SCHEMA, Directive, Input} from "@angular/core"; import {provideMockActions} from "@ngrx/effects/testing"; import {MockStore, provideMockStore} from "@ngrx/store/testing"; import {Observable, of} from "rxjs"; -import {BS_ENDPOINT} from "src/util/constants"; import {SAPI} from "src/atlasComponents/sapi"; import {AngularMaterialModule} from "src/sharedModules"; @@ -66,10 +65,6 @@ describe('ConnectivityComponent', () => { providers: [ provideMockActions(() => actions$), provideMockStore(), - { - provide: BS_ENDPOINT, - useValue: MOCK_BS_ENDPOINT - }, { provide: SAPI, useValue: { diff --git a/src/environments/parseEnv.js b/src/environments/parseEnv.js index b05909d596c85cc1875650602cafb8a5fa2fba3a..7b23070ca889aae07002b73c51f1549050fa369c 100644 --- a/src/environments/parseEnv.js +++ b/src/environments/parseEnv.js @@ -10,7 +10,7 @@ const main = async () => { STRICT_LOCAL, MATOMO_URL, MATOMO_ID, - BS_REST_URL, + SIIBRA_API_ENDPOINTS, VERSION, GIT_HASH = 'unknown hash', EXPERIMENTAL_FEATURE_FLAG @@ -21,7 +21,7 @@ const main = async () => { STRICT_LOCAL, MATOMO_URL, MATOMO_ID, - BS_REST_URL, + SIIBRA_API_ENDPOINTS, VERSION, GIT_HASH, EXPERIMENTAL_FEATURE_FLAG, @@ -39,7 +39,7 @@ export const environment = { ...commonEnv, GIT_HASH: ${gitHash}, VERSION: ${version}, - BS_REST_URL: ${JSON.stringify(BS_REST_URL)}, + SIIBRA_API_ENDPOINTS: ${JSON.stringify(SIIBRA_API_ENDPOINTS)}, BACKEND_URL: ${JSON.stringify(BACKEND_URL)}, STRICT_LOCAL: ${JSON.stringify(STRICT_LOCAL)}, MATOMO_URL: ${JSON.stringify(MATOMO_URL)}, diff --git a/src/main.module.ts b/src/main.module.ts index 7d26a8ee52400fa2acd8e9cbd0a670ddd06c5670..da570799012cb86e814b3760f110174c943f8f36 100644 --- a/src/main.module.ts +++ b/src/main.module.ts @@ -33,7 +33,6 @@ import { CookieModule } from './ui/cookieAgreement/module'; import { KgTosModule } from './ui/kgtos/module'; import { AtlasViewerRouterModule } from './routerModule'; import { MessagingGlue } from './messagingGlue'; -import { BS_ENDPOINT } from './util/constants'; import { QuickTourModule } from './ui/quickTour'; import { of } from 'rxjs'; import { CANCELLABLE_DIALOG, CANCELLABLE_DIALOG_OPTS } from './util/interfaces'; @@ -163,10 +162,6 @@ import { CONST } from "common/constants" provide: WINDOW_MESSAGING_HANDLER_TOKEN, useClass: MessagingGlue }, - { - provide: BS_ENDPOINT, - useValue: (environment.BS_REST_URL || `https://siibra-api-stable.apps.hbp.eu/v1_0`).replace(/\/$/, '') - }, { provide: DARKTHEME, useFactory: (store: Store) => store.pipe( diff --git a/src/util/constants.ts b/src/util/constants.ts index 5c4e7185743a1dca35e0523f076385b797fc21b5..9b1700442a02984d4b5a15c73b122d5bcc0cf8ed 100644 --- a/src/util/constants.ts +++ b/src/util/constants.ts @@ -115,7 +115,6 @@ export const compareLandmarksChanged: (prevLandmarks: any[], newLandmarks: any[] } export const CYCLE_PANEL_MESSAGE = `[spacebar] to cycle through views` -export const BS_ENDPOINT = new InjectionToken<string>('BS_ENDPOINT') export const UNSUPPORTED_PREVIEW = [{ text: 'Preview of Colin 27 and JuBrain Cytoarchitectonic',