Skip to content

Live Collab M2 - Automatically update annotation to newest changes #8648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 77 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
5d6ff54
wip: ignore user state updates; update to skeleton and volume changes
philippotto May 22, 2025
ce266b0
stop polling aggressively when an unapplicable update was encountered
philippotto May 22, 2025
b330a37
live update to proofreading actions
philippotto May 22, 2025
93b4789
update comment
philippotto May 22, 2025
19cffd8
integrate live bbox updates for skeleton tracing
philippotto May 28, 2025
e4aeb61
rename BoundingBoxType to BoundingBoxMinMaxType
philippotto May 28, 2025
7d74402
rename UserBoundingBoxToServer to UserBoundingBoxForServer
philippotto May 28, 2025
f16688e
refactor bbox types a bit (mainly move them to common module)
philippotto May 28, 2025
1694d89
refactor update action application code into own folder and new files…
philippotto May 28, 2025
e9605c4
fix cyclic dep
philippotto May 28, 2025
e65f24a
fix type
philippotto May 28, 2025
1072cda
fix bbox updates for volume by accessing correct tracing
philippotto May 28, 2025
03c8998
rename to BoundingBoxProto where applicable
philippotto May 28, 2025
e76f0a1
also rename to UserBoundingBoxProto
philippotto May 28, 2025
7c02290
also rename AdditionalAxisProto
philippotto May 28, 2025
0481bed
misc
philippotto May 28, 2025
5931fb6
support createTree update action
philippotto May 28, 2025
01cae25
also implement updateTree
philippotto May 28, 2025
1cd1935
misc
philippotto May 30, 2025
3cc4a6f
implement more live updates of skeleton actions; add some tests
philippotto Jun 2, 2025
4ea23ba
clean up chain reduce
philippotto Jun 3, 2025
c03e04d
wip: skeleton update action tests
philippotto Jun 3, 2025
0a507ae
add values method for EdgeCollection
philippotto Jun 3, 2025
a0c18cb
fix cachedMaxNodeId
philippotto Jun 3, 2025
e8a245e
typing
philippotto Jun 3, 2025
a794535
add todo comment
philippotto Jun 3, 2025
35e64d8
also pass prev and current tracing to compact function so that moved …
philippotto Jun 4, 2025
73f1b79
prepare testing bbox related actions
philippotto Jun 4, 2025
9e234da
fix skeleton specs (don't concat and then compact because that scenar…
philippotto Jun 10, 2025
3ff93c7
fix bounding box test in skeleton.spec
philippotto Jun 10, 2025
d50c728
finish skeleton spec and fix bbox related test
philippotto Jun 10, 2025
dcdce64
support more update actions
philippotto Jun 10, 2025
6f0c98a
improve typing
philippotto Jun 11, 2025
c118dd8
refactor to fix cyclic deps
philippotto Jun 11, 2025
49a3b8b
refactor fixtures
philippotto Jun 11, 2025
13ec558
write and fix volume specs for UA application
philippotto Jun 11, 2025
71cab45
misc
philippotto Jun 11, 2025
a7ced9f
fix merge-related problems in specs
philippotto Jun 12, 2025
eb0b54c
prepare hybrid fixtures for proofreading tests and clean up
philippotto Jun 13, 2025
23835bd
replace volumeTracing in spec with existing fixture and fix wrong id
philippotto Jun 13, 2025
7972857
DRY more fixtures
philippotto Jun 13, 2025
2eac7ac
refactor preprocessing of dataset in model initialization
philippotto Jun 13, 2025
035ae5f
introduce StoreDataset to add type safety for mandatory preprocessing…
philippotto Jun 16, 2025
dfe41ef
implement first test for proofreading (merges two agglomerates)
philippotto Jun 18, 2025
3a67f16
also add test for proofreading min cut
philippotto Jun 18, 2025
f95cdd7
refactor spec
philippotto Jun 18, 2025
2963c7c
further refac
philippotto Jun 18, 2025
70fb5b9
fix wrong import
philippotto Jun 19, 2025
13b91a3
reconfigure tsconfig to be compatible with tsgo (no more baseUrl)
philippotto Jun 19, 2025
46510c2
Merge branch 'master' of github.com:scalableminds/webknossos into liv…
philippotto Jun 19, 2025
2a3b7c1
also add proofreading specs for incorporating update actions from server
philippotto Jun 19, 2025
2f02cb1
format
philippotto Jun 19, 2025
dd73fc9
clean up
philippotto Jun 19, 2025
6d515db
update changelog
philippotto Jun 19, 2025
302d078
speed up tests by reducing sleep in ensureSavedState
philippotto Jun 20, 2025
cb645d0
bump timeouts a bit
philippotto Jun 20, 2025
e66e72f
add test for reloading bucket if it changed on the server
philippotto Jun 20, 2025
78833e5
bump save delay a bit to fix flaky test
philippotto Jun 20, 2025
26f02fb
Merge branch 'master' into live-m2
philippotto Jun 23, 2025
42c3ebb
use ViewModeValues constant where possible
philippotto Jun 24, 2025
1662292
incorporate some feedback
philippotto Jun 24, 2025
7b3adab
read activeTreeId and activeNodeId directly from store instead of usi…
philippotto Jun 24, 2025
0928f6c
more feedback
philippotto Jun 24, 2025
81b5a60
more feedback
philippotto Jun 24, 2025
2ea0341
refresh layer in finalization step too
philippotto Jun 24, 2025
82e1682
swap param order for updateMappingWithMerge
philippotto Jun 24, 2025
f22bc56
also swap order for updateMappingWithMerge
philippotto Jun 24, 2025
d4353fa
more feedback
philippotto Jun 24, 2025
a94a7a6
fix incorrect invocation of saga
philippotto Jun 24, 2025
bd46a5a
fix incorrect newActiveNodeId
philippotto Jun 25, 2025
ae2299b
Merge branch 'master' of github.com:scalableminds/webknossos into liv…
philippotto Jun 25, 2025
d8dbc69
remove one todo and make watchChangedBucketsForLayer a bit clearer
philippotto Jun 25, 2025
bd536d0
show error and terminate synchronizing saga in error case
philippotto Jun 25, 2025
a9fa06c
fix race condition between getNewestVersionForAnnotation and getUpdat…
philippotto Jun 25, 2025
51e08f1
format
philippotto Jun 25, 2025
5059116
fix that some actions were not applied because of allowUpdate==false
philippotto Jun 26, 2025
33bb355
refactor transformStateAsReadOnly
philippotto Jun 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions frontend/javascripts/admin/rest_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -767,8 +767,9 @@ export function getUpdateActionLog(
annotationId: string,
oldestVersion?: number,
newestVersion?: number,
sortAscending: boolean = false,
): Promise<Array<APIUpdateActionBatch>> {
return doWithToken((token) => {
return doWithToken(async (token) => {
const params = new URLSearchParams();
params.set("token", token);
if (oldestVersion != null) {
Expand All @@ -777,9 +778,14 @@ export function getUpdateActionLog(
if (newestVersion != null) {
params.set("newestVersion", newestVersion.toString());
}
return Request.receiveJSON(
const log: APIUpdateActionBatch[] = await Request.receiveJSON(
`${tracingStoreUrl}/tracings/annotation/${annotationId}/updateActionLog?${params}`,
);

if (sortAscending) {
log.reverse();
}
return log;
});
}

Expand Down Expand Up @@ -1969,6 +1975,9 @@ export async function getAgglomeratesForSegmentsFromDatastore<T extends number |
mappingId: string,
segmentIds: Array<T>,
): Promise<Mapping> {
if (segmentIds.length === 0) {
return new Map();
}
const segmentIdBuffer = serializeProtoListOfLong<T>(segmentIds);
const listArrayBuffer: ArrayBuffer = await doWithToken((token) => {
const params = new URLSearchParams({ token });
Expand Down Expand Up @@ -1999,6 +2008,9 @@ export async function getAgglomeratesForSegmentsFromTracingstore<T extends numbe
annotationId: string,
version?: number | null | undefined,
): Promise<Mapping> {
if (segmentIds.length === 0) {
return new Map();
}
const params = new URLSearchParams({ annotationId });
if (version != null) {
params.set("version", version.toString());
Expand Down Expand Up @@ -2181,7 +2193,7 @@ export function getSynapseTypes(
);
}

type MinCutTargetEdge = {
export type MinCutTargetEdge = {
position1: Vector3;
position2: Vector3;
segmentId1: number;
Expand Down
67 changes: 45 additions & 22 deletions frontend/javascripts/libs/utils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { Chalk } from "chalk";
import dayjs from "dayjs";
import naturalSort from "javascript-natural-sort";
import window, { document, location } from "libs/window";
import _ from "lodash";
import type { APIDataset, APIUser, MapEntries } from "types/api_types";
import type { BoundingBoxMinMaxType } from "types/bounding_box";
import type { ArbitraryObject, Comparator } from "types/globals";
import type {
BoundingBoxType,
ColorObject,
Point3,
TypedArray,
Vector3,
Vector4,
Vector6,
} from "viewer/constants";
import type { ColorObject, Point3, TypedArray, Vector3, Vector4, Vector6 } from "viewer/constants";
import type { TreeGroup } from "viewer/model/types/tree_types";
import type { BoundingBoxObject, NumberLike, SegmentGroup } from "viewer/store";

Expand Down Expand Up @@ -276,19 +270,23 @@ export function getRandomColor(): Vector3 {
return randomColor as any as Vector3;
}

export function computeBoundingBoxFromArray(bb: Vector6): BoundingBoxType {
export function computeBoundingBoxFromArray(bb: Vector6): BoundingBoxMinMaxType {
const [x, y, z, width, height, depth] = bb;
return {
min: [x, y, z],
max: [x + width, y + height, z + depth],
};
}

export function computeBoundingBoxFromBoundingBoxObject(bb: BoundingBoxObject): BoundingBoxType {
export function computeBoundingBoxFromBoundingBoxObject(
bb: BoundingBoxObject,
): BoundingBoxMinMaxType {
return computeBoundingBoxFromArray([...bb.topLeft, bb.width, bb.height, bb.depth]);
}

export function computeBoundingBoxObjectFromBoundingBox(bb: BoundingBoxType): BoundingBoxObject {
export function computeBoundingBoxObjectFromBoundingBox(
bb: BoundingBoxMinMaxType,
): BoundingBoxObject {
const boundingBoxArray = computeArrayFromBoundingBox(bb);
return {
topLeft: [boundingBoxArray[0], boundingBoxArray[1], boundingBoxArray[2]],
Expand All @@ -298,7 +296,7 @@ export function computeBoundingBoxObjectFromBoundingBox(bb: BoundingBoxType): Bo
};
}

export function computeArrayFromBoundingBox(bb: BoundingBoxType): Vector6 {
export function computeArrayFromBoundingBox(bb: BoundingBoxMinMaxType): Vector6 {
return [
bb.min[0],
bb.min[1],
Expand All @@ -309,11 +307,13 @@ export function computeArrayFromBoundingBox(bb: BoundingBoxType): Vector6 {
];
}

export function computeShapeFromBoundingBox(bb: BoundingBoxType): Vector3 {
export function computeShapeFromBoundingBox(bb: BoundingBoxMinMaxType): Vector3 {
return [bb.max[0] - bb.min[0], bb.max[1] - bb.min[1], bb.max[2] - bb.min[2]];
}

export function aggregateBoundingBox(boundingBoxes: Array<BoundingBoxObject>): BoundingBoxType {
export function aggregateBoundingBox(
boundingBoxes: Array<BoundingBoxObject>,
): BoundingBoxMinMaxType {
if (boundingBoxes.length === 0) {
return {
min: [0, 0, 0],
Expand Down Expand Up @@ -344,8 +344,8 @@ export function aggregateBoundingBox(boundingBoxes: Array<BoundingBoxObject>): B
}

export function areBoundingBoxesOverlappingOrTouching(
firstBB: BoundingBoxType,
secondBB: BoundingBoxType,
firstBB: BoundingBoxMinMaxType,
secondBB: BoundingBoxMinMaxType,
) {
let areOverlapping = true;

Expand Down Expand Up @@ -425,10 +425,6 @@ export function stringToNumberArray(s: string): Array<number> {
return result;
}

export function concatVector3(a: Vector3, b: Vector3): Vector6 {
return [a[0], a[1], a[2], b[0], b[1], b[2]];
}

export function numberArrayToVector3(array: Array<number>): Vector3 {
const output: Vector3 = [0, 0, 0];

Expand Down Expand Up @@ -1262,7 +1258,11 @@ export function notEmpty<TValue>(value: TValue | null | undefined): value is TVa

export function isNumberMap(x: Map<NumberLike, NumberLike>): x is Map<number, number> {
const { value } = x.entries().next();
return Boolean(value && typeof value[0] === "number");
if (value === undefined) {
// Let's assume a number map when the map is empty.
return true;
}
return Boolean(typeof value[0] === "number");
}

export function isBigInt(x: NumberLike): x is bigint {
Expand Down Expand Up @@ -1368,3 +1368,26 @@ export function areSetsEqual<T>(setA: Set<T>, setB: Set<T>) {
}
return true;
}

// ColoredLogger can be used to make certain log outputs easier to find (especially useful
// when automatic logging of redux actions is enabled which makes the overall logging
// very verbose).
const chalk = new Chalk({ level: 3 });
export const ColoredLogger = {
log: (...args: unknown[]) => {
// Simple wrapper to allow easy switching from colored to non-colored logs
console.log(...args);
},
logRed: (str: string, ...args: unknown[]) => {
console.log(chalk.bgRed(str), ...args);
},
logGreen: (str: string, ...args: unknown[]) => {
console.log(chalk.bgGreen(str), ...args);
},
logYellow: (str: string, ...args: unknown[]) => {
console.log(chalk.bgYellow(str), ...args);
},
logBlue: (str: string, ...args: unknown[]) => {
console.log(chalk.bgBlue(str), ...args);
},
};
8 changes: 4 additions & 4 deletions frontend/javascripts/libs/vector_input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { InputProps } from "antd";
import * as Utils from "libs/utils";
import _ from "lodash";
import * as React from "react";
import type { ServerBoundingBoxTypeTuple } from "types/api_types";
import type { ServerBoundingBoxMinMaxTypeTuple } from "types/api_types";
import type { Vector3, Vector6 } from "viewer/constants";
import InputComponent from "viewer/view/components/input_component";

Expand Down Expand Up @@ -206,11 +206,11 @@ export class ArbitraryVectorInput extends BaseVector<number[]> {
}

type BoundingBoxInputProps = Omit<InputProps, "value"> & {
value: ServerBoundingBoxTypeTuple;
onChange: (arg0: ServerBoundingBoxTypeTuple) => void;
value: ServerBoundingBoxMinMaxTypeTuple;
onChange: (arg0: ServerBoundingBoxMinMaxTypeTuple) => void;
};

function boundingBoxToVector6(value: ServerBoundingBoxTypeTuple): Vector6 {
function boundingBoxToVector6(value: ServerBoundingBoxMinMaxTypeTuple): Vector6 {
const { topLeft, width, height, depth } = value;
const [x, y, z] = topLeft;
return [x, y, z, width, height, depth];
Expand Down
Loading