Skip to content
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

Tri-State plane display in 3D viewport #5440

Merged
merged 13 commits into from
May 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
[Commits](https://github.com/scalableminds/webknossos/compare/21.05.1...HEAD)

### Added
-
- Added the option to hide the plane borders and crosshairs in the 3D viewport. Also, this setting was moved from the "Other" section of the user settings to the 3D viewport. Additionally, added a setting to hide the dataset bounding box in the 3D view. [#5440](https://github.com/scalableminds/webknossos/pull/5440)

### Changed
-
Expand All @@ -20,7 +20,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
-

### Removed
-
- Removed the button to load or refresh the isosurface of the centered cell from the 3D view. Instead, this action can be triggered from the "Meshes" tab. [#5440](https://github.com/scalableminds/webknossos/pull/5440)

### Breaking Change
-
2 changes: 1 addition & 1 deletion MIGRATIONS.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ User-facing changes are documented in the [changelog](CHANGELOG.released.md).
-

### Postgres Evolutions:
-
- [071-adapt-td-view-display-planes.sql](conf/evolutions/071-adapt-td-view-display-planes.sql)
25 changes: 10 additions & 15 deletions app/controllers/ConfigurationController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ package controllers

import com.mohiva.play.silhouette.api.Silhouette
import com.scalableminds.util.accesscontext.GlobalAccessContext
import javax.inject.Inject
import models.binary.{DataSetDAO, DataSetService}
import models.configuration.{DataSetConfigurationService, UserConfiguration}
import models.configuration.DataSetConfigurationService
import models.user.UserService
import oxalis.security.{URLSharing, WkEnv}
import play.api.i18n.Messages
import play.api.libs.json.{JsObject, JsValue}
import play.api.libs.json.Json._
import play.api.libs.json.{JsObject, JsValue, Json}
import play.api.mvc.{Action, AnyContent, PlayBodyParsers}
import javax.inject.Inject

import scala.concurrent.ExecutionContext

Expand All @@ -22,19 +21,15 @@ class ConfigurationController @Inject()(
sil: Silhouette[WkEnv])(implicit ec: ExecutionContext, bodyParsers: PlayBodyParsers)
extends Controller {

def read: Action[AnyContent] = sil.UserAwareAction.async { implicit request =>
request.identity.toFox.flatMap { user =>
for {
userConfig <- user.userConfigurationStructured
} yield userConfig.configurationOrDefaults
}.getOrElse(UserConfiguration.default.configuration).map(configuration => Ok(toJson(configuration)))
def read: Action[AnyContent] = sil.UserAwareAction { implicit request =>
val config = request.identity.map(_.userConfiguration).getOrElse(Json.obj())
Ok(Json.toJson(config))
}

def update: Action[JsValue] = sil.SecuredAction.async(parse.json(maxLength = 20480)) { implicit request =>
for {
jsConfiguration <- request.body.asOpt[JsObject] ?~> "user.configuration.invalid"
conf = jsConfiguration.fields.toMap
_ <- userService.updateUserConfiguration(request.identity, UserConfiguration(conf))
configuration <- request.body.asOpt[JsObject] ?~> "user.configuration.invalid"
_ <- userService.updateUserConfiguration(request.identity, configuration)
} yield JsonOk(Messages("user.configuration.updated"))
}

Expand All @@ -55,7 +50,7 @@ class ConfigurationController @Inject()(
organizationName)(ctx)
)
.getOrElse(Map.empty)
.map(configuration => Ok(toJson(configuration)))
.map(configuration => Ok(Json.toJson(configuration)))
}

def updateDataSetViewConfiguration(organizationName: String, dataSetName: String): Action[JsValue] =
Expand All @@ -77,7 +72,7 @@ class ConfigurationController @Inject()(
sil.SecuredAction.async { implicit request =>
dataSetConfigurationService
.getCompleteAdminViewConfiguration(dataSetName, organizationName)
.map(configuration => Ok(toJson(configuration)))
.map(configuration => Ok(Json.toJson(configuration)))
}

def updateDataSetAdminViewConfiguration(organizationName: String, dataSetName: String): Action[JsValue] =
Expand Down
3 changes: 1 addition & 2 deletions app/controllers/InitialDataController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import com.scalableminds.util.tools.{Fox, FoxImplicits}
import com.typesafe.scalalogging.LazyLogging
import models.annotation.{TracingStore, TracingStoreDAO}
import models.binary._
import models.configuration.UserConfiguration
import models.project.{Project, ProjectDAO}
import models.task.{TaskType, TaskTypeDAO}
import models.team._
Expand Down Expand Up @@ -87,7 +86,7 @@ Samplecountry
"SCM",
"Boy",
System.currentTimeMillis(),
Json.toJson(UserConfiguration.default),
Json.obj(),
userService.createLoginInfo(userId),
isAdmin = true,
isDatasetManager = true,
Expand Down
44 changes: 0 additions & 44 deletions app/models/configuration/UserConfiguration.scala

This file was deleted.

23 changes: 11 additions & 12 deletions app/models/user/User.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package models.user

import com.mohiva.play.silhouette.api.{Identity, LoginInfo}
import com.scalableminds.util.accesscontext._
import com.scalableminds.util.tools.{Fox, FoxImplicits, JsonHelper}
import com.scalableminds.util.tools.JsonHelper.parseJsonToFox
import com.scalableminds.util.tools.{Fox, FoxImplicits}
import com.scalableminds.webknossos.datastore.models.datasource.DataSetViewConfiguration.DataSetViewConfiguration
import com.scalableminds.webknossos.datastore.models.datasource.LayerViewConfiguration.LayerViewConfiguration
import com.scalableminds.webknossos.schema.Tables._
import javax.inject.Inject
import models.configuration.UserConfiguration
import models.team._
import play.api.libs.json._
import slick.jdbc.PostgresProfile.api._
Expand All @@ -28,7 +28,7 @@ case class User(
firstName: String,
lastName: String,
lastActivity: Long = System.currentTimeMillis(),
userConfiguration: JsValue,
userConfiguration: JsObject,
loginInfo: LoginInfo,
isAdmin: Boolean,
isDatasetManager: Boolean,
Expand All @@ -48,9 +48,6 @@ case class User(
val abreviatedName: String =
(firstName.take(1) + lastName).toLowerCase.replace(" ", "_")

def userConfigurationStructured: Fox[UserConfiguration] =
JsonHelper.jsResultToFox(userConfiguration.validate[Map[String, JsValue]]).map(UserConfiguration(_))

def isAdminOf(_organization: ObjectId): Boolean =
isAdmin && _organization == this._organization

Expand All @@ -67,15 +64,17 @@ class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext)
def isDeletedColumn(x: Users): Rep[Boolean] = x.isdeleted

def parse(r: UsersRow): Fox[User] =
Fox.successful(
for {
userConfiguration <- parseJsonToFox[JsObject](r.userconfiguration)
} yield {
User(
ObjectId(r._Id),
ObjectId(r._Multiuser),
ObjectId(r._Organization),
r.firstname,
r.lastname,
r.lastactivity.getTime,
Json.parse(r.userconfiguration),
userConfiguration,
LoginInfo(User.default_login_provider_id, r._Id),
r.isadmin,
r.isdatasetmanager,
Expand All @@ -84,7 +83,8 @@ class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext)
r.created.getTime,
r.lasttasktypeid.map(ObjectId(_)),
r.isdeleted
))
)
}

override def readAccessQ(requestingUserId: ObjectId) =
s"""(_id in (select _user from webknossos.user_team_roles where _team in (select _team from webknossos.user_team_roles where _user = '$requestingUserId' and isTeamManager)))
Expand Down Expand Up @@ -203,12 +203,11 @@ class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext)
def updateLastActivity(userId: ObjectId, lastActivity: Long)(implicit ctx: DBAccessContext): Fox[Unit] =
updateTimestampCol(userId, _.lastactivity, new java.sql.Timestamp(lastActivity))

def updateUserConfiguration(userId: ObjectId, userConfiguration: UserConfiguration)(
implicit ctx: DBAccessContext): Fox[Unit] =
def updateUserConfiguration(userId: ObjectId, userConfiguration: JsObject)(implicit ctx: DBAccessContext): Fox[Unit] =
for {
_ <- assertUpdateAccess(userId)
_ <- run(sqlu"""update webknossos.users
set userConfiguration = '#${sanitize(Json.toJson(userConfiguration.configuration).toString)}'
set userConfiguration = '#${sanitize(Json.toJson(userConfiguration).toString)}'
where _id = $userId""")
} yield ()

Expand Down
5 changes: 2 additions & 3 deletions app/models/user/UserService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import com.scalableminds.webknossos.datastore.models.datasource.DataSetViewConfi
import com.scalableminds.webknossos.datastore.models.datasource.LayerViewConfiguration.LayerViewConfiguration
import com.typesafe.scalalogging.LazyLogging
import models.binary.DataSetDAO
import models.configuration.UserConfiguration
import models.team._
import oxalis.mail.{DefaultMails, Send}
import oxalis.security.TokenDAO
Expand Down Expand Up @@ -105,7 +104,7 @@ class UserService @Inject()(conf: WkConf,
firstName,
lastName,
System.currentTimeMillis(),
Json.toJson(UserConfiguration.default),
Json.obj(),
LoginInfo(CredentialsProvider.ID, newUserId.id),
isAdmin,
isDatasetManager = false,
Expand Down Expand Up @@ -201,7 +200,7 @@ class UserService @Inject()(conf: WkConf,
_ <- multiUserDAO.updatePasswordInfo(user._multiUser, passwordInfo)(GlobalAccessContext)
} yield passwordInfo

def updateUserConfiguration(user: User, configuration: UserConfiguration)(implicit ctx: DBAccessContext): Fox[Unit] =
def updateUserConfiguration(user: User, configuration: JsObject)(implicit ctx: DBAccessContext): Fox[Unit] =
userDAO.updateUserConfiguration(user._id, configuration).map { result =>
userCache.invalidateUser(user._id)
result
Expand Down
44 changes: 44 additions & 0 deletions conf/evolutions/071-adapt-td-view-display-planes.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
-- https://github.com/scalableminds/webknossos/pull/5440

START TRANSACTION;

-- Update tdViewDisplayPlanes user configuration setting based on its previous value
-- A previous tdViewDisplayPlanes value of true corresponds to the "DATA" enum value
-- and a value of false corresponds to the "WIREFRAME" enum value

-- For the user configuration
UPDATE webknossos.users
SET userconfiguration = CASE
WHEN jsonb_typeof(userconfiguration->'tdViewDisplayPlanes') = 'boolean' AND (userconfiguration->>'tdViewDisplayPlanes')::boolean IS TRUE THEN jsonb_set(
userconfiguration,
array['tdViewDisplayPlanes'],
to_jsonb('DATA'::text))
ELSE jsonb_set(
userconfiguration,
array['tdViewDisplayPlanes'],
to_jsonb('WIREFRAME'::text))
END
WHERE userconfiguration ? 'tdViewDisplayPlanes';

-- For the recommended configuration in task types
UPDATE webknossos.tasktypes
SET recommendedconfiguration = CASE
WHEN jsonb_typeof(recommendedconfiguration->'tdViewDisplayPlanes') = 'boolean' AND (recommendedconfiguration->>'tdViewDisplayPlanes')::boolean IS TRUE THEN jsonb_set(
recommendedconfiguration,
array['tdViewDisplayPlanes'],
to_jsonb('DATA'::text))
ELSE jsonb_set(
recommendedconfiguration,
array['tdViewDisplayPlanes'],
to_jsonb('WIREFRAME'::text))
END
WHERE recommendedconfiguration ? 'tdViewDisplayPlanes';

-- Remove unused configuration key of user configuration
UPDATE webknossos.users
SET userconfiguration = userconfiguration - 'configuration'
WHERE userconfiguration ? 'configuration';

UPDATE webknossos.releaseInformation SET schemaVersion = 71;

COMMIT TRANSACTION;
37 changes: 37 additions & 0 deletions conf/evolutions/reversions/071-adapt-td-view-display-planes.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
START TRANSACTION;

-- Update tdViewDisplayPlanes user configuration setting based on its previous value
-- A previous tdViewDisplayPlanes value of "DATA" corresponds to true
-- and a value of "WIREFRAME" or "NONE" corresponds to false

-- For the user configuration
UPDATE webknossos.users
SET userconfiguration = CASE
WHEN jsonb_typeof(userconfiguration->'tdViewDisplayPlanes') = 'string' AND userconfiguration->>'tdViewDisplayPlanes' = 'DATA' THEN jsonb_set(
userconfiguration,
array['tdViewDisplayPlanes'],
to_jsonb('true'::boolean))
ELSE jsonb_set(
userconfiguration,
array['tdViewDisplayPlanes'],
to_jsonb('false'::boolean))
END
WHERE userconfiguration ? 'tdViewDisplayPlanes';

-- For the recommended configuration in task types
UPDATE webknossos.tasktypes
SET recommendedconfiguration = CASE
WHEN jsonb_typeof(recommendedconfiguration->'tdViewDisplayPlanes') = 'string' AND recommendedconfiguration->>'tdViewDisplayPlanes' = 'DATA' THEN jsonb_set(
recommendedconfiguration,
array['tdViewDisplayPlanes'],
to_jsonb('true'::boolean))
ELSE jsonb_set(
recommendedconfiguration,
array['tdViewDisplayPlanes'],
to_jsonb('false'::boolean))
END
WHERE recommendedconfiguration ? 'tdViewDisplayPlanes';

UPDATE webknossos.releaseInformation SET schemaVersion = 70;

COMMIT TRANSACTION;
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { jsonEditStyle } from "dashboard/dataset/helper_components";
import { jsonStringify } from "libs/utils";
import { settings } from "messages";
import { validateUserSettingsJSON } from "types/validation";
import { TDViewDisplayModeEnum } from "oxalis/constants";

const FormItem = Form.Item;
const { Panel } = Collapse;
Expand All @@ -20,7 +21,8 @@ const recommendedConfigByCategory = {
displayScalebars: false,
newNodeNewTree: false,
centerNewNode: true,
tdViewDisplayPlanes: false,
tdViewDisplayPlanes: TDViewDisplayModeEnum.WIREFRAME,
tdViewDisplayDatasetBorders: true,
},
all: {
dynamicSpaceDirection: true,
Expand Down Expand Up @@ -70,6 +72,7 @@ export const settingComments = {
clippingDistanceArbitrary: "flight/oblique mode",
moveValue3d: "flight/oblique mode",
loadingStrategy: "BEST_QUALITY_FIRST or PROGRESSIVE_QUALITY",
tdViewDisplayPlanes: Object.values(TDViewDisplayModeEnum).join(" or "),
};

const columns = [
Expand Down
3 changes: 2 additions & 1 deletion frontend/javascripts/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const settings = {
nodeRadius: "Node Radius",
overrideNodeRadius: "Override Node Radius",
particleSize: "Particle Size",
tdViewDisplayPlanes: "Display Planes in 3D View",
tdViewDisplayPlanes: "Plane Display Mode in 3D View",
tdViewDisplayDatasetBorders: "Display Dataset Borders in 3D View",
fourBit: "4 Bit",
interpolation: "Interpolation",
quality: "Quality",
Expand Down
Loading