Skip to content

Commit 4ec0b8f

Browse files
authored
Merge pull request #1501 from FZJ-INM1-BDA/staging
2.14.24
2 parents a7a9645 + 0f8816f commit 4ec0b8f

File tree

8 files changed

+137
-77
lines changed

8 files changed

+137
-77
lines changed

.prepare_release.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ async function updateCodemeta(version){
9696
// getMonth returns index 0 month...
9797
// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMonth
9898
const MM = (date.getMonth() + 1).toString().padStart(2, "0")
99-
const DD = date.getDate().toString()
99+
const DD = date.getDate().toString().padStart(2, "0")
100100

101101
codemetaContent["dateModified"] = `${YYYY}-${MM}-${DD}`
102102
await writeFile(pathToCodemeta, JSON.stringify(codemetaContent, null, 4), "utf-8")

.sop/DEPLOYMENT.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Deployment
2+
3+
This document outline the standard operating procedure of how to rollout a new release on ebrains infrastructure.
4+
5+
## Requirement
6+
7+
node v20+
8+
9+
Go to https://docker-registry.ebrains.eu/harbor/projects/28/summary , and ensure sufficient disk space (> 1GB). If insufficient:
10+
11+
- `siibra/siibra-explorer` namespace: `2.*.*` that is not the latest can be deleted
12+
- `siibra/siibra-api` namespace: `0.3.*[-worker|-worker-v4|server]` that is not the latest can be deleted
13+
- above, any untagged image can be deleted
14+
- if unsure, ask Xiao
15+
16+
(optional) Ensure siibra-api `-rc` prerelease action completes without error. Ensure in `src/atlasComponents/sapi/sapi.service.ts`, `export const EXPECTED_SIIBRA_API_VERSION = ''` is set to the expected siibra-api version.
17+
18+
## Steps
19+
20+
0. Commit any changes. (Run `npm prepare-release` if necessary) push to staging/branch and PR and merge to staging.
21+
22+
1. Raise PR from staging to master, ensure all check passes
23+
24+
2. Go through the checklist generated by github-bot. This is a manual process, and is meant to take awhile. Ensure all passes.
25+
26+
3. (if siibra-api is also updated) release siibra-api first. When all actions passes, merge staging -> master.

codemeta.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
],
9292
"codeRepository": "git+https://github.com/fzj-inm1-bda/siibra-explorer.git",
9393
"dateCreated": "2024-08-28",
94-
"dateModified": "2025-08-20",
94+
"dateModified": "2025-09-09",
9595
"datePublished": "2019-04-26",
9696
"description": "`siibra-explorer` is a browser based 3D viewer for exploring brain atlases that cover different spatial resolutions and modalities. It is built around an interactive 3D view of the brain displaying a unique selection of detailed templates and parcellation maps for the human, macaque, rat or mouse brain, including BigBrain as a microscopic resolution human brain model at its full resolution of 20 micrometers. ",
9797
"license": "https://spdx.org/licenses/Apache-2.0",
@@ -100,9 +100,9 @@
100100
"python 3",
101101
"typescript"
102102
],
103-
"schema:releaseNotes": "# v2.14.23\n\n## Feature\n\n- show messages when some error occurs (e.g. propagate region selection, spatial transformation)\n- enable von economo atlas\n- enable api select template/parcellation\n- add warning to users outside EU about perf implications\n- (experimental) enable light/dark theme toggling\n\n## Bugfixes\n\n- drag drop JSON pointcloud now checks selected template, and use the appropriate transform\n\n## Behind the scene\n\n- disentangle maps, propagate selected region when change parcellations\n",
103+
"schema:releaseNotes": "# v2.14.24\n\n## Feature\n\n- Selecting region will now navigate to the region's centroid\n- Add warning text when warping, region deselection and/or when cortical layers is selected\n\n## Behind the scene\n\n- Fix prepare_release script\n- Added SOP for ebrains deployment\n\n",
104104
"runtimePlatform": "docker",
105-
"version": "2.14.23",
105+
"version": "2.14.24",
106106
"contIntegration": "https://github.com/FZJ-INM1-BDA/siibra-explorer/actions",
107107
"codemeta:continuousIntegration": {
108108
"id": "https://github.com/FZJ-INM1-BDA/siibra-explorer/actions"

docs/releases/v2.14.24.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# v2.14.24
2+
3+
## Feature
4+
5+
- Selecting region will now navigate to the region's centroid
6+
- Add warning text when warping, region deselection and/or when cortical layers is selected
7+
8+
## Behind the scene
9+
10+
- Fix prepare_release script
11+
- Added SOP for ebrains deployment
12+

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ nav:
4646
- Plugin API: "advanced/api/README.md"
4747

4848
- Release notes:
49+
- v2.14.24: 'releases/v2.14.24.md'
4950
- v2.14.23: 'releases/v2.14.23.md'
5051
- v2.14.22: 'releases/v2.14.22.md'
5152
- v2.14.21: 'releases/v2.14.21.md'

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "siibra-explorer",
3-
"version": "2.14.23",
3+
"version": "2.14.24",
44
"description": "siibra-explorer - explore brain atlases. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular",
55
"scripts": {
66
"lint": "eslint src --ext .ts",

src/atlasComponents/sapi/sapi.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const useViewer = {
1919
} as const
2020

2121
export const SIIBRA_API_VERSION_HEADER_KEY='x-siibra-api-version'
22-
export const EXPECTED_SIIBRA_API_VERSION = '0.3.28'
22+
export const EXPECTED_SIIBRA_API_VERSION = '0.3.29'
2323

2424
type PaginatedResponse<T> = {
2525
items: T[]

src/state/atlasSelection/effects.ts

Lines changed: 92 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Component, Inject, Injectable, InjectionToken, Injector } from "@angular/core";
22
import { Actions, createEffect, ofType } from "@ngrx/effects";
3-
import { combineLatest, concat, EMPTY, forkJoin, from, NEVER, Observable, of, throwError, TimeoutError } from "rxjs";
3+
import { combineLatest, concat, forkJoin, from, NEVER, Observable, of, throwError, TimeoutError } from "rxjs";
44
import { catchError, debounceTime, distinctUntilChanged, filter, map, mapTo, switchMap, take, timeout, withLatestFrom } from "rxjs/operators";
55
import { IDS, SAPI } from "src/atlasComponents/sapi";
66
import * as mainActions from "../actions"
77
import { select, Store } from "@ngrx/store";
88
import { selectors, actions, fromRootStore } from '.'
99
import { AtlasSelectionState } from "./const"
10-
import { atlasAppearance, atlasSelection, generalActions, userPreference } from "..";
10+
import { atlasAppearance, atlasSelection, generalActions } from "..";
1111

1212
import { InterSpaceCoordXformSvc } from "src/atlasComponents/sapi/core/space/interSpaceCoordXform.service";
1313
import { SxplrAtlas, SxplrParcellation, SxplrRegion, SxplrTemplate } from "src/atlasComponents/sapi/sxplrTypes";
@@ -75,6 +75,20 @@ function sortParc(parcs: SxplrParcellation[]) {
7575
]
7676
}
7777

78+
const SPATIAL_TRANSFORM_SRC = "SPATIAL_TRANSFORM_SRC"
79+
const SPATIAL_TRANSFORM_RESULT = "SPATIAL_TRANSFORM_RESULT"
80+
const CORTICAL_LAYERS_WARNING = "CORTICAL_LAYERS_WARNING"
81+
const REGION_DESELECTED_WARNING = "REGION_DESELECTED_WARNING"
82+
83+
type TPSelectPostHookOptions = {
84+
[SPATIAL_TRANSFORM_SRC]?: number[]
85+
[SPATIAL_TRANSFORM_RESULT]?: "failed" | "succeeded"
86+
[CORTICAL_LAYERS_WARNING]?: string
87+
[REGION_DESELECTED_WARNING]?: string
88+
}
89+
90+
type TPSelectPostHook = Partial<AtlasSelectionState> & { options?: TPSelectPostHookOptions }
91+
7892
@Injectable()
7993
export class Effect {
8094

@@ -96,7 +110,7 @@ export class Effect {
96110
)
97111
}
98112

99-
onTemplateParcSelectionPostHook: ((arg: OnTmplParcHookArg) => Observable<Partial<AtlasSelectionState>>)[] = [
113+
onTemplateParcSelectionPostHook: ((arg: OnTmplParcHookArg) => Observable<TPSelectPostHook>)[] = [
100114
/**
101115
* This hook gets the region associated with the selected parcellation and template,
102116
* and then set selectedParcellationAllRegions to it
@@ -130,27 +144,34 @@ export class Effect {
130144
switchMap(navigation =>
131145
/**
132146
* if either space name is undefined, return default state for navigation
147+
* else if space name is the same, skip trying to transform
133148
*/
134-
!prevSpcName || !currSpcName
149+
!prevSpcName || !currSpcName || prevSpcName === currSpcName
135150
? of({ navigation })
136151
: this.interSpaceCoordXformSvc.transform(prevSpcName, currSpcName, navigation.position as [number, number, number]).pipe(
137152
map(value => {
153+
const common: TPSelectPostHookOptions = {
154+
[SPATIAL_TRANSFORM_SRC]: navigation.position
155+
}
138156
if (value.status === "error") {
139-
this.sxplrSnackBarSvc.open({
140-
message: `spatial transformation failed: ${value.statusText}. Using default navigation`,
141-
142-
// TODO switch to maticon when material icon css is added
143-
// maticon: "warning"
144-
icon: "fas fa-exclamation-triangle",
145-
})
146-
return { navigation: null }
157+
return {
158+
navigation: null,
159+
options: {
160+
[SPATIAL_TRANSFORM_RESULT]: 'failed',
161+
...common,
162+
}
163+
} as TPSelectPostHook
147164
}
148165
return {
149166
navigation: {
150167
...navigation,
151168
position: value.result,
169+
},
170+
options: {
171+
SPATIAL_TRANSFORM_RESULT: 'succeeded',
172+
...common,
152173
}
153-
} as Partial<AtlasSelectionState>
174+
} as TPSelectPostHook
154175
})
155176
)
156177
)
@@ -159,15 +180,11 @@ export class Effect {
159180
({ current, previous }) => {
160181
const prevParcId = previous?.parcellation?.id
161182
const currentParcId = current?.parcellation?.id
183+
const options: Record<string, string> = {}
162184
if (currentParcId !== prevParcId && currentParcId === IDS.PARCELLATION.CORTICAL_LAYERS) {
163-
this.sxplrSnackBarSvc.open({
164-
message: `Regional inaccuracies in the automated computation of cortical layers may occur due to limitations in the available training data and algorithm. Regions that deviate from the expected canonical isocortical structure should be examined with caution.`,
165-
// TODO switch to maticon when material icon css is added
166-
// maticon: "warning"
167-
icon: "fas fa-exclamation-triangle",
168-
})
185+
options[CORTICAL_LAYERS_WARNING] = "Regional inaccuracies in the automated computation of cortical layers may occur due to limitations in the available training data and algorithm. Regions that deviate from the expected canonical isocortical structure should be examined with caution."
169186
}
170-
return of({})
187+
return of({ options })
171188
}
172189
]
173190

@@ -349,16 +366,6 @@ export class Effect {
349366
}
350367
}
351368
return from(prAskUser()).pipe(
352-
switchMap(val => {
353-
/** user cancelled */
354-
if (!val) {
355-
return of(null)
356-
}
357-
const { atlas, parcellation, template } = val
358-
return of({
359-
atlas, parcellation, template
360-
})
361-
}),
362369
switchMap(current => {
363370
if (!current) {
364371
return of(
@@ -376,29 +383,51 @@ export class Effect {
376383
selectedParcellation: current.parcellation,
377384
selectedTemplate: current.template
378385
}
386+
let talliedOptions: TPSelectPostHookOptions = {}
379387
for (const partial of partialState){
388+
const { options, ...rest } = partial
380389
state = {
381390
...state,
382-
...partial,
391+
...rest,
392+
}
393+
talliedOptions = {
394+
...talliedOptions,
395+
...options,
383396
}
384397
}
385398

386399
state.selectedRegions = []
387400
if (!!regionId) {
388401
const selectedRegions = (state.selectedParcellationAllRegions || []).filter(r => r.name === regionId)
389402
if (selectedRegions.length === 0) {
390-
391-
this.sxplrSnackBarSvc.open({
392-
message: `Previously selected region \`${regionId}\` not found in the currently selected parcellation \`${state.selectedParcellation?.name}\`. Region selections were cleared.`,
393-
useMarkdown: true,
394-
// TODO switch to maticon when material icon css is added
395-
// maticon: "warning"
396-
icon: "fas fa-exclamation-triangle",
397-
})
403+
talliedOptions[REGION_DESELECTED_WARNING] = regionId
398404
}
399405
state.selectedRegions = selectedRegions
400406
}
401-
407+
408+
const warningMarkdowns = []
409+
if (talliedOptions[SPATIAL_TRANSFORM_SRC] && talliedOptions[SPATIAL_TRANSFORM_RESULT]) {
410+
let text = `Due to the change of reference space, previous navigation location \`${talliedOptions[SPATIAL_TRANSFORM_SRC].map(v => (v/1e6).toFixed(2) + "mm").join(", ")}\` in \`${template.name}\` `
411+
if (talliedOptions[SPATIAL_TRANSFORM_RESULT] === "succeeded") {
412+
text += `was warped to \`${(state?.navigation?.position || [0, 0, 0]).map(v => (v/1e6).toFixed(2) + "mm").join(", ")}\` in \`${state?.selectedTemplate?.name}\``
413+
} else {
414+
text += `was attempted to be warped to \`${state?.selectedTemplate?.name}\`, but was unsuccessful. The navigation was reset to \`0, 0, 0\``
415+
}
416+
warningMarkdowns.push(text)
417+
}
418+
if (talliedOptions[CORTICAL_LAYERS_WARNING]) {
419+
warningMarkdowns.push(talliedOptions[CORTICAL_LAYERS_WARNING])
420+
}
421+
if (talliedOptions[REGION_DESELECTED_WARNING]) {
422+
warningMarkdowns.push(`Due to the change of reference parcellation, previously selected region \`${talliedOptions[REGION_DESELECTED_WARNING]}\` is not available. Therefore, region selection has been reset.`)
423+
}
424+
if (warningMarkdowns.length > 0) {
425+
this.sxplrSnackBarSvc.open({
426+
message: warningMarkdowns.join(`\n\n---\n\n`),
427+
useMarkdown: true,
428+
icon: "fas fa-info"
429+
})
430+
}
402431
return actions.setAtlasSelectionState(state)
403432
})
404433
)
@@ -540,39 +569,31 @@ export class Effect {
540569
})
541570
))
542571

