Skip to content

Commit

Permalink
Merge branch 'master' of github.com:scalableminds/webknossos into wel…
Browse files Browse the repository at this point in the history
…come-toast

* 'master' of github.com:scalableminds/webknossos:
  updates docs for docker installation (#6963)
  Fix misc stuff when viewing tasks/annotations of another user (#6957)
  Remove segment from list and add undo/redo for segments (#6944)
  • Loading branch information
hotzenklotz committed Apr 4, 2023
2 parents 6d77a39 + b588324 commit 3bc977f
Show file tree
Hide file tree
Showing 25 changed files with 1,121 additions and 943 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released

### Added
- Added rendering precomputed meshes with level of detail depending on the zoom of the 3D viewport. This feature only works with version 3 mesh files. [#6909](https://github.com/scalableminds/webknossos/pull/6909)
- Segments can now be removed from the segment list via the context menu. [#6944](https://github.com/scalableminds/webknossos/pull/6944)
- Editing the meta data of segments (e.g., the name) is now undoable. [#6944](https://github.com/scalableminds/webknossos/pull/6944)

### Changed
- Moved the view mode selection in the toolbar next to the position field. [#6949](https://github.com/scalableminds/webknossos/pull/6949)

### Fixed
- Fixed incorrect initial tab when clicking "Show Annotations" for a user in the user list. Also, the datasets tab was removed from that page as it was the same as the datasets table from the main dashboard. [#6957](https://github.com/scalableminds/webknossos/pull/6957)

### Removed

Expand Down
8 changes: 4 additions & 4 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The easiest way to get started with WEBKNOSSOS is to get an account on [webknoss
WEBKNOSSOS is open-source, so you can install it on your own server.
We recommend a server with at least 4 CPU cores, 16 GB RAM, and as much disk space as you require for your datasets.

As prerequisites, you need to install [Docker](https://docs.docker.com/install/) and [Docker Compose](https://docs.docker.com/compose/install/) on your server. Docker 17+ and Docker Compose 1.18+ are required.
As prerequisites, you need to install [Docker](https://docs.docker.com/desktop/install/linux-install/) including [Docker Compose](https://docs.docker.com/compose/reference/) on your server. Docker 23+ is recommended.

This tutorial shows how to install WEBKNOSSOS on a fresh VM, which is available over the public internet and has a domain name (or a subdomain) already configured.
WEBKNOSSOS will then be available over a secured connection (HTTPS) with automatic certificate management.
Expand All @@ -29,20 +29,20 @@ chown -R 1000:1000 binaryData
# Note that PUBLIC_HOST does not include http:// or https:// prefixes
# Please look up the latest WEBKNOSSOS version number at https://github.com/scalableminds/webknossos/releases
DOCKER_TAG=xx.yy.z PUBLIC_HOST=webknossos.example.com [email protected] \
docker-compose up webknossos nginx nginx-letsencrypt
docker compose up webknossos nginx nginx-letsencrypt

# Wait a couple of minutes for WEBKNOSSOS to become available under your domain
# e.g. https://webknossos.example.com
# Set up your organization and admin account using the onboarding screens (see below)

# After the initial run, you can start WEBKNOSSOS in the background
DOCKER_TAG=xx.yy.z PUBLIC_HOST=webknossos.example.com [email protected] \
docker-compose up -d webknossos nginx nginx-letsencrypt
docker compose up -d webknossos nginx nginx-letsencrypt

# Congratulations! Your WEBKNOSSOS is now up and running.

# Stop everything
docker-compose down
docker compose down
```

**This setup does not support regular backups or monitoring.
Expand Down
13 changes: 10 additions & 3 deletions frontend/javascripts/components/color_picker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useRef, useState } from "react";
import { Popover } from "antd";
import * as Utils from "libs/utils";
import { HexColorInput, HexColorPicker } from "react-colorful";
Expand Down Expand Up @@ -47,19 +47,26 @@ export function ChangeColorMenuItemContent({
}: {
title: string;
isDisabled: boolean;
onSetColor: (rgb: Vector3) => void;
onSetColor: (rgb: Vector3, createsNewUndoState: boolean) => void;
rgb: Vector3;
hidePickerIcon?: boolean;
}) {
const isFirstColorChange = useRef(true);
const color = Utils.rgbToHex(Utils.map3((value) => value * 255, rgb));
const onChangeColor = (colorStr: string) => {
if (isDisabled) {
return;
}
const colorRgb = Utils.hexToRgb(colorStr);
const newColor = Utils.map3((component) => component / 255, colorRgb);
onSetColor(newColor);

// Only create a new undo state on the first color change event.
// All following color change events should mutate the most recent undo
// state so that the undo stack is not filled on each mouse movement.
onSetColor(newColor, isFirstColorChange.current);
isFirstColorChange.current = false;
};

const content = isDisabled ? null : (
<ThrottledColorPicker color={color} onChange={onChangeColor} />
);
Expand Down
29 changes: 15 additions & 14 deletions frontend/javascripts/dashboard/dashboard_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,14 @@ class DashboardView extends PureComponent<PropsWithRouter, State> {
let defaultTabKey = "datasets";

if (this.props.isAdminView) {
defaultTabKey = "tasks";
defaultTabKey = "explorativeAnnotations";
} else if (features().isWkorgInstance) {
defaultTabKey = "publications";
}

// Flow doesn't allow validTabKeys[key] where key may be null, so check that first
const activeTabKey =
(initialTabKey && initialTabKey in validTabKeys && initialTabKey) ||
(lastUsedTabKey && lastUsedTabKey in validTabKeys && lastUsedTabKey) ||
(initialTabKey && validTabKeys[initialTabKey] ? initialTabKey : null) ||
(lastUsedTabKey && validTabKeys[lastUsedTabKey] ? lastUsedTabKey : null) ||
defaultTabKey;

this.state = {
Expand Down Expand Up @@ -148,7 +147,7 @@ class DashboardView extends PureComponent<PropsWithRouter, State> {
datasets: !isAdminView,
tasks: true,
explorativeAnnotations: true,
};
} as { [key: string]: boolean };
}

getTabs(user: APIUser): Tab[] {
Expand All @@ -166,15 +165,17 @@ class DashboardView extends PureComponent<PropsWithRouter, State> {
),
}
: null,
{
label: <span>Datasets</span>,
key: "datasets",
children: (
<RenderingTabContext.Provider value="datasets">
<DatasetFolderView user={user} />
</RenderingTabContext.Provider>
),
},
validTabKeys.datasets
? {
label: <span>Datasets</span>,
key: "datasets",
children: (
<RenderingTabContext.Provider value="datasets">
<DatasetFolderView user={user} />
</RenderingTabContext.Provider>
),
}
: null,
{
label: "Tasks",
key: "tasks",
Expand Down
7 changes: 5 additions & 2 deletions frontend/javascripts/libs/diffable_map.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
const defaultItemsPerBatch = 1000;
let idCounter = 0;
const idSymbol = Symbol("id"); // DiffableMap is an immutable key-value data structure which supports fast diffing.
const idSymbol = Symbol("id");

// DiffableMap is an immutable key-value data structure which supports fast diffing.
// Updating a DiffableMap returns a new DiffableMap, in which case the Maps are
// derived from each other ("dependent").
// Diffing is very fast when the given Maps are dependent, since the separate chunks
// can be compared shallowly.
// The insertion order of the DiffableMap is not guaranteed.
// Stored values may be null. However, `undefined` is equal to "does not exist".
// Stored values may be null. However, be careful when dealing with `undefined`, as
// it's interpreted as "does not exist", but can still be listed during enumeration.

class DiffableMap<K extends number, V> {
chunks: Array<Map<K, V>>;
Expand Down
2 changes: 2 additions & 0 deletions frontend/javascripts/oxalis/api/api_latest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2066,6 +2066,8 @@ class DataApi {
color: rgbColor,
},
effectiveLayerName,
undefined,
true,
),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,18 @@ export async function loadSynapsesOfAgglomerateAtPosition(position: Vector3) {
const isConnectomeEnabled = hasConnectomeFile(state);

if (mappingName && isConnectomeEnabled.value) {
const cellId = await getSegmentIdForPositionAsync(position);
Store.dispatch(setActiveConnectomeAgglomerateIdsAction(segmentation.name, [cellId]));
const segmentId = await getSegmentIdForPositionAsync(position);
Store.dispatch(setActiveConnectomeAgglomerateIdsAction(segmentation.name, [segmentId]));
} else {
Toast.error(isConnectomeEnabled.reason);
}
}
export function handleClickSegment(clickPosition: Point2) {
const state = Store.getState();
const globalPosition = calculateGlobalPos(state, clickPosition);
const cellId = getSegmentIdForPosition(globalPosition);
const segmentId = getSegmentIdForPosition(globalPosition);

if (cellId > 0) {
Store.dispatch(clickSegmentAction(cellId, globalPosition));
if (segmentId > 0) {
Store.dispatch(clickSegmentAction(segmentId, globalPosition));
}
}
28 changes: 14 additions & 14 deletions frontend/javascripts/oxalis/model/actions/annotation_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,37 +260,37 @@ export const maybeFetchMeshFilesAction = (
callback,
} as const);

export const triggerIsosurfaceDownloadAction = (cellName: string, cellId: number) =>
export const triggerIsosurfaceDownloadAction = (cellName: string, segmentId: number) =>
({
type: "TRIGGER_ISOSURFACE_DOWNLOAD",
cellName,
cellId,
segmentId,
} as const);

export const refreshIsosurfacesAction = () =>
({
type: "REFRESH_ISOSURFACES",
} as const);

export const refreshIsosurfaceAction = (layerName: string, cellId: number) =>
export const refreshIsosurfaceAction = (layerName: string, segmentId: number) =>
({
type: "REFRESH_ISOSURFACE",
layerName,
cellId,
segmentId,
} as const);

export const startedLoadingIsosurfaceAction = (layerName: string, cellId: number) =>
export const startedLoadingIsosurfaceAction = (layerName: string, segmentId: number) =>
({
type: "STARTED_LOADING_ISOSURFACE",
layerName,
cellId,
segmentId,
} as const);

export const finishedLoadingIsosurfaceAction = (layerName: string, cellId: number) =>
export const finishedLoadingIsosurfaceAction = (layerName: string, segmentId: number) =>
({
type: "FINISHED_LOADING_ISOSURFACE",
layerName,
cellId,
segmentId,
} as const);

export const updateMeshFileListAction = (layerName: string, meshFiles: Array<APIMeshFile>) =>
Expand All @@ -317,39 +317,39 @@ export const importIsosurfaceFromStlAction = (layerName: string, buffer: ArrayBu
buffer,
} as const);

export const removeIsosurfaceAction = (layerName: string, cellId: number) =>
export const removeIsosurfaceAction = (layerName: string, segmentId: number) =>
({
type: "REMOVE_ISOSURFACE",
layerName,
cellId,
segmentId,
} as const);

export const addAdHocIsosurfaceAction = (
layerName: string,
cellId: number,
segmentId: number,
seedPosition: Vector3,
mappingName: string | null | undefined,
mappingType: MappingType | null | undefined,
) =>
({
type: "ADD_AD_HOC_ISOSURFACE",
layerName,
cellId,
segmentId,
seedPosition,
mappingName,
mappingType,
} as const);

export const addPrecomputedIsosurfaceAction = (
layerName: string,
cellId: number,
segmentId: number,
seedPosition: Vector3,
meshFileName: string,
) =>
({
type: "ADD_PRECOMPUTED_ISOSURFACE",
layerName,
cellId,
segmentId,
seedPosition,
meshFileName,
} as const);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@ export type LoadPrecomputedMeshAction = ReturnType<typeof loadPrecomputedMeshAct
export type SegmentationAction = LoadAdHocMeshAction | LoadPrecomputedMeshAction;

export const loadAdHocMeshAction = (
cellId: number,
segmentId: number,
seedPosition: Vector3,
extraInfo?: AdHocIsosurfaceInfo,
layerName?: string,
) =>
({
type: "LOAD_AD_HOC_MESH_ACTION",
cellId,
segmentId,
seedPosition,
extraInfo,
layerName,
} as const);

export const loadPrecomputedMeshAction = (
cellId: number,
segmentId: number,
seedPosition: Vector3,
meshFileName: string,
layerName?: string,
) =>
({
type: "LOAD_PRECOMPUTED_MESH_ACTION",
cellId,
segmentId,
seedPosition,
meshFileName,
layerName,
Expand Down
Loading

0 comments on commit 3bc977f

Please sign in to comment.