From 1db5ab18145d2914739434f79eeac1b3596d36b1 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Wed, 19 Dec 2018 15:38:46 +0100 Subject: [PATCH 01/16] redesign spotlight view --- .../javascripts/dashboard/dataset_panel.js | 8 +++-- .../javascripts/dashboard/spotlight_view.js | 30 +++++++++++++++---- app/assets/stylesheets/_dashboard.less | 10 +++++++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/dashboard/dataset_panel.js b/app/assets/javascripts/dashboard/dataset_panel.js index c4da6b65b5e..ae9380bce6d 100644 --- a/app/assets/javascripts/dashboard/dataset_panel.js +++ b/app/assets/javascripts/dashboard/dataset_panel.js @@ -109,7 +109,7 @@ class DatasetPanel extends React.PureComponent { renderCard = (dataset: APIDataset) => ( - + @@ -166,8 +166,10 @@ class DatasetPanel extends React.PureComponent { return (
- {this.props.showOrganizationHeader &&

{this.props.organizationName}

} - + {this.props.showOrganizationHeader && ( +

{this.props.organizationName}

+ )} + {maybeCroppedDatasetsGroup.map(([groupName, datasets]) => ( {datasets.length === 1 diff --git a/app/assets/javascripts/dashboard/spotlight_view.js b/app/assets/javascripts/dashboard/spotlight_view.js index 2f519aa6843..ab9f33ecefc 100644 --- a/app/assets/javascripts/dashboard/spotlight_view.js +++ b/app/assets/javascripts/dashboard/spotlight_view.js @@ -29,7 +29,12 @@ const WelcomeHeader = ({ history }) => ( backgroundImage: "url(https://webknossos.org/images/nature-cover-compressed.jpg)", }} > -
+
( /> -

+

Welcome to webKnossos

webKnossos is an in-browser annotation tool for 3D electron microscopic data that @@ -145,8 +162,9 @@ class SpotlightView extends React.PureComponent { render() { return ( - {this.props.activeUser == null && - (features().allowOrganizationCreation || !this.state.hasOrganizations) ? ( + {true || + (this.props.activeUser == null && + (features().allowOrganizationCreation || !this.state.hasOrganizations)) ? ( ) : ( diff --git a/app/assets/stylesheets/_dashboard.less b/app/assets/stylesheets/_dashboard.less index 5b9064402cc..85e90d937c0 100644 --- a/app/assets/stylesheets/_dashboard.less +++ b/app/assets/stylesheets/_dashboard.less @@ -7,6 +7,14 @@ padding-right: 24px; float: right; } + + .organization-header { + font-weight: 300; + letter-spacing: 4px; + color: #5d5d69; + font-size: 24px; + text-shadow: rgba(0, 0, 0, 0.08) 0px 1px 6px; + } } .dataset-description :first-child { @@ -131,6 +139,8 @@ width: 100%; position: relative; overflow: hidden; + box-shadow: 0 4px 6px hsla(0, 0%, 0%, 0.22), 0 5px 15px hsla(0, 0%, 0%, 0.1); + border-radius: 10px; &:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); From ae67f2234bafbf2c31b5353a6f0982a0740d4248 Mon Sep 17 00:00:00 2001 From: Florian M Date: Mon, 14 Jan 2019 15:54:51 +0100 Subject: [PATCH 02/16] add publication to dataset --- app/models/binary/DataSet.scala | 14 ++++- app/models/binary/DataSetService.scala | 7 +++ app/models/binary/Publication.scala | 56 +++++++++++++++++++ .../036-add-lastTaskTypeId-to-user.sql | 2 +- conf/evolutions/037-add-publications.sql | 25 +++++++++ .../reversions/037-add-publications.sql | 15 +++++ tools/postgres/schema.sql | 13 +++++ 7 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 app/models/binary/Publication.scala create mode 100644 conf/evolutions/037-add-publications.sql create mode 100644 conf/evolutions/reversions/037-add-publications.sql diff --git a/app/models/binary/DataSet.scala b/app/models/binary/DataSet.scala index a1f7ed0ab4a..fa4faec972d 100755 --- a/app/models/binary/DataSet.scala +++ b/app/models/binary/DataSet.scala @@ -35,6 +35,7 @@ case class DataSet( _id: ObjectId, _dataStore: String, _organization: ObjectId, + _publication: Option[ObjectId], defaultConfiguration: Option[DataSetConfiguration] = None, description: Option[String] = None, displayName: Option[String] = None, @@ -46,6 +47,7 @@ case class DataSet( status: String, logoUrl: Option[String], sortingKey: Long = System.currentTimeMillis(), + details: Option[JsObject] = None, created: Long = System.currentTimeMillis(), isDeleted: Boolean = false ) extends FoxImplicits { @@ -80,11 +82,14 @@ class DataSetDAO @Inject()(sqlClient: SQLClient, scale <- parseScaleOpt(r.scale) defaultConfigurationOpt <- Fox.runOptional(r.defaultconfiguration)( JsonHelper.parseJsonToFox[DataSetConfiguration](_)) + details <- Fox.runOptional(r.details)( + JsonHelper.parseJsonToFox[JsObject](_)) } yield { DataSet( ObjectId(r._Id), r._Datastore.trim, ObjectId(r._Organization), + r._Publication.map(ObjectId(_)), defaultConfigurationOpt, r.description, r.displayname, @@ -96,6 +101,7 @@ class DataSetDAO @Inject()(sqlClient: SQLClient, r.status, r.logourl, r.sortingkey.getTime, + details, r.created.getTime, r.isdeleted ) @@ -215,12 +221,14 @@ class DataSetDAO @Inject()(sqlClient: SQLClient, def insertOne(d: DataSet)(implicit ctx: DBAccessContext): Fox[Unit] = { val defaultConfiguration: Option[String] = d.defaultConfiguration.map(c => Json.toJson(c.configuration).toString) + val details: Option[String] = d.details.map(_.toString) for { - _ <- run(sqlu"""insert into webknossos.dataSets(_id, _dataStore, _organization, defaultConfiguration, description, displayName, isPublic, isUsable, name, scale, status, sharingToken, sortingKey, created, isDeleted) - values(${d._id.id}, ${d._dataStore}, ${d._organization.id}, #${optionLiteral( + _ <- run(sqlu"""insert into webknossos.dataSets(_id, _dataStore, _organization, _publication, defaultConfiguration, description, displayName, + isPublic, isUsable, name, scale, status, sharingToken, sortingKey, details, created, isDeleted) + values(${d._id.id}, ${d._dataStore}, ${d._organization.id}, #${optionLiteral(d._publication.map(_.id))}, #${optionLiteral( defaultConfiguration.map(sanitize))}, ${d.description}, ${d.displayName}, ${d.isPublic}, ${d.isUsable}, ${d.name}, #${optionLiteral(d.scale.map(s => writeScaleLiteral(s)))}, ${d.status - .take(1024)}, ${d.sharingToken}, ${new java.sql.Timestamp(d.sortingKey)}, ${new java.sql.Timestamp(d.created)}, ${d.isDeleted}) + .take(1024)}, ${d.sharingToken}, ${new java.sql.Timestamp(d.sortingKey)}, #${optionLiteral(details.map(sanitize))}, ${new java.sql.Timestamp(d.created)}, ${d.isDeleted}) """) } yield () } diff --git a/app/models/binary/DataSetService.scala b/app/models/binary/DataSetService.scala index 93f3ffdd25b..1de0284f40a 100644 --- a/app/models/binary/DataSetService.scala +++ b/app/models/binary/DataSetService.scala @@ -32,6 +32,8 @@ class DataSetService @Inject()(organizationDAO: OrganizationDAO, dataSetLastUsedTimesDAO: DataSetLastUsedTimesDAO, dataSetDataLayerDAO: DataSetDataLayerDAO, teamDAO: TeamDAO, + publicationDAO: PublicationDAO, + publicationService: PublicationService, dataStoreService: DataStoreService, teamService: TeamService, userService: UserService, @@ -66,6 +68,7 @@ class DataSetService @Inject()(organizationDAO: OrganizationDAO, None, None, None, + None, false, dataSource.toUsable.isDefined, dataSource.id.name, @@ -265,6 +268,8 @@ class DataSetService @Inject()(organizationDAO: OrganizationDAO, dataStore <- dataStoreFor(dataSet) dataStoreJs <- dataStoreService.publicWrites(dataStore) dataSource <- dataSourceFor(dataSet, Some(organization), skipResolutions) + publicationOpt <- Fox.runOptional(dataSet._publication)(publicationDAO.findOne(_)) + publicationJson <- Fox.runOptional(publicationOpt)(publicationService.publicWrites(_)) } yield { Json.obj( "name" -> dataSet.name, @@ -281,6 +286,8 @@ class DataSetService @Inject()(organizationDAO: OrganizationDAO, "lastUsedByUser" -> lastUsedByUser, "logoUrl" -> logoUrl, "sortingKey" -> dataSet.sortingKey, + "details" -> dataSet.details, + "publication" -> publicationJson, "isForeign" -> dataStore.isForeign ) } diff --git a/app/models/binary/Publication.scala b/app/models/binary/Publication.scala new file mode 100644 index 00000000000..ac6f1fbccc6 --- /dev/null +++ b/app/models/binary/Publication.scala @@ -0,0 +1,56 @@ +package models.binary + +import com.scalableminds.util.accesscontext.GlobalAccessContext +import com.scalableminds.util.tools.Fox +import com.scalableminds.webknossos.schema.Tables._ +import javax.inject.Inject +import play.api.libs.json.{JsObject, Json} +import slick.lifted.Rep +import utils.{ObjectId, SQLClient, SQLDAO} + +import scala.concurrent.ExecutionContext + +case class Publication( + _id: ObjectId, + publicationDate: Option[Long], + imageUrl: Option[String], + title: Option[String], + details: Option[String], + created: Long = System.currentTimeMillis(), + isDeleted: Boolean = false) + +class PublicationService @Inject()()(implicit ec: ExecutionContext) { + def publicWrites(p: Publication): Fox[JsObject] = { + Fox.successful(Json.obj( + "id" -> p._id.id, + "publicationDate" -> p.publicationDate, + "imageUrl" -> p.imageUrl, + "title" -> p.title, + "details" -> p.details, + "created" -> p.created + )) + } +} + +class PublicationDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) + extends SQLDAO[Publication, PublicationsRow, Publications](sqlClient) { + val collection = Publications + + def idColumn(x: Publications): Rep[String] = x._Id + + def isDeletedColumn(x: Publications): Rep[Boolean] = x.isdeleted + + def parse(r: PublicationsRow): Fox[Publication] = + Fox.successful( + Publication( + ObjectId(r._Id), + r.publicationdate.map(_.getTime), + r.imageurl, + r.title, + r.details, + r.created.getTime, + r.isdeleted + ) + ) +} + diff --git a/conf/evolutions/036-add-lastTaskTypeId-to-user.sql b/conf/evolutions/036-add-lastTaskTypeId-to-user.sql index 6f5650de7fe..ac8ed107f56 100644 --- a/conf/evolutions/036-add-lastTaskTypeId-to-user.sql +++ b/conf/evolutions/036-add-lastTaskTypeId-to-user.sql @@ -1,4 +1,4 @@ --- https://github.com/scalableminds/webknossos/pull/TODO +-- https://github.com/scalableminds/webknossos/pull/3466 START TRANSACTION; diff --git a/conf/evolutions/037-add-publications.sql b/conf/evolutions/037-add-publications.sql new file mode 100644 index 00000000000..33e80ad1206 --- /dev/null +++ b/conf/evolutions/037-add-publications.sql @@ -0,0 +1,25 @@ +-- https://github.com/scalableminds/webknossos/pull/TODO + +START TRANSACTION; + +DROP VIEW webknossos.dataSets_; + +CREATE TABLE webknossos.publications( + _id CHAR(24) PRIMARY KEY DEFAULT '', + publicationDate TIMESTAMPTZ, + imageUrl VARCHAR(2048), + title VARCHAR(2048), + details VARCHAR(4096), + created TIMESTAMPTZ NOT NULL DEFAULT NOW(), + isDeleted BOOLEAN NOT NULL DEFAULT false +); + +ALTER TABLE webknossos.dataSets ADD COLUMN _publication CHAR(24); +ALTER TABLE webknossos.dataSets ADD COLUMN details JSONB; + +CREATE VIEW webknossos.publications_ AS SELECT * FROM webknossos.publications WHERE NOT isDeleted; +CREATE VIEW webknossos.dataSets_ AS SELECT * FROM webknossos.dataSets WHERE NOT isDeleted; + +UPDATE webknossos.releaseInformation SET schemaVersion = 37; + +COMMIT TRANSACTION; diff --git a/conf/evolutions/reversions/037-add-publications.sql b/conf/evolutions/reversions/037-add-publications.sql new file mode 100644 index 00000000000..c9d82f3628c --- /dev/null +++ b/conf/evolutions/reversions/037-add-publications.sql @@ -0,0 +1,15 @@ +START TRANSACTION; + +DROP VIEW webknossos.publications_; +DROP VIEW webknossos.dataSets_; + +ALTER TABLE webknossos.dataSets DROP _publication; +ALTER TABLE webknossos.dataSets DROP details; + +DROP TABLE webknossos.publications; + +CREATE VIEW webknossos.dataSets_ AS SELECT * FROM webknossos.dataSets WHERE NOT isDeleted; + +UPDATE webknossos.releaseInformation SET schemaVersion = 36; + +COMMIT TRANSACTION; diff --git a/tools/postgres/schema.sql b/tools/postgres/schema.sql index e325622aec6..97388cd6cf3 100644 --- a/tools/postgres/schema.sql +++ b/tools/postgres/schema.sql @@ -68,10 +68,21 @@ CREATE TABLE webknossos.meshes( isDeleted BOOLEAN NOT NULL DEFAULT false ); +CREATE TABLE webknossos.publications( + _id CHAR(24) PRIMARY KEY DEFAULT '', + publicationDate TIMESTAMPTZ, + imageUrl VARCHAR(2048), + title VARCHAR(2048), + details VARCHAR(4096), + created TIMESTAMPTZ NOT NULL DEFAULT NOW(), + isDeleted BOOLEAN NOT NULL DEFAULT false +); + CREATE TABLE webknossos.dataSets( _id CHAR(24) PRIMARY KEY DEFAULT '', _dataStore CHAR(256) NOT NULL, _organization CHAR(24) NOT NULL, + _publication CHAR(24), defaultConfiguration JSONB, description TEXT, displayName VARCHAR(256), @@ -83,6 +94,7 @@ CREATE TABLE webknossos.dataSets( sharingToken CHAR(256), logoUrl VARCHAR(2048), sortingKey TIMESTAMPTZ NOT NULL, + details JSONB, created TIMESTAMPTZ NOT NULL DEFAULT NOW(), isDeleted BOOLEAN NOT NULL DEFAULT false, UNIQUE (name, _organization) @@ -298,6 +310,7 @@ INSERT INTO webknossos.maintenance(maintenanceExpirationTime) values('2000-01-01 CREATE VIEW webknossos.analytics_ AS SELECT * FROM webknossos.analytics WHERE NOT isDeleted; CREATE VIEW webknossos.annotations_ AS SELECT * FROM webknossos.annotations WHERE NOT isDeleted; CREATE VIEW webknossos.meshes_ AS SELECT * FROM webknossos.meshes WHERE NOT isDeleted; +CREATE VIEW webknossos.publications_ AS SELECT * FROM webknossos.publications WHERE NOT isDeleted; CREATE VIEW webknossos.dataSets_ AS SELECT * FROM webknossos.dataSets WHERE NOT isDeleted; CREATE VIEW webknossos.dataStores_ AS SELECT * FROM webknossos.dataStores WHERE NOT isDeleted; CREATE VIEW webknossos.tracingStores_ AS SELECT * FROM webknossos.tracingStores WHERE NOT isDeleted; From 8b010c601cbac322f288c6b01da8ce3d970d51e7 Mon Sep 17 00:00:00 2001 From: Florian M Date: Mon, 14 Jan 2019 15:59:35 +0100 Subject: [PATCH 03/16] update migration guide, schema number --- MIGRATIONS.md | 2 +- conf/evolutions/037-add-publications.sql | 2 +- tools/postgres/schema.sql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MIGRATIONS.md b/MIGRATIONS.md index d9a0bd36878..8eb2bcc317c 100644 --- a/MIGRATIONS.md +++ b/MIGRATIONS.md @@ -8,7 +8,7 @@ User-facing changes are documented in the [changelog](CHANGELOG.md). - ### Postgres Evolutions: -- +- [037-add-publications.sql](conf/evolutions/037-add-publications.sql) ## [19.01.0](https://github.com/scalableminds/webknossos/releases/tag/19.01.0) - 2019-01-14 diff --git a/conf/evolutions/037-add-publications.sql b/conf/evolutions/037-add-publications.sql index 33e80ad1206..ca59ef9c942 100644 --- a/conf/evolutions/037-add-publications.sql +++ b/conf/evolutions/037-add-publications.sql @@ -1,4 +1,4 @@ --- https://github.com/scalableminds/webknossos/pull/TODO +-- https://github.com/scalableminds/webknossos/pull/3625 START TRANSACTION; diff --git a/tools/postgres/schema.sql b/tools/postgres/schema.sql index 97388cd6cf3..b34eb785034 100644 --- a/tools/postgres/schema.sql +++ b/tools/postgres/schema.sql @@ -21,7 +21,7 @@ START TRANSACTION; CREATE TABLE webknossos.releaseInformation ( schemaVersion BIGINT NOT NULL ); -INSERT INTO webknossos.releaseInformation(schemaVersion) values(36); +INSERT INTO webknossos.releaseInformation(schemaVersion) values(37); COMMIT TRANSACTION; CREATE TABLE webknossos.analytics( From 04ed7741418bd5ee57125fb6fb267f36789b3848 Mon Sep 17 00:00:00 2001 From: Florian M Date: Mon, 14 Jan 2019 16:18:27 +0100 Subject: [PATCH 04/16] new snapshots + test db --- .../backend-snapshot-tests/datasets.e2e.js.md | 16 ++++++++++++++++ .../datasets.e2e.js.snap | Bin 3653 -> 3702 bytes test/db/dataSets.csv | 14 +++++++------- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.md b/app/assets/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.md index 352f5019c0e..d2a33cecac0 100644 --- a/app/assets/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.md +++ b/app/assets/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.md @@ -150,6 +150,7 @@ Generated by [AVA](https://ava.li). url: 'http://localhost:9000', }, description: null, + details: null, displayName: null, isActive: true, isEditable: true, @@ -159,6 +160,7 @@ Generated by [AVA](https://ava.li). logoUrl: '/images/mpi-logos.svg', name: 'confocal-multi_knossos', owningOrganization: 'Organization_X', + publication: null, sortingKey: 1508495293763, }, { @@ -224,6 +226,7 @@ Generated by [AVA](https://ava.li). url: 'http://localhost:9000', }, description: null, + details: null, displayName: null, isActive: true, isEditable: true, @@ -233,6 +236,7 @@ Generated by [AVA](https://ava.li). logoUrl: '/images/mpi-logos.svg', name: 'e2006_knossos', owningOrganization: 'Organization_X', + publication: null, sortingKey: 1508495293789, }, ] @@ -264,6 +268,7 @@ Generated by [AVA](https://ava.li). url: 'http://localhost:9000', }, description: null, + details: null, displayName: null, isActive: false, isEditable: true, @@ -273,6 +278,7 @@ Generated by [AVA](https://ava.li). logoUrl: '/images/mpi-logos.svg', name: '2012-06-28_Cortex', owningOrganization: 'Organization_X', + publication: null, sortingKey: 1460379470082, }, { @@ -299,6 +305,7 @@ Generated by [AVA](https://ava.li). url: 'http://localhost:9000', }, description: null, + details: null, displayName: null, isActive: false, isEditable: true, @@ -308,6 +315,7 @@ Generated by [AVA](https://ava.li). logoUrl: '/images/mpi-logos.svg', name: '2012-09-28_ex145_07x2', owningOrganization: 'Organization_X', + publication: null, sortingKey: 1460379470080, }, { @@ -334,6 +342,7 @@ Generated by [AVA](https://ava.li). url: 'http://localhost:9000', }, description: null, + details: null, displayName: null, isActive: false, isEditable: true, @@ -343,6 +352,7 @@ Generated by [AVA](https://ava.li). logoUrl: '/images/mpi-logos.svg', name: 'Experiment_001', owningOrganization: 'Organization_X', + publication: null, sortingKey: 1460379470079, }, { @@ -422,6 +432,7 @@ Generated by [AVA](https://ava.li). url: 'http://localhost:9000', }, description: null, + details: null, displayName: null, isActive: true, isEditable: true, @@ -431,6 +442,7 @@ Generated by [AVA](https://ava.li). logoUrl: '/images/mpi-logos.svg', name: 'confocal-multi_knossos', owningOrganization: 'Organization_X', + publication: null, sortingKey: 1508495293763, }, { @@ -496,6 +508,7 @@ Generated by [AVA](https://ava.li). url: 'http://localhost:9000', }, description: null, + details: null, displayName: null, isActive: true, isEditable: true, @@ -505,6 +518,7 @@ Generated by [AVA](https://ava.li). logoUrl: '/images/mpi-logos.svg', name: 'e2006_knossos', owningOrganization: 'Organization_X', + publication: null, sortingKey: 1508495293789, }, { @@ -531,6 +545,7 @@ Generated by [AVA](https://ava.li). url: 'http://localhost:9000', }, description: null, + details: null, displayName: null, isActive: false, isEditable: true, @@ -540,6 +555,7 @@ Generated by [AVA](https://ava.li). logoUrl: '/images/mpi-logos.svg', name: 'rgb', owningOrganization: 'Organization_X', + publication: null, sortingKey: 1460379603792, }, ] diff --git a/app/assets/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.snap b/app/assets/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.snap index 33030da2019cdd290140354a616f5fb1991f5f28..14b39a432b9fb8f80b949cec1a66aa95dcec32df 100644 GIT binary patch literal 3702 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 X4*W`W=k Date: Mon, 14 Jan 2019 16:22:31 +0100 Subject: [PATCH 05/16] scalafmt --- app/models/binary/DataSet.scala | 11 +++++---- app/models/binary/Publication.scala | 38 ++++++++++++++--------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/app/models/binary/DataSet.scala b/app/models/binary/DataSet.scala index fa4faec972d..1e01517865d 100755 --- a/app/models/binary/DataSet.scala +++ b/app/models/binary/DataSet.scala @@ -82,8 +82,7 @@ class DataSetDAO @Inject()(sqlClient: SQLClient, scale <- parseScaleOpt(r.scale) defaultConfigurationOpt <- Fox.runOptional(r.defaultconfiguration)( JsonHelper.parseJsonToFox[DataSetConfiguration](_)) - details <- Fox.runOptional(r.details)( - JsonHelper.parseJsonToFox[JsObject](_)) + details <- Fox.runOptional(r.details)(JsonHelper.parseJsonToFox[JsObject](_)) } yield { DataSet( ObjectId(r._Id), @@ -223,12 +222,14 @@ class DataSetDAO @Inject()(sqlClient: SQLClient, val defaultConfiguration: Option[String] = d.defaultConfiguration.map(c => Json.toJson(c.configuration).toString) val details: Option[String] = d.details.map(_.toString) for { - _ <- run(sqlu"""insert into webknossos.dataSets(_id, _dataStore, _organization, _publication, defaultConfiguration, description, displayName, + _ <- run( + sqlu"""insert into webknossos.dataSets(_id, _dataStore, _organization, _publication, defaultConfiguration, description, displayName, isPublic, isUsable, name, scale, status, sharingToken, sortingKey, details, created, isDeleted) values(${d._id.id}, ${d._dataStore}, ${d._organization.id}, #${optionLiteral(d._publication.map(_.id))}, #${optionLiteral( - defaultConfiguration.map(sanitize))}, ${d.description}, ${d.displayName}, ${d.isPublic}, ${d.isUsable}, + defaultConfiguration.map(sanitize))}, ${d.description}, ${d.displayName}, ${d.isPublic}, ${d.isUsable}, ${d.name}, #${optionLiteral(d.scale.map(s => writeScaleLiteral(s)))}, ${d.status - .take(1024)}, ${d.sharingToken}, ${new java.sql.Timestamp(d.sortingKey)}, #${optionLiteral(details.map(sanitize))}, ${new java.sql.Timestamp(d.created)}, ${d.isDeleted}) + .take(1024)}, ${d.sharingToken}, ${new java.sql.Timestamp(d.sortingKey)}, #${optionLiteral( + details.map(sanitize))}, ${new java.sql.Timestamp(d.created)}, ${d.isDeleted}) """) } yield () } diff --git a/app/models/binary/Publication.scala b/app/models/binary/Publication.scala index ac6f1fbccc6..c195e1fc1f5 100644 --- a/app/models/binary/Publication.scala +++ b/app/models/binary/Publication.scala @@ -10,30 +10,29 @@ import utils.{ObjectId, SQLClient, SQLDAO} import scala.concurrent.ExecutionContext -case class Publication( - _id: ObjectId, - publicationDate: Option[Long], - imageUrl: Option[String], - title: Option[String], - details: Option[String], - created: Long = System.currentTimeMillis(), - isDeleted: Boolean = false) +case class Publication(_id: ObjectId, + publicationDate: Option[Long], + imageUrl: Option[String], + title: Option[String], + details: Option[String], + created: Long = System.currentTimeMillis(), + isDeleted: Boolean = false) class PublicationService @Inject()()(implicit ec: ExecutionContext) { - def publicWrites(p: Publication): Fox[JsObject] = { - Fox.successful(Json.obj( - "id" -> p._id.id, - "publicationDate" -> p.publicationDate, - "imageUrl" -> p.imageUrl, - "title" -> p.title, - "details" -> p.details, - "created" -> p.created - )) - } + def publicWrites(p: Publication): Fox[JsObject] = + Fox.successful( + Json.obj( + "id" -> p._id.id, + "publicationDate" -> p.publicationDate, + "imageUrl" -> p.imageUrl, + "title" -> p.title, + "details" -> p.details, + "created" -> p.created + )) } class PublicationDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) - extends SQLDAO[Publication, PublicationsRow, Publications](sqlClient) { + extends SQLDAO[Publication, PublicationsRow, Publications](sqlClient) { val collection = Publications def idColumn(x: Publications): Rep[String] = x._Id @@ -53,4 +52,3 @@ class PublicationDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionConte ) ) } - From 95ebe82e1a208e9a82240368fa6e0d5510a88df0 Mon Sep 17 00:00:00 2001 From: Daniel Werner Date: Tue, 15 Jan 2019 14:21:28 +0100 Subject: [PATCH 06/16] minor cleanup --- app/assets/javascripts/dashboard/spotlight_view.js | 5 ++--- app/assets/stylesheets/_dashboard.less | 14 +++----------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/dashboard/spotlight_view.js b/app/assets/javascripts/dashboard/spotlight_view.js index e3aaef28766..58dcb450f9e 100644 --- a/app/assets/javascripts/dashboard/spotlight_view.js +++ b/app/assets/javascripts/dashboard/spotlight_view.js @@ -158,9 +158,8 @@ class SpotlightView extends React.PureComponent { render() { return ( - {true || - (this.props.activeUser == null && - (features().allowOrganizationCreation || !this.state.hasOrganizations)) ? ( + {this.props.activeUser == null && + (features().allowOrganizationCreation || !this.state.hasOrganizations) ? ( ) : ( diff --git a/app/assets/stylesheets/_dashboard.less b/app/assets/stylesheets/_dashboard.less index b740abfba18..c38abd26bae 100644 --- a/app/assets/stylesheets/_dashboard.less +++ b/app/assets/stylesheets/_dashboard.less @@ -7,14 +7,6 @@ padding-right: 24px; float: right; } - - .organization-header { - font-weight: 300; - letter-spacing: 4px; - color: #5d5d69; - font-size: 24px; - text-shadow: rgba(0, 0, 0, 0.08) 0px 1px 6px; - } } .dataset-description :first-child { @@ -146,11 +138,11 @@ width: 100%; position: relative; overflow: hidden; - box-shadow: 0 4px 6px hsla(0, 0%, 0%, 0.22), 0 5px 15px hsla(0, 0%, 0%, 0.1); - border-radius: 10px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + border-radius: 6px; &:hover { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + box-shadow: 0 4px 6px hsla(0, 0%, 0%, 0.22), 0 5px 15px hsla(0, 0%, 0%, 0.1); transform: translateY(-2px); .dataset-thumbnail-image { From 25de7c3b9819ce0aec6cfa628a95e260aededa19 Mon Sep 17 00:00:00 2001 From: Daniel Werner Date: Wed, 16 Jan 2019 15:15:53 +0100 Subject: [PATCH 07/16] first version of spotlight redesign with grouped publications --- .../javascripts/admin/api_flow_types.js | 11 + .../javascripts/dashboard/dataset_panel.js | 275 +++++++++++------- app/assets/javascripts/oxalis/store.js | 2 + app/assets/stylesheets/_dashboard.less | 70 ++++- 4 files changed, 250 insertions(+), 108 deletions(-) diff --git a/app/assets/javascripts/admin/api_flow_types.js b/app/assets/javascripts/admin/api_flow_types.js index 8e466d9120c..52dd65f7bac 100644 --- a/app/assets/javascripts/admin/api_flow_types.js +++ b/app/assets/javascripts/admin/api_flow_types.js @@ -78,6 +78,15 @@ export type APITeam = { +organization: string, }; +type APIPublication = { + +created: number, + +details: string, + +id: string, + +imageUrl: string, + +publicationDate: number, + +title: string, +}; + export type APIDatasetId = { +owningOrganization: string, +name: string, @@ -88,6 +97,7 @@ type APIDatasetBase = APIDatasetId & { +created: number, +dataStore: APIDataStore, +description: ?string, + +details: ?Object, +isEditable: boolean, +isPublic: boolean, +displayName: ?string, @@ -95,6 +105,7 @@ type APIDatasetBase = APIDatasetId & { +lastUsedByUser: number, +isForeign: boolean, +sortingKey: number, + +publication: ?APIPublication, }; export type APIMaybeUnimportedDataset = APIDatasetBase & { diff --git a/app/assets/javascripts/dashboard/dataset_panel.js b/app/assets/javascripts/dashboard/dataset_panel.js index 6b3cbab39c6..32afaf75ab5 100644 --- a/app/assets/javascripts/dashboard/dataset_panel.js +++ b/app/assets/javascripts/dashboard/dataset_panel.js @@ -1,10 +1,11 @@ // @flow -import { Row, Col, Card, Popover } from "antd"; +import { Row, Col, Card, Button } from "antd"; import Markdown from "react-remarkable"; import * as React from "react"; import _ from "lodash"; +import classNames from "classnames"; -import type { APIDataset } from "admin/api_flow_types"; +import type { APIDataset, APIDatasetId } from "admin/api_flow_types"; import { formatScale } from "libs/format_utils"; import { getThumbnailURL, @@ -12,19 +13,9 @@ import { getSegmentationThumbnailURL, } from "oxalis/model/accessors/dataset_accessor"; -const columnSpan = { xs: 24, sm: 24, md: 24, lg: 12, xl: 12, xxl: 8 }; +const columnSpan = { xs: 24, sm: 24, md: 24, lg: 24, xl: 12, xxl: 12 }; const thumbnailDimension = 500; - -type Props = { - datasets: Array, - organizationName: string, - showOrganizationHeader: boolean, - croppedDatasetCount: ?number, -}; - -type State = { - showLessContent: boolean, -}; +const miniThumbnailDimension = 50; function getDisplayName(dataset: APIDataset): string { return dataset.displayName != null && dataset.displayName !== "" @@ -49,141 +40,215 @@ function getDescription(dataset: APIDataset) { ); } - return ( -

-

Scale: {formatScale(dataset.dataSource.scale)}

- {freeTextDescription} -
- ); + return
{freeTextDescription}
; +} + +function getDetails(dataset: APIDataset) { + const { dataSource, details } = dataset; + return { scale: formatScale(dataSource.scale), name: dataset.name, ...details }; } function ThumbnailAndDescription({ thumbnailURL, description, + details, name, + datasetId, segmentationThumbnailURL, }: { thumbnailURL: string, name: string, + datasetId: APIDatasetId, description: React.Element<*> | string, + details: Object, segmentationThumbnailURL: ?string, }) { return ( - -
- {segmentationThumbnailURL ? ( -
- ) : null} -
-

{name}

+

{name}

{description}
+ + +
Click To View
+
+ {segmentationThumbnailURL ? ( +
+ ) : null} +
+
+ {details.name} +
+
+ {details.species && ( +
+ {details.species} +
+ )} + {details["brain-region"] && ( +
+ {details["brain-region"]} +
+ )} +
+
+ {details.acquisition && ( +
+ {details.acquisition} +
+ )} + {details.scale && ( + + Scale: {details.scale} + + )} +
+
+
+ ); } -function ThumbnailAndDescriptionFromDataset({ dataset }: { dataset: APIDataset }) { +function DatasetCard({ dataset }: { dataset: APIDataset }) { return ( - + + + ); } -class DatasetPanel extends React.PureComponent { - constructor(props: Props) { - super(props); - this.state = { - showLessContent: true, - }; - } +type MultiDatasetCardProps = { datasets: Array }; +type MultiDatasetCardState = { selectedDataset: APIDataset, hoveredDataset: ?APIDataset }; - handleClick = () => { - this.setState(prevState => ({ showLessContent: !prevState.showLessContent })); +class MultiDatasetCard extends React.PureComponent { + state = { + selectedDataset: this.props.datasets[0], + hoveredDataset: null, }; - renderCard = (dataset: APIDataset) => ( - - - - - - ); + render() { + const { datasets } = this.props; + const { selectedDataset, hoveredDataset } = this.state; + const activeDataset = hoveredDataset || selectedDataset; + const { publication } = activeDataset; + // This method will only be called for datasets with a publication, but Flow doesn't know that + if (publication == null) return null; - renderMultiDatasetCard = (groupName: string, datasets: APIDataset[]) => { const multiDescription = ( -
- This collection consists of multiple datasets: -
    - {datasets.map(dataset => { - const popoverContent = ( -
    - -
    - ); - return ( -
  • - - {getDisplayName(dataset)} - -
  • - ); - })} -
+
+ {publication.details} +
+ Published Datasets +
+ {datasets.map(dataset => ( +
+
); return ( - + ); + } +} + +type DatasetPanelProps = { + datasets: Array, + organizationName: string, + showOrganizationHeader: boolean, + croppedDatasetCount: ?number, +}; + +type DatasetPanelState = { + showLessContent: boolean, +}; + +class DatasetPanel extends React.PureComponent { + state = { + showLessContent: true, + }; + + handleClick = () => { + this.setState(prevState => ({ showLessContent: !prevState.showLessContent })); }; render() { const groupedDatasets = _.entries( - // Instead of dataset.name, this could be grouped by a group tag - _.groupBy(this.props.datasets, dataset => dataset.name), + _.groupBy( + this.props.datasets, + dataset => (dataset.publication != null ? dataset.publication.id : dataset.name), + ), ); const maybeCroppedDatasetsGroup = this.state.showLessContent && this.props.croppedDatasetCount != null @@ -198,9 +263,11 @@ class DatasetPanel extends React.PureComponent { {maybeCroppedDatasetsGroup.map(([groupName, datasets]) => ( - {datasets.length === 1 - ? this.renderCard(datasets[0]) - : this.renderMultiDatasetCard(groupName, datasets)} + {datasets[0].publication == null ? ( + + ) : ( + + )} ))} diff --git a/app/assets/javascripts/oxalis/store.js b/app/assets/javascripts/oxalis/store.js index 82f651908c9..9408fa47bba 100644 --- a/app/assets/javascripts/oxalis/store.js +++ b/app/assets/javascripts/oxalis/store.js @@ -462,6 +462,7 @@ export const defaultState: OxalisState = { team: "", }, }, + details: null, isPublic: false, isActive: true, isEditable: true, @@ -478,6 +479,7 @@ export const defaultState: OxalisState = { lastUsedByUser: 0, isForeign: false, sortingKey: 123, + publication: null, }, tracing: { ...initialAnnotationInfo, diff --git a/app/assets/stylesheets/_dashboard.less b/app/assets/stylesheets/_dashboard.less index c38abd26bae..256124128b8 100644 --- a/app/assets/stylesheets/_dashboard.less +++ b/app/assets/stylesheets/_dashboard.less @@ -7,6 +7,11 @@ padding-right: 24px; float: right; } + + .organization-header { + font-size: 24px; + text-transform: uppercase; + } } .dataset-description :first-child { @@ -22,6 +27,7 @@ } .dataset-thumbnail { + left: 50%; height: 100%; width: 50%; display: inline-block; @@ -37,8 +43,43 @@ .dataset-thumbnail-image { transition: all 0.3s ease-in-out; + background-size: cover; + width: 100%; + height: 100%; &.segmentation { opacity: 0; + position: absolute; + left: 0; + top: 0; + } +} + +.dataset-thumbnail-overlay { + width: 100%; + height: 100px; + bottom: 0; + position: absolute; + background-color: rgba(0, 0, 0, 0.85); + padding: 5px 15px; + color: rgba(255, 255, 255, 0.95); + display: flex; + flex-direction: column; +} + +.dataset-click-hint { + opacity: 0; + width: 100%; + height: 100%; + position: absolute; + text-align: center; + color: white; + z-index: 100; + line-height: 400px; + font-size: 20px; + + &:hover { + background-color: rgba(0, 0, 0, 0.6); + opacity: 1; } } @@ -52,10 +93,10 @@ bottom: 0px; width: 50%; height: 100%; - padding-top: 16px; - padding-left: 16px; + padding: 16px; overflow-y: auto; background-color: white; + z-index: 1; @media @smartphones { padding-top: 24px; padding-left: 24px; @@ -85,7 +126,7 @@ .dataset-description-body { width: 100%; - height: 240px; + height: 100%; overflow-y: auto; @media @smartphones { height: 243px; @@ -134,7 +175,7 @@ } .spotlight-item-card { - height: 300px; + height: 400px; width: 100%; position: relative; overflow: hidden; @@ -161,6 +202,27 @@ } } +.mini-dataset-thumbnail-grid { + display: grid; + grid-gap: 10px; + grid-template-columns: repeat(auto-fill, 50px); + padding: 5px; +} + +.mini-dataset-thumbnail { + opacity: 0.5; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + background-size: cover; + + &:hover, + &.active { + opacity: 1; + } + &:active { + transform: scale(1.1); + } +} + .dataset-actions { a { display: block; From 3f8de315ce180b78758f0e3c80eabe1d850f9335 Mon Sep 17 00:00:00 2001 From: Daniel Werner Date: Mon, 21 Jan 2019 15:41:27 +0100 Subject: [PATCH 08/16] make dataset gallery publication gallery --- .../javascripts/dashboard/dashboard_view.js | 8 +- .../javascripts/dashboard/dataset_view.js | 2 +- .../dashboard/gallery_dataset_view.js | 77 ++++----- .../{dataset_panel.js => publication_card.js} | 146 ++++-------------- .../javascripts/dashboard/spotlight_view.js | 27 +++- app/assets/stylesheets/_dashboard.less | 20 +-- 6 files changed, 86 insertions(+), 194 deletions(-) rename app/assets/javascripts/dashboard/{dataset_panel.js => publication_card.js} (58%) diff --git a/app/assets/javascripts/dashboard/dashboard_view.js b/app/assets/javascripts/dashboard/dashboard_view.js index 2c746f9e070..b81a26d49b6 100644 --- a/app/assets/javascripts/dashboard/dashboard_view.js +++ b/app/assets/javascripts/dashboard/dashboard_view.js @@ -21,7 +21,7 @@ import Request from "libs/request"; const TabPane = Tabs.TabPane; -const validTabKeys = ["datasets", "advanced-datasets", "tasks", "explorativeAnnotations"]; +const validTabKeys = ["publications", "advanced-datasets", "tasks", "explorativeAnnotations"]; type OwnProps = { userId: ?string, @@ -57,7 +57,7 @@ export const datasetCache = { }; export const urlTokenToTabKeyMap = { - gallery: "datasets", + gallery: "publications", datasets: "advanced-datasets", tasks: "tasks", annotations: "explorativeAnnotations", @@ -151,7 +151,7 @@ class DashboardView extends React.PureComponent { getTabs(user: APIUser) { if (this.props.activeUser) { - const isAdminView = this.props.isAdminView; + const { isAdminView } = this.props; const datasetViewProps = { user, @@ -162,7 +162,7 @@ class DashboardView extends React.PureComponent { return [ !isAdminView ? ( - + ) : null, diff --git a/app/assets/javascripts/dashboard/dataset_view.js b/app/assets/javascripts/dashboard/dataset_view.js index 0e79b999cb2..2e88b641bfa 100644 --- a/app/assets/javascripts/dashboard/dataset_view.js +++ b/app/assets/javascripts/dashboard/dataset_view.js @@ -144,7 +144,7 @@ class DatasetView extends React.PureComponent { return (
{adminHeader} -

Datasets

+

{isGallery ? "Publications" : "Datasets"}

{content} diff --git a/app/assets/javascripts/dashboard/gallery_dataset_view.js b/app/assets/javascripts/dashboard/gallery_dataset_view.js index b47a85b67d9..d60c222789b 100644 --- a/app/assets/javascripts/dashboard/gallery_dataset_view.js +++ b/app/assets/javascripts/dashboard/gallery_dataset_view.js @@ -1,14 +1,20 @@ // @flow import * as React from "react"; import _ from "lodash"; +import { List } from "antd"; import type { APIDataset, APIMaybeUnimportedDataset } from "admin/api_flow_types"; -import { getOrganizations } from "admin/admin_rest_api"; -import DatasetPanel from "dashboard/dataset_panel"; +import PublicationCard from "dashboard/publication_card"; import * as Utils from "libs/utils"; -type State = { - organizationNameMap: { [key: string]: string }, +const gridValues = { + gutter: 24, + xs: 1, + sm: 1, + md: 1, + lg: 1, + xl: 2, + xxl: 2, }; type Props = { @@ -16,67 +22,40 @@ type Props = { searchQuery: string, }; -const croppedDatasetCount = 6; - -class GalleryDatasetView extends React.PureComponent { - state = { - organizationNameMap: {}, - }; - - componentDidMount() { - this.fetch(); - } - - async fetch() { - const organizations = await getOrganizations(); - - this.setState({ - organizationNameMap: _.mapValues(_.keyBy(organizations, "name"), org => org.displayName), - }); - } - +class GalleryDatasetView extends React.PureComponent { render() { // $FlowFixMe flow doesn't check that after filtering there are only imported datasets left const activeDatasets: Array = this.props.datasets.filter(ds => ds.isActive); const filteredDatasets = Utils.filterWithSearchQueryAND( activeDatasets, - ["name", "description"], + ["name", "description", "details"], this.props.searchQuery, ); - const groupedDatasets = _.chain(filteredDatasets) - .groupBy("owningOrganization") - .entries() - .map(([organization, datasets]) => - // Sort each group of datasets - [ - organization, - datasets.sort(Utils.compareBy(([]: APIDataset[]), dataset => dataset.sortingKey, false)), - ], - ) - .value() + const datasetsByPublication = _.chain(filteredDatasets) + .filter(dataset => dataset.publication != null) + .groupBy("publication.id") + .values() .sort( - // Sort groups by creation date of first dataset + // Sort publication groups by publication creation date Utils.compareBy( - ([]: Array<[string, Array]>), - ([_organization, datasets]) => datasets[0].sortingKey, + ([]: Array), + datasets => datasets[0].publication.publicationDate, false, ), ); - const hasMultipleOrganizations = groupedDatasets.length > 1; return ( - {groupedDatasets.map(([organization, datasets]) => ( - - ))} + ( + + + + )} + /> ); } diff --git a/app/assets/javascripts/dashboard/dataset_panel.js b/app/assets/javascripts/dashboard/publication_card.js similarity index 58% rename from app/assets/javascripts/dashboard/dataset_panel.js rename to app/assets/javascripts/dashboard/publication_card.js index 856a67e6275..1f402f8ed04 100644 --- a/app/assets/javascripts/dashboard/dataset_panel.js +++ b/app/assets/javascripts/dashboard/publication_card.js @@ -1,8 +1,7 @@ // @flow -import { Row, Col, Card, Button } from "antd"; +import { Card, Button } from "antd"; import Markdown from "react-remarkable"; import * as React from "react"; -import _ from "lodash"; import classNames from "classnames"; import type { APIDataset, APIDatasetId } from "admin/api_flow_types"; @@ -13,7 +12,6 @@ import { getSegmentationThumbnailURL, } from "oxalis/model/accessors/dataset_accessor"; -const columnSpan = { xs: 24, sm: 24, md: 24, lg: 24, xl: 12, xxl: 12 }; const thumbnailDimension = 500; const miniThumbnailDimension = 50; @@ -23,51 +21,32 @@ function getDisplayName(dataset: APIDataset): string { : dataset.name; } -function getDescription(dataset: APIDataset) { - let freeTextDescription = null; - if (dataset.description) { - freeTextDescription = ( - - ); - } else { - freeTextDescription = hasSegmentation(dataset) ? ( -

Original data and segmentation

- ) : ( -

Original data

- ); - } - - return
{freeTextDescription}
; -} - function getDetails(dataset: APIDataset) { const { dataSource, details } = dataset; - return { scale: formatScale(dataSource.scale), name: dataset.name, ...details }; + return { scale: formatScale(dataSource.scale), name: getDisplayName(dataset), ...details }; } function ThumbnailAndDescription({ thumbnailURL, description, - details, - name, + datasetDetails, + publicationName, datasetId, segmentationThumbnailURL, }: { thumbnailURL: string, - name: string, + publicationName: string, datasetId: APIDatasetId, description: React.Element<*> | string, - details: Object, + datasetDetails: Object, segmentationThumbnailURL: ?string, }) { + const details = datasetDetails; return (
-

{name}

+

{publicationName}

{description}
@@ -139,27 +118,10 @@ function ThumbnailAndDescription({ ); } -function DatasetCard({ dataset }: { dataset: APIDataset }) { - return ( - - - - ); -} +type Props = { datasets: Array }; +type State = { selectedDataset: APIDataset, hoveredDataset: ?APIDataset }; -type MultiDatasetCardProps = { datasets: Array }; -type MultiDatasetCardState = { selectedDataset: APIDataset, hoveredDataset: ?APIDataset }; - -class MultiDatasetCard extends React.PureComponent { +class PublicationCard extends React.PureComponent { state = { selectedDataset: this.props.datasets[0], hoveredDataset: null, @@ -173,18 +135,23 @@ class MultiDatasetCard extends React.PureComponent - {publication.description} + + +
Published Datasets
{datasets.map(dataset => (
diff --git a/app/assets/javascripts/dashboard/gallery_dataset_view.js b/app/assets/javascripts/dashboard/publication_view.js similarity index 94% rename from app/assets/javascripts/dashboard/gallery_dataset_view.js rename to app/assets/javascripts/dashboard/publication_view.js index d60c222789b..d806503a8f4 100644 --- a/app/assets/javascripts/dashboard/gallery_dataset_view.js +++ b/app/assets/javascripts/dashboard/publication_view.js @@ -22,7 +22,7 @@ type Props = { searchQuery: string, }; -class GalleryDatasetView extends React.PureComponent { +class PublicationView extends React.PureComponent { render() { // $FlowFixMe flow doesn't check that after filtering there are only imported datasets left const activeDatasets: Array = this.props.datasets.filter(ds => ds.isActive); @@ -61,4 +61,4 @@ class GalleryDatasetView extends React.PureComponent { } } -export default GalleryDatasetView; +export default PublicationView; diff --git a/app/assets/javascripts/dashboard/spotlight_view.js b/app/assets/javascripts/dashboard/spotlight_view.js index 8cdb8fe53dd..b420aff45ae 100644 --- a/app/assets/javascripts/dashboard/spotlight_view.js +++ b/app/assets/javascripts/dashboard/spotlight_view.js @@ -8,7 +8,7 @@ import type { APIMaybeUnimportedDataset, APIUser } from "admin/api_flow_types"; import type { OxalisState } from "oxalis/store"; import { getOrganizations, getDatasets } from "admin/admin_rest_api"; import { handleGenericError } from "libs/error_handling"; -import GalleryDatasetView from "dashboard/gallery_dataset_view"; +import PublicationView from "dashboard/publication_view"; import features from "features"; const { Content, Footer } = Layout; @@ -194,7 +194,7 @@ class SpotlightView extends React.PureComponent { in action.

) : ( - diff --git a/app/assets/stylesheets/_dashboard.less b/app/assets/stylesheets/_dashboard.less index 007eb82dfce..93ac82c8e6e 100644 --- a/app/assets/stylesheets/_dashboard.less +++ b/app/assets/stylesheets/_dashboard.less @@ -187,7 +187,6 @@ .mini-dataset-thumbnail-grid { display: grid; grid-gap: 10px; - grid-template-columns: repeat(auto-fill, 50px); padding: 5px; } @@ -201,7 +200,7 @@ opacity: 1; } &:active { - transform: scale(1.1); + transform: scale(1.05); } } From 1e0a890d5a3911bc1d22f34230bfbebeb7af0eb2 Mon Sep 17 00:00:00 2001 From: Daniel Werner Date: Wed, 23 Jan 2019 17:46:18 +0100 Subject: [PATCH 12/16] refresh snapshots --- .../test/enzyme/snapshot.e2e.js.md | 40 ++++++++++++------ .../test/enzyme/snapshot.e2e.js.snap | Bin 29426 -> 29492 bytes 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.md b/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.md index f3b21a3fa50..19985b66778 100644 --- a/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.md +++ b/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.md @@ -109,7 +109,7 @@ Generated by [AVA](https://ava.li).
␊ - ␊ +
␊ @@ -129,7 +129,7 @@ Generated by [AVA](https://ava.li).
␊ -
␊ + ␊
␊ @@ -273,7 +273,7 @@ Generated by [AVA](https://ava.li).
␊ - ␊ +
␊ @@ -293,7 +293,7 @@ Generated by [AVA](https://ava.li).
␊ -
␊ + ␊
␊ @@ -615,12 +615,14 @@ Generated by [AVA](https://ava.li). ␊ Reload␊ ␊ - ␊ + ␊ + ␊ View␊ ␊ + ␊ skeleton icon␊ Start Skeleton Tracing␊ @@ -790,12 +792,14 @@ Generated by [AVA](https://ava.li). ␊ Reload␊ ␊ - ␊ + ␊ + ␊ View␊ ␊ + ␊ skeleton icon␊ Start Skeleton Tracing␊ @@ -1456,7 +1460,7 @@ Generated by [AVA](https://ava.li).
␊ - ␊ +
␊ @@ -1476,7 +1480,7 @@ Generated by [AVA](https://ava.li).
␊ -
␊ + ␊
␊ @@ -1798,12 +1802,14 @@ Generated by [AVA](https://ava.li). ␊ Reload␊
␊ - ␊ + ␊ + ␊ View␊ ␊ + ␊ skeleton icon␊ Start Skeleton Tracing␊ @@ -1973,12 +1979,14 @@ Generated by [AVA](https://ava.li). ␊ Reload␊ ␊ - ␊ + ␊ + ␊ View␊ ␊ + ␊ skeleton icon␊ Start Skeleton Tracing␊ @@ -3628,7 +3636,7 @@ Generated by [AVA](https://ava.li).
␊ - ␊ +
␊ @@ -3648,7 +3656,7 @@ Generated by [AVA](https://ava.li).
␊ -
␊ + ␊
␊ @@ -3970,12 +3978,14 @@ Generated by [AVA](https://ava.li). ␊ Reload␊
␊ - ␊ + ␊ + ␊ View␊ ␊ + ␊ skeleton icon␊ Start Skeleton Tracing␊ @@ -4145,12 +4155,14 @@ Generated by [AVA](https://ava.li). ␊ Reload␊ ␊ - ␊ + ␊ + ␊ View␊ ␊ + ␊ skeleton icon␊ Start Skeleton Tracing␊ diff --git a/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.snap b/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.snap index 77e0d0cecc136e086bf5cafcfc0698878eb1a11b..a0fa5e86073b0bdcc94436a3e207c6abd50ad77c 100644 GIT binary patch delta 24875 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%0Dv8Ma}TwV`p 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 From 613d428c6412f9d0d6382edc9be5d6357edbf3b3 Mon Sep 17 00:00:00 2001 From: Daniel Werner Date: Thu, 24 Jan 2019 13:32:26 +0100 Subject: [PATCH 13/16] also show segmentation in mini thumbnail, update changelog --- CHANGELOG.md | 1 + app/assets/javascripts/dashboard/publication_card.js | 11 ++++++++++- app/assets/stylesheets/_dashboard.less | 8 ++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e839bcd3125..331854ca048 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.md). ### Changed +- The Dataset Gallery was redesigned to be a Publication Gallery instead. It will feature scientific publications together with their published datasets and information such as the species, brain region or acquisition method of such datasets. [#3653](https://github.com/scalableminds/webknossos/pull/3653) - Statistics are now separated by organization, rather than showing the webKnossos instance’s totals. [#3663](https://github.com/scalableminds/webknossos/pull/3663) ### Fixed diff --git a/app/assets/javascripts/dashboard/publication_card.js b/app/assets/javascripts/dashboard/publication_card.js index 7c683008226..309efbd0b52 100644 --- a/app/assets/javascripts/dashboard/publication_card.js +++ b/app/assets/javascripts/dashboard/publication_card.js @@ -167,7 +167,16 @@ class PublicationCard extends React.PureComponent { height: `${miniThumbnailDimension}px`, }} onMouseEnter={() => this.setState({ activeDataset: dataset })} - /> + > +

+ ); })} diff --git a/app/assets/stylesheets/_dashboard.less b/app/assets/stylesheets/_dashboard.less index 93ac82c8e6e..5d690c56387 100644 --- a/app/assets/stylesheets/_dashboard.less +++ b/app/assets/stylesheets/_dashboard.less @@ -195,6 +195,14 @@ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); background-size: cover; + &.segmentation { + opacity: 0.2 !important; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + } &:hover, &.active { opacity: 1; From 993bd67083055aeda1412d0ad12e526bfff9e120 Mon Sep 17 00:00:00 2001 From: Daniel Werner Date: Thu, 24 Jan 2019 15:39:22 +0100 Subject: [PATCH 14/16] update migrations.md --- MIGRATIONS.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MIGRATIONS.md b/MIGRATIONS.md index 8eb2bcc317c..aa4cb54d8bf 100644 --- a/MIGRATIONS.md +++ b/MIGRATIONS.md @@ -5,7 +5,13 @@ This project adheres to [Calendar Versioning](http://calver.org/) `0Y.0M.MICRO`. User-facing changes are documented in the [changelog](CHANGELOG.md). ## Unreleased -- +- WebKnossos has a publication gallery now. There is no public interface to create publications yet, but instead those need to be inserted into the database directly. + Publications and additional dataset properties that are displayed in the gallery as well, can be inserted as follows: + ``` + insert into webknossos.publications(_id, publicationDate, imageUrl, title, description) values('5c3c9ec895010095014759fd', NOW(), '', '', '<DESCRIPTION>'); + + update webknossos.datasets set _publication = '5c3c9ec895010095014759fd', details='{"species":"<e.g. Mouse>", "brain-region":"<e.g. cortex>", "acquisition":"<e.g. Raw CLSM data>"}' where _id = '<DATASET_ID>' ; + ``` ### Postgres Evolutions: - [037-add-publications.sql](conf/evolutions/037-add-publications.sql) From 1e4856460c9e760ebdba30e63e7813d664ce7d49 Mon Sep 17 00:00:00 2001 From: Daniel Werner <daniel.werner@scalableminds.com> Date: Thu, 24 Jan 2019 15:53:11 +0100 Subject: [PATCH 15/16] fix empty text if there are not featured publications --- app/assets/javascripts/dashboard/publication_view.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/dashboard/publication_view.js b/app/assets/javascripts/dashboard/publication_view.js index d806503a8f4..ecfe18f55cf 100644 --- a/app/assets/javascripts/dashboard/publication_view.js +++ b/app/assets/javascripts/dashboard/publication_view.js @@ -50,6 +50,7 @@ class PublicationView extends React.PureComponent<Props> { <List grid={gridValues} dataSource={datasetsByPublication} + locale={{ emptyText: "No featured publications." }} renderItem={datasets => ( <List.Item key={datasets[0].publication.id}> <PublicationCard className="dataset-panel" datasets={datasets} /> From 85fde224cd9b576698b011335cf78d527148d2ab Mon Sep 17 00:00:00 2001 From: Daniel Werner <daniel.werner@scalableminds.com> Date: Thu, 24 Jan 2019 16:44:42 +0100 Subject: [PATCH 16/16] refresh snapshots --- .../test/enzyme/snapshot.e2e.js.md | 16 ++++++++-------- .../test/enzyme/snapshot.e2e.js.snap | Bin 29492 -> 29529 bytes 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.md b/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.md index 19985b66778..699141a928c 100644 --- a/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.md +++ b/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.md @@ -110,7 +110,7 @@ Generated by [AVA](https://ava.li). <AnimateChild animation={{...}} transitionName="fade" transitionEnter={true} transitionAppear={false} transitionLeave={true}>␊ <div className="ant-spin-container">␊ <PublicationView datasets={{...}} searchQuery="">␊ - <List grid={{...}} dataSource={{...}} renderItem={[Function: renderItem]} prefixCls="ant-list" bordered={false} split={true} loading={false} pagination={false}>␊ + <List grid={{...}} dataSource={{...}} locale={{...}} renderItem={[Function: renderItem]} prefixCls="ant-list" bordered={false} split={true} loading={false} pagination={false}>␊ <div className="ant-list ant-list-split ant-list-grid">␊ <Spin spinning={false} prefixCls="ant-spin" size="default" wrapperClassName="">␊ <Animate component="div" className="ant-spin-nested-loading" style={{...}} transitionName="fade" animation={{...}} componentProps={{...}} transitionEnter={true} transitionLeave={true} transitionAppear={false} onEnd={[Function: noop]} onEnter={[Function: noop]} onLeave={[Function: noop]} onAppear={[Function: noop]}>␊ @@ -119,7 +119,7 @@ Generated by [AVA](https://ava.li). <div className="ant-spin-container">␊ <LocaleReceiver componentName="Table" defaultLocale={{...}}>␊ <div className="ant-list-empty-text">␊ - No data␊ + No featured publications.␊ </div>␊ </LocaleReceiver>␊ </div>␊ @@ -274,7 +274,7 @@ Generated by [AVA](https://ava.li). <AnimateChild animation={{...}} transitionName="fade" transitionEnter={true} transitionAppear={false} transitionLeave={true}>␊ <div className="ant-spin-container">␊ <PublicationView datasets={{...}} searchQuery="">␊ - <List grid={{...}} dataSource={{...}} renderItem={[Function: renderItem]} prefixCls="ant-list" bordered={false} split={true} loading={false} pagination={false}>␊ + <List grid={{...}} dataSource={{...}} locale={{...}} renderItem={[Function: renderItem]} prefixCls="ant-list" bordered={false} split={true} loading={false} pagination={false}>␊ <div className="ant-list ant-list-split ant-list-grid">␊ <Spin spinning={false} prefixCls="ant-spin" size="default" wrapperClassName="">␊ <Animate component="div" className="ant-spin-nested-loading" style={{...}} transitionName="fade" animation={{...}} componentProps={{...}} transitionEnter={true} transitionLeave={true} transitionAppear={false} onEnd={[Function: noop]} onEnter={[Function: noop]} onLeave={[Function: noop]} onAppear={[Function: noop]}>␊ @@ -283,7 +283,7 @@ Generated by [AVA](https://ava.li). <div className="ant-spin-container">␊ <LocaleReceiver componentName="Table" defaultLocale={{...}}>␊ <div className="ant-list-empty-text">␊ - No data␊ + No featured publications.␊ </div>␊ </LocaleReceiver>␊ </div>␊ @@ -1461,7 +1461,7 @@ Generated by [AVA](https://ava.li). <AnimateChild animation={{...}} transitionName="fade" transitionEnter={true} transitionAppear={false} transitionLeave={true}>␊ <div className="ant-spin-container">␊ <PublicationView datasets={{...}} searchQuery="">␊ - <List grid={{...}} dataSource={{...}} renderItem={[Function: renderItem]} prefixCls="ant-list" bordered={false} split={true} loading={false} pagination={false}>␊ + <List grid={{...}} dataSource={{...}} locale={{...}} renderItem={[Function: renderItem]} prefixCls="ant-list" bordered={false} split={true} loading={false} pagination={false}>␊ <div className="ant-list ant-list-split ant-list-grid">␊ <Spin spinning={false} prefixCls="ant-spin" size="default" wrapperClassName="">␊ <Animate component="div" className="ant-spin-nested-loading" style={{...}} transitionName="fade" animation={{...}} componentProps={{...}} transitionEnter={true} transitionLeave={true} transitionAppear={false} onEnd={[Function: noop]} onEnter={[Function: noop]} onLeave={[Function: noop]} onAppear={[Function: noop]}>␊ @@ -1470,7 +1470,7 @@ Generated by [AVA](https://ava.li). <div className="ant-spin-container">␊ <LocaleReceiver componentName="Table" defaultLocale={{...}}>␊ <div className="ant-list-empty-text">␊ - No data␊ + No featured publications.␊ </div>␊ </LocaleReceiver>␊ </div>␊ @@ -3637,7 +3637,7 @@ Generated by [AVA](https://ava.li). <AnimateChild animation={{...}} transitionName="fade" transitionEnter={true} transitionAppear={false} transitionLeave={true}>␊ <div className="ant-spin-container">␊ <PublicationView datasets={{...}} searchQuery="">␊ - <List grid={{...}} dataSource={{...}} renderItem={[Function: renderItem]} prefixCls="ant-list" bordered={false} split={true} loading={false} pagination={false}>␊ + <List grid={{...}} dataSource={{...}} locale={{...}} renderItem={[Function: renderItem]} prefixCls="ant-list" bordered={false} split={true} loading={false} pagination={false}>␊ <div className="ant-list ant-list-split ant-list-grid">␊ <Spin spinning={false} prefixCls="ant-spin" size="default" wrapperClassName="">␊ <Animate component="div" className="ant-spin-nested-loading" style={{...}} transitionName="fade" animation={{...}} componentProps={{...}} transitionEnter={true} transitionLeave={true} transitionAppear={false} onEnd={[Function: noop]} onEnter={[Function: noop]} onLeave={[Function: noop]} onAppear={[Function: noop]}>␊ @@ -3646,7 +3646,7 @@ Generated by [AVA](https://ava.li). <div className="ant-spin-container">␊ <LocaleReceiver componentName="Table" defaultLocale={{...}}>␊ <div className="ant-list-empty-text">␊ - No data␊ + No featured publications.␊ </div>␊ </LocaleReceiver>␊ </div>␊ diff --git a/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.snap b/app/assets/javascripts/test/snapshots/public/test-bundle/test/enzyme/snapshot.e2e.js.snap index a0fa5e86073b0bdcc94436a3e207c6abd50ad77c..7b4c409b72205c9e33dce50b8eb0dbeff6a3947e 100644 GIT binary patch delta 13170 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 delta 13133 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%0Ads(f(Pu<h^pak!!+uVxWd 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