543-
onRegionSelection = createEffect(() => this.store.pipe(
544-
select(userPreference.selectors.showExperimental),
545-
switchMap(flag => {
546-
if (!flag) {
547-
return EMPTY
548-
}
549-
return this.action.pipe(
550-
ofType(actions.selectRegion),
551-
map(({ region }) => {
552-
553-
if (region) {
554-
this.onNavigateToRegion.pipe(
555-
take(1)
556-
).subscribe(() => {
557-
this.sxplrOverlaySvc.close()
558-
})
572+
onRegionSelectionNavigateToCentroid = createEffect(() => this.action.pipe(
573+
ofType(actions.selectRegion),
574+
map(({ region }) => {
575+
576+
if (region) {
577+
this.onNavigateToRegion.pipe(
578+
take(1)
579+
).subscribe(() => {
580+
this.sxplrOverlaySvc.close()
581+
})
559582

560-
const injector = Injector.create({
561-
providers: [
562-
{
563-
provide: REGION_LOADING_TOKEN,
564-
useValue: { region } as RegionLoadingCfg
565-
}
566-
]
567-
})
568-
const portal = new ComponentPortal(LoadingRegionCmp, null, injector)
569-
this.sxplrOverlaySvc.openPortal(portal)
570-
this.store.dispatch(
571-
actions.navigateToRegion({ region, timeout: REGION_LOADING_TIMEOUT })
572-
)
573-
}
583+
const injector = Injector.create({
584+
providers: [
585+
{
586+
provide: REGION_LOADING_TOKEN,
587+
useValue: { region } as RegionLoadingCfg
588+
}
589+
]
574590
})
575-
)
591+
const portal = new ComponentPortal(LoadingRegionCmp, null, injector)
592+
this.sxplrOverlaySvc.openPortal(portal)
593+
this.store.dispatch(
594+
actions.navigateToRegion({ region, timeout: REGION_LOADING_TIMEOUT })
595+
)
596+
}
576597
})
577598
), { dispatch: false })
578599

0 commit comments

Comments
 (0)