Skip to content

Commit

Permalink
Merge branch 'master' into neuvue
Browse files Browse the repository at this point in the history
  • Loading branch information
dxenes1 committed Nov 6, 2024
2 parents b57612e + 9eb296f commit 9fb3240
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 146 deletions.
68 changes: 44 additions & 24 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,47 +1,67 @@
name: BuildAndDeploy
name: Build

on: [push]
on: [push, pull_request]

jobs:
build-and-deploy:

permissions:
contents: 'read'
id-token: 'write'
deployments: 'write'
strategy:
matrix:
node-version:
- '16.x'
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- uses: actions/cache@v3
with:
node-version: '10.x'
- run: npm i
- run: npm run build
path: "**/node_modules"
key: ${{ runner.os }}-${{ matrix.node-version }}-node_modules-${{ hashFiles('**/package-lock.json') }}
- run: npm install
- name: Build
run: npm run build
- run: cp -r ./dist/dev appengine/frontend/static/
- name: Extract branch name
id: get_branch
- name: Get branch name (merge)
if: github.event_name != 'pull_request'
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/} | tr / - | tr _ -)"
- run: echo ${{ steps.get_branch.outputs.branch }}
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/} | tr / - | tr _ -)" >> $GITHUB_ENV
- name: Get branch name (pull request)
if: github.event_name == 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_HEAD_REF} | tr / - | tr _ -)" >> $GITHUB_ENV
- run: echo ${{ env.BRANCH_NAME }}
- name: start deployment
uses: bobheadxi/deployments@v0.5.2
uses: bobheadxi/deployments@v1
id: deployment
with:
step: start
token: ${{ secrets.GITHUB_TOKEN }}
env: ${{ steps.get_branch.outputs.branch }}
desc: Setting up staging deployment for ${{ steps.get_branch.outputs.branch }}
- name: deploy to gcloud dev branch
uses: actions-hub/gcloud@master
env:
PROJECT_ID: neuromancer-seung-import
APPLICATION_CREDENTIALS: ${{ secrets.SA_NEUROMANCER_GOOGLE_APPS_DEPLOY }}
env: ${{ env.BRANCH_NAME }}
desc: Setting up staging deployment for ${{ env.BRANCH_NAME }}
- id: 'auth'
uses: 'google-github-actions/auth@v1'
with:
workload_identity_provider: 'projects/483670036293/locations/global/workloadIdentityPools/neuroglancer-github/providers/github'
service_account: '[email protected]'
- id: deploy
uses: google-github-actions/deploy-appengine@main
with:
args: app deploy appengine/frontend/app.yaml --no-promote --version ${{ steps.get_branch.outputs.branch }}
version: ${{ env.BRANCH_NAME }}
deliverables: appengine/frontend/app.yaml
promote: false
- name: update deployment status
uses: bobheadxi/deployments@v0.5.2
uses: bobheadxi/deployments@v1
if: always()
with:
step: finish
token: ${{ secrets.GITHUB_TOKEN }}
env: ${{ steps.deployment.outputs.env }}
env_url: https://${{ steps.get_branch.outputs.branch }}-dot-neuromancer-seung-import.appspot.com
env_url: ${{ steps.deploy.outputs.url }}
status: ${{ job.status }}
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
125 changes: 71 additions & 54 deletions src/neuroglancer/annotation/annotation_layer_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import {StatusMessage} from 'neuroglancer/status';
import {TrackableBoolean, TrackableBooleanCheckbox} from 'neuroglancer/trackable_boolean';
import {getPositionSummary, SelectedAnnotationState, UserLayerWithAnnotations} from 'neuroglancer/ui/annotations';
import {HidingList} from 'neuroglancer/ui/hiding_list';
import {br} from 'neuroglancer/util/br';
import {Borrowed, Owned} from 'neuroglancer/util/disposable';
import {mat4, transformVectorByMat4, vec3} from 'neuroglancer/util/geom';
import {formatIntegerBounds, formatIntegerPoint} from 'neuroglancer/util/spatial_units';
import {Uint64} from 'neuroglancer/util/uint64';
import {ColorWidget} from 'neuroglancer/widget/color';
import {MinimizableGroupWidget} from 'neuroglancer/widget/minimizable_group';
import {RangeWidget} from 'neuroglancer/widget/range';
Expand Down Expand Up @@ -314,6 +316,8 @@ export class AnnotationLayerView extends Tab {
const importCSVButton = document.createElement('button');
const importCSVForm = document.createElement('form');
const importCSVFileSelect = document.createElement('input');
const segmentCSVOverrideCheckbox = document.createElement('input');
const segmentCSVOverrideLabel = document.createElement('label');
exportToCSVButton.id = 'exportToCSVButton';
exportToCSVButton.textContent = 'Export to CSV';
exportToCSVButton.addEventListener('click', () => {
Expand All @@ -329,12 +333,19 @@ export class AnnotationLayerView extends Tab {
});
importCSVForm.appendChild(importCSVFileSelect);
importCSVFileSelect.addEventListener('change', () => {
this.importCSV(importCSVFileSelect.files);
this.importCSV(importCSVFileSelect.files, segmentCSVOverrideCheckbox.checked);
importCSVForm.reset();
});
importCSVFileSelect.classList.add('neuroglancer-hidden-button');
segmentCSVOverrideLabel.textContent = 'Select segments on import (Experimental): ';
segmentCSVOverrideLabel.title =
'This requires that the segmentation source of the annotation layer when importing the CSV file is the same as the segmentation source when the file was exported. Imported IDs may be outdated.'
segmentCSVOverrideCheckbox.type = 'checkbox';

const csvContainer = document.createElement('span');
csvContainer.append(exportToCSVButton, importCSVButton, importCSVForm);
csvContainer.append(
exportToCSVButton, importCSVButton, br(), segmentCSVOverrideLabel,
segmentCSVOverrideCheckbox, importCSVForm);
this.groupAnnotations.appendFixedChild(csvContainer);
}

Expand Down Expand Up @@ -1047,34 +1058,38 @@ export class AnnotationLayerView extends Tab {
}

// TODO: pull request to papa repo
private betterPapa = (inputFile: File|Blob): Promise<any> => {
return new Promise((resolve) => {
Papa.parse(inputFile, {
complete: (results: any) => {
resolve(results);
}
private betterPapa = (inputFile: File|Blob):
Promise<any> => {
return new Promise((resolve) => {
Papa.parse(inputFile, {
complete: (results: any) => {
resolve(results);
}
});
});
});
}
}

private stringToVec3 = (input: string): vec3 => {
// format: (x, y, z)
let raw = input.split('');
raw.shift();
raw.pop();
let list = raw.join('');
let val = list.split(',').map(v => parseInt(v, 10));
return vec3.fromValues(val[0], val[1], val[2]);
}
private stringToVec3 = (input: string):
vec3 => {
// format: (x, y, z)
let list = input.replace(/[{()}[\]]/g, '');
let val = list.split(',').map(v => parseInt(v, 10));
return vec3.fromValues(val[0], val[1], val[2]);
}

private dimensionsToVec3 = (input: string): vec3 => {
// format: A × B × C
let raw = input.replace(/s/g, '');
let val = raw.split('×').map(v => parseInt(v, 10));
return vec3.fromValues(val[0], val[1], val[2]);
}
private dimensionsToVec3 = (input: string): vec3 => {
// format: A × B × C
let raw = input.replace(/s/g, '');
let val = raw.split('×').map(v => parseInt(v, 10));
return vec3.fromValues(val[0], val[1], val[2]);
}
private textToPoint = (point: string, transform: mat4, dimension?: boolean) => {
const parsedVec = dimension ? this.dimensionsToVec3(point) : this.stringToVec3(point);
const spatialPoint = this.voxelSize.spatialFromVoxel(tempVec3, parsedVec);
return vec3.transformMat4(vec3.create(), spatialPoint, transform);
}

private async importCSV(files: FileList|null) {
private async importCSV(files: FileList|null, segmentOverride: boolean = false) {
const rawAnnotations = <Annotation[]>[];
let successfulImport = 0;

Expand All @@ -1088,61 +1103,59 @@ export class AnnotationLayerView extends Tab {
if (!rawData.data.length) {
continue;
}
const annStrings = rawData.data;
const annStrings = <string[][]>rawData.data;
const csvIdToRealAnnotationIdMap: {[key: string]: string} = {};
const childStorage: {[key: string]: string[]} = {};
const textToPoint = (point: string, transform: mat4, dimension?: boolean) => {
const parsedVec = dimension ? this.dimensionsToVec3(point) : this.stringToVec3(point);
const spatialPoint = this.voxelSize.spatialFromVoxel(tempVec3, parsedVec);
return vec3.transformMat4(vec3.create(), spatialPoint, transform);
};
let row = -1;

for (const annProps of annStrings) {
row++;
const type = annProps[7];
const type = annProps[7].toLowerCase();
const parentId = annProps[6];
const annotationID: string|undefined = annProps[8];
const tags = annProps[3];
const segments = annProps[5];
let raw = <Annotation>{id: makeAnnotationId(), description: annProps[4]};

switch (type) {
case 'AABB':
case 'Line':
case 'aabb':
case 'line':
raw.type =
type === 'Line' ? AnnotationType.LINE : AnnotationType.AXIS_ALIGNED_BOUNDING_BOX;
(<Line>raw).pointA = textToPoint(annProps[0], this.annotationLayer.globalToObject);
(<Line>raw).pointB = textToPoint(annProps[1], this.annotationLayer.globalToObject);
type === 'line' ? AnnotationType.LINE : AnnotationType.AXIS_ALIGNED_BOUNDING_BOX;
(<Line>raw).pointA = this.textToPoint(annProps[0], this.annotationLayer.globalToObject);
(<Line>raw).pointB = this.textToPoint(annProps[1], this.annotationLayer.globalToObject);
break;
case 'Point':
case 'point':
raw.type = AnnotationType.POINT;
(<Point>raw).point = textToPoint(annProps[0], this.annotationLayer.globalToObject);
(<Point>raw).point = this.textToPoint(annProps[0], this.annotationLayer.globalToObject);
break;
case 'Ellipsoid':
case 'ellipsoid':
raw.type = AnnotationType.ELLIPSOID;
(<Ellipsoid>raw).center = textToPoint(annProps[0], this.annotationLayer.globalToObject);
(<Ellipsoid>raw).center =
this.textToPoint(annProps[0], this.annotationLayer.globalToObject);
(<Ellipsoid>raw).radii =
textToPoint(annProps[2], this.annotationLayer.globalToObject, true);
this.textToPoint(annProps[2], this.annotationLayer.globalToObject, true);
break;
case 'Line Strip':
case 'Line Strip*':
case 'Spoke':
case 'Spoke*':
case 'Collection':
if (type === 'Line Strip' || type === 'Line Strip*') {
case 'line Strip':
case 'line Strip*':
case 'spoke':
case 'spoke*':
case 'collection':
if (type === 'line Strip' || type === 'line Strip*') {
raw.type = AnnotationType.LINE_STRIP;
(<LineStrip>raw).connected = true;
(<LineStrip>raw).looped = type === 'Line Strip*';
} else if (type === 'Spoke' || type === 'Spoke*') {
(<LineStrip>raw).looped = type === 'line Strip*';
} else if (type === 'spoke' || type === 'spoke*') {
raw.type = AnnotationType.SPOKE;
(<Spoke>raw).connected = true;
(<Spoke>raw).wheeled = type === 'Spoke*';
(<Spoke>raw).wheeled = type === 'spoke*';
} else {
raw.type = AnnotationType.COLLECTION;
(<Collection>raw).connected = false;
}
(<Collection>raw).childrenVisible = new TrackableBoolean(false, true);
(<Collection>raw).source =
textToPoint(annProps[0], this.annotationLayer.globalToObject);
this.textToPoint(annProps[0], this.annotationLayer.globalToObject);
(<Collection>raw).entry = (index: number) =>
(<LocalAnnotationSource>this.annotationLayer.source)
.get((<Collection>raw).entries[index]);
Expand Down Expand Up @@ -1192,7 +1205,11 @@ export class AnnotationLayerView extends Tab {
});
}
// Segments not supported

// getSelectedAssocatedSegment(this.annotationLayer)
// naively add segment directly from excel
if (segments && segmentOverride) {
raw.segments = segments.split(',').map((s: string) => Uint64.parseString(s));
}
rawAnnotations.push(raw);
}
successfulImport++;
Expand Down
29 changes: 29 additions & 0 deletions src/neuroglancer/graph/path_finder_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,35 @@ class PathBetweenSupervoxels extends RefCounted {
this.addSourceOrTarget(newTarget);
}

getLatestSegments(layer: SegmentationUserLayerWithGraph) {
if (!this._source || !this._target){
return
}
const {segmentSelectionState} = layer.displayState;
const newSource: Point = {
id: '',
segments: [
segmentSelectionState.rawSelectedSegment.clone(),
segmentSelectionState.selectedSegment.clone()
],
point: this._source.point,
type: AnnotationType.POINT,
};

const newTarget: Point = {
id: '',
segments: [
segmentSelectionState.rawSelectedSegment.clone(),
segmentSelectionState.selectedSegment.clone()
],
point: this._target.point,
type: AnnotationType.POINT,
};
this.clear();
this.addSourceOrTarget(newSource);
this.addSourceOrTarget(newTarget);
}

toJSON() {
const x: any = {
[ANNOTATION_PATH_JSON_KEY]: this.annotationSource.toJSON(),
Expand Down
9 changes: 5 additions & 4 deletions src/neuroglancer/save_state/save_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {Dialog} from 'neuroglancer/dialog';
import {Overlay} from 'neuroglancer/overlay';
import {dismissUnshareWarning, getSaveToAddressBar, getUnshareWarning} from 'neuroglancer/preferences/user_preferences';
import {StatusMessage} from 'neuroglancer/status';
import {br} from 'neuroglancer/util/br';
import {RefCounted} from 'neuroglancer/util/disposable';
import {getRandomHexString} from 'neuroglancer/util/random';
import {Trackable} from 'neuroglancer/util/trackable';
Expand Down Expand Up @@ -200,7 +201,8 @@ export class SaveState extends RefCounted {

this.key = getRandomHexString();
params.set('local_id', this.key);
history.pushState({}, '', `${window.location.origin}${window.location.pathname}?${params.toString()}`);
history.pushState(
{}, '', `${window.location.origin}${window.location.pathname}?${params.toString()}`);
}
private reassign(master: any) {
const hist = <string[]>master.history;
Expand Down Expand Up @@ -294,9 +296,8 @@ type FieldConfig = {
};

class SaveDialog extends Overlay {
constructor(public viewer: Viewer, jsonString?: string, getUrlType?: UrlType, hidden = false) {
super(hidden);
const br = () => document.createElement('br');
constructor(public viewer: Viewer, jsonString?: string, getUrlType?: UrlType) {
super();
const jsonURLDefault = `LINK SHORTNER INACCESSIBLE`;

const urlStart = `${window.location.origin}${window.location.pathname}`;
Expand Down
Loading

0 comments on commit 9fb3240

Please sign in to comment.