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

2705 sortby gallery #3499

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion app/controllers/GalleryController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ class GalleryController @Inject() (implicit val env: Environment[User, SessionAu
val regionIds: Set[Int] = submission.regionIds.getOrElse(Seq()).toSet
val severities: Set[Int] = submission.severities.getOrElse(Seq()).toSet
val tags: Set[String] = submission.tags.getOrElse(Seq()).toSet
val order: Int = submission.order

// Get labels from LabelTable.
val labels: Seq[LabelValidationMetadata] =
LabelTable.getGalleryLabels(n, labelTypeId, loadedLabelIds, valOptions, regionIds, severities, tags, user.userId)
LabelTable.getGalleryLabels(n, labelTypeId, loadedLabelIds, valOptions, regionIds, severities, tags, user.userId, order)

val jsonList: Seq[JsObject] = labels.map(l => Json.obj(
"label" -> LabelFormat.validationLabelMetadataToJson(l),
Expand Down
5 changes: 3 additions & 2 deletions app/formats/json/GalleryFormats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ object GalleryFormats {
case class GalleryEnvironmentSubmission(browser: Option[String], browserVersion: Option[String], browserWidth: Option[Int], browserHeight: Option[Int], screenWidth: Option[Int], screenHeight: Option[Int], availWidth: Option[Int], availHeight: Option[Int], operatingSystem: Option[String], language: String)
case class GalleryInteractionSubmission(action: String, panoId: Option[String], note: Option[String], timestamp: Long)
case class GalleryTaskSubmission(environment: GalleryEnvironmentSubmission, interactions: Seq[GalleryInteractionSubmission])
case class GalleryLabelsRequest(n: Int, labelTypeId: Option[Int], validationOptions: Option[Seq[String]], regionIds: Option[Seq[Int]], severities: Option[Seq[Int]], tags: Option[Seq[String]], loadedLabels: Seq[Int])
case class GalleryLabelsRequest(n: Int, labelTypeId: Option[Int], validationOptions: Option[Seq[String]], regionIds: Option[Seq[Int]], severities: Option[Seq[Int]], tags: Option[Seq[String]], loadedLabels: Seq[Int], order: Int)

implicit val galleryEnvironmentSubmissionReads: Reads[GalleryEnvironmentSubmission] = (
(JsPath \ "browser").readNullable[String] and
Expand Down Expand Up @@ -42,6 +42,7 @@ object GalleryFormats {
(JsPath \ "neighborhoods").readNullable[Seq[Int]] and
(JsPath \ "severities").readNullable[Seq[Int]] and
(JsPath \ "tags").readNullable[Seq[String]] and
(JsPath \ "loaded_labels").read[Seq[Int]]
(JsPath \ "loaded_labels").read[Seq[Int]] and
(JsPath \ "order").read[Int]
)(GalleryLabelsRequest.apply _)
}
56 changes: 48 additions & 8 deletions app/models/label/LabelTable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -643,9 +643,10 @@ object LabelTable {
* @param regionIds Set of neighborhoods to get labels from. All neighborhoods if empty.
* @param severity Set of severities the labels grabbed can have.
* @param tags Set of tags the labels grabbed can have.
* @param order Order to grab labels by
* @return Seq[LabelValidationMetadata]
*/
def getGalleryLabels(n: Int, labelTypeId: Option[Int], loadedLabelIds: Set[Int], valOptions: Set[String], regionIds: Set[Int], severity: Set[Int], tags: Set[String], userId: UUID): Seq[LabelValidationMetadata] = db.withSession { implicit session =>
def getGalleryLabels(n: Int, labelTypeId: Option[Int], loadedLabelIds: Set[Int], valOptions: Set[String], regionIds: Set[Int], severity: Set[Int], tags: Set[String], userId: UUID, order: Int): Seq[LabelValidationMetadata] = db.withSession { implicit session =>
// Filter labels based on correctness.
val _l1 = if (!valOptions.contains("correct")) labels.filter(l => l.correct.isEmpty || !l.correct) else labels
val _l2 = if (!valOptions.contains("incorrect")) _l1.filter(l => l.correct.isEmpty || l.correct) else _l1
Expand Down Expand Up @@ -691,24 +692,63 @@ object LabelTable {
// Remove duplicates that we got from joining with the `label_tag` table.
val _uniqueLabels = if (tags.nonEmpty) _labelInfoWithUserVals.groupBy(x => x).map(_._1) else _labelInfoWithUserVals

// Randomize, check for GSV imagery, & add tag info. If no label type is specified, do it by label type.
// Sort by order code, check for GSV imagery, & add tag info. If no label type is specified, do it by label type.
if (labelTypeId.isDefined) {
val rand = SimpleFunction.nullary[Double]("random")
val _randomizedLabels = _uniqueLabels.sortBy(x => rand).list.map(LabelValidationMetadataWithoutTags.tupled)
val _assortedLabels = _uniqueLabels.list.map(LabelValidationMetadataWithoutTags.tupled)

// Sort label by order code
order match {
case 0 => _assortedLabels.sortBy(_.severity).reverse
case 1 => _assortedLabels.sortBy(_.severity)
case 2 => _assortedLabels.sortBy(_.timestamp).reverse
case 3 => _assortedLabels.sortBy(_.timestamp)
case 4 => _assortedLabels.sortBy(_.agreeCount).reverse
case 5 => _assortedLabels.sortBy(_.disagreeCount)
case 6 => _assortedLabels.sortBy(label => getTagsFromLabelId(label.labelId).length).reverse
case 7 => _assortedLabels.sortBy(label => getTagsFromLabelId(label.labelId).length)
case -1 => scala.util.Random.shuffle(_assortedLabels)
}

// Take the first `n` labels with non-expired GSV imagery.
checkForGsvImagery(_randomizedLabels, n)
checkForGsvImagery(_assortedLabels, n)
.map(l => labelAndTagsToLabelValidationMetadata(l, getTagsFromLabelId(l.labelId)))
} else {
val _potentialLabels: Map[String, List[LabelValidationMetadataWithoutTags]] =
//
_labelInfoWithUserVals.list.map(LabelValidationMetadataWithoutTags.tupled)
.groupBy(_.labelType).map(l => l._1 -> scala.util.Random.shuffle(l._2))
.groupBy(_.labelType)
.map(l => l._1 -> scala.util.Random.shuffle(l._2))

// Sort individual labels by order code first
order match {
case 0 => _potentialLabels.mapValues(labels => labels.sortBy(_.severity).reverse)
case 1 => _potentialLabels.mapValues(labels => labels.sortBy(_.severity))
case 2 => _potentialLabels.mapValues(labels => labels.sortBy(_.timestamp).reverse)
case 3 => _potentialLabels.mapValues(labels => labels.sortBy(_.timestamp))
case 4 => _potentialLabels.mapValues(labels => labels.sortBy(_.agreeCount).reverse)
case 5 => _potentialLabels.mapValues(labels => labels.sortBy(_.disagreeCount))
case 6 => _potentialLabels.mapValues(labels => labels.sortBy(label => getTagsFromLabelId(label.labelId).length).reverse)
case 7 => _potentialLabels.mapValues(labels => labels.sortBy(label => getTagsFromLabelId(label.labelId).length))
case -1 => _potentialLabels.mapValues(labels => scala.util.Random.shuffle(labels))
}
val nPerType: Int = n / LabelTypeTable.primaryLabelTypes.size

// Take the first `nPerType` labels with non-expired GSV imagery for each label type, then randomize them.
// Take the first `nPerType` labels with non-expired GSV imagery for each label type, then sort them.
val chosenLabels: Seq[LabelValidationMetadata] = checkForImageryByLabelType(_potentialLabels, nPerType)
.map(l => labelAndTagsToLabelValidationMetadata(l, getTagsFromLabelId(l.labelId)))
scala.util.Random.shuffle(chosenLabels)

// Now resort based on all labels by order code
order match {
case 0 => chosenLabels.sortBy(_.severity).reverse
case 1 => chosenLabels.sortBy(_.severity)
case 2 => chosenLabels.sortBy(_.timestamp).reverse
case 3 => chosenLabels.sortBy(_.timestamp)
case 4 => chosenLabels.sortBy(_.agreeCount).reverse
case 5 => chosenLabels.sortBy(_.disagreeCount)
case 6 => chosenLabels.sortBy(_.tags.length).reverse
case 7 => chosenLabels.sortBy(_.tags.length)
case -1 => scala.util.Random.shuffle(chosenLabels)
}
}
}

Expand Down
50 changes: 50 additions & 0 deletions app/views/gallery.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,56 @@ <h5 id="validation-options-header" class="filter-subheader">@Messages("validatio
<span id="validation-options"></span>
<button id="clear-filters" hidden><h6>&#10006; @Messages("gallery.clear.filters")</h6></button>
</div>
<div class="card-sort-menu-holder">
<h4 id="sort-header"><b>@Messages("gallery.sort.by")</b></h4>
<div class="card-sort-select">
<div class="card-sort-select-option">
<h5 >@Messages("gallery.severity")</h5>
<div>
<button onclick="sg.cardContainer.sortCards(0)">
<svg id="icon0" width="12px" height="12px" viewBox="0 0 1024.00 1024.00" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="5"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="6.144"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 768l56.768-50.432L512 256l-448 461.568 56.768 50.432L512 364.928z" fill="#000000"></path></g></svg>
</button>
<button onclick="sg.cardContainer.sortCards(1)">
<svg id="icon1" width="12px" height="12px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="5"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 256l56.768 50.432L512 768 64 306.432 120.768 256 512 659.072z" fill="#000000"></path></g></svg>
</button>
</div>
</div>
<div class="card-sort-select-option">
<h5>@Messages("gallery.recency")</h5>
<div>
<button onclick="sg.cardContainer.sortCards(2)">
<svg id="icon2" width="12px" height="12px" viewBox="0 0 1024.00 1024.00" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="5"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="6.144"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 768l56.768-50.432L512 256l-448 461.568 56.768 50.432L512 364.928z" fill="#000000"></path></g></svg>
</button>
<button onclick="sg.cardContainer.sortCards(3)">
<svg id="icon3" width="12px" height="12px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="5"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 256l56.768 50.432L512 768 64 306.432 120.768 256 512 659.072z" fill="#000000"></path></g></svg>
</button>
</div>
</div>
<div class="card-sort-select-option">
<h5>@Messages("gallery.validation")</h5>
<div>
<button onclick="sg.cardContainer.sortCards(4)">
<svg id="icon4" width="12px" height="12px" viewBox="0 0 1024.00 1024.00" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="5"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="6.144"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 768l56.768-50.432L512 256l-448 461.568 56.768 50.432L512 364.928z" fill="#000000"></path></g></svg>
</button>
<button onclick="sg.cardContainer.sortCards(5)">
<svg id="icon5" width="12px" height="12px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="5"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 256l56.768 50.432L512 768 64 306.432 120.768 256 512 659.072z" fill="#000000"></path></g></svg>
</button>
</div>
</div>
<div class="card-sort-select-option">
<h5>@Messages("gallery.tags")</h5>
<div>
<button onclick="sg.cardContainer.sortCards(6)">
<svg id="icon6" width="12px" height="12px" viewBox="0 0 1024.00 1024.00" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="5"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="6.144"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 768l56.768-50.432L512 256l-448 461.568 56.768 50.432L512 364.928z" fill="#000000"></path></g></svg>
</button>
<button onclick="sg.cardContainer.sortCards(7)">
<svg id="icon7" width="12px" height="12px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="5"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 256l56.768 50.432L512 768 64 306.432 120.768 256 512 659.072z" fill="#000000"></path></g></svg>
</button>
</div>
</div>
</div>
</div>
<button id="clear-sorting" hidden><h6>&#10006; @Messages("gallery.clear.sorting")</h6></button>
</div>
</div>
<div id="labels-not-found-text">
Expand Down
6 changes: 6 additions & 0 deletions conf/messages.de
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,12 @@ gallery.all = Alle Beschriftungskategorien
gallery.labels.not.found = Keine Treffer. <a href="/explore">Erkundung starten</a>, um mehr Daten beizutragen!
gallery.cards = Beschriftungen werden zufällig sortiert, basierend auf gewählten Filtern
gallery.clear.filters = Filter löschen
gallery.sort.by = Sorteer Nach
gallery.severity = Schweregrad
gallery.recency = Zeitstempel
gallery.validation = Validierung
gallery.tags = Tags
gallery.clear.sorting = Sortierung löschen

routebuilder.name = RouteBuilder
routebuilder.welcome = Willkommen bei RouteBuilder
Expand Down
6 changes: 6 additions & 0 deletions conf/messages.en
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ gallery.all = All Label Types
gallery.labels.not.found = No matches. <a href="/explore">Start exploring</a> to contribute more data!
gallery.cards = Labels are sorted randomly based on selected filters
gallery.clear.filters = Clear Filters
gallery.sort.by = Sort By
gallery.severity = Severity
gallery.recency = Time Stamp
gallery.validation = Validation
gallery.tags = Tags
gallery.clear.sorting = Clear Sorting

routebuilder.name = RouteBuilder
routebuilder.welcome = Welcome to RouteBuilder
Expand Down
6 changes: 6 additions & 0 deletions conf/messages.es
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,12 @@ gallery.all = Todos los tipos de etiquetas
gallery.labels.not.found = No hay resultados. ¡<a href="/explore">Comienza a explorar</a> para aportar más datos!
gallery.cards = Las etiquetas se ordenan aleatoriamente según los filtros seleccionados
gallery.clear.filters = Borrar Filtros
gallery.sort.by = Ordenar por
gallery.severity = Gravedad
gallery.recency= Marca de tiempo
gallery.validation = Validación
gallery.tags = Etiquetas
gallery.clear.sorting = Borrar Clasificación

routebuilder.name = Constructor de rutas
routebuilder.welcome = Bienvenido a RouteBuilder
Expand Down
6 changes: 6 additions & 0 deletions conf/messages.nl
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,12 @@ gallery.all = Alle labeltypen
gallery.labels.not.found = Geen overeenkomsten. <a href="/explore">Begin met verkennen</a> om meer data bij te dragen!
gallery.cards = Labels worden willekeurig gesorteerd op basis van geselecteerde filters
gallery.clear.filters = Filters Wissen
gallery.sort.by = Sorteer op
gallery.severity = Ernst
gallery.recency = Tijdstempel
gallery.validation = Validatie
gallery.tags = Labels
gallery.clear.sorting = Duidelijke Sortering

routebuilder.name = Routebuilder
routebuilder.welcome = Welkom bij Routebuilder
Expand Down
6 changes: 6 additions & 0 deletions conf/messages.zh-TW
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,12 @@ gallery.all = 所有的標記類型
gallery.labels.not.found = 無相符資料。 <a href="/explore">開始探索</a>以蒐集更多的資料!
gallery.cards = 所有標記依據所選定的過濾器而隨機排序
gallery.clear.filters = 清除過濾器
gallery.sort.by = 排序方式
gallery.severity = 嚴重程度
gallery.recency = 时间戳
gallery.validation = 验证
gallery.tags = 标签
gallery.clear.sorting = 清除排序

routebuilder.name = 路線設立工具
routebuilder.welcome = 歡迎使用路線設立工具
Expand Down
46 changes: 46 additions & 0 deletions public/javascripts/Gallery/css/filter.css
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,49 @@
margin-top: 5px;
color: darkgray;
}

/* added new parts for card sort menu*/

#card-sort-menu-holder {
display: flex;
flex-direction: row;
align-items: center;
margin-top: 5px;
background-color: transparent;
border-color: transparent;
}

.card-sort-select button {
background-color: transparent;
border-color: transparent;
cursor: pointer;
display: flex;
flex-direction: column;
}

.card-sort-select-option{
display: flex;
flex-direction: row;
}

.icon {
width: 20px;
height: 15px;
}

.active {
stroke-width: 102.4;
}

#clear-sorting {
background-color: transparent;
border-color: transparent;
cursor: pointer;
display: none
}

#clear-sorting h6 {
margin-top: 5px;
color: darkgray;
}

5 changes: 3 additions & 2 deletions public/javascripts/Gallery/src/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function Main (params) {
sg.ui.cardContainer.prevPage = $("#prev-page");
sg.ui.cardContainer.pageNumber = $("#page-number")
sg.ui.cardContainer.nextPage = $("#next-page");
sg.ui.cardContainer.clearSorting = $("#clear-sorting");

// Keep track of some other elements whose status or dimensions are useful.
sg.ui.pageControl = $(".page-control");
Expand All @@ -72,7 +73,7 @@ function Main (params) {
sg.cityMenu = new CityMenu(sg.ui.cityMenu);
sg.labelTypeMenu = new LabelTypeMenu(sg.ui.labelTypeMenu, params.initialFilters.labelType);

// sg.cardSortMenu = new CardSortMenu(sg.ui.cardSortMenu);
sg.cardSortMenu = new CardSortMenu(sg.ui.cardSortMenu);
sg.cardFilter = new CardFilter(sg.ui.cardFilter, sg.labelTypeMenu, sg.cityMenu, params.initialFilters);
sg.cardContainer = new CardContainer(sg.ui.cardContainer, params.initialFilters);
sg.modal = sg.cardContainer.getModal;
Expand All @@ -91,7 +92,7 @@ function Main (params) {
if (!sg.pageLoading.is(":visible") && !sg.labelsNotFound.is(':visible')) {
let sidebarBottomOffset = sidebarWrapper.offset().top + sidebarWrapper.outerHeight(true);
let cardContainerBottomOffset = sg.ui.cardContainer.holder.offset().top +
sg.ui.cardContainer.holder.outerHeight(true) - 5;
sg.ui.cardContainer.holder.outerHeight(true) - 175;
let visibleWindowBottomOffset = $(window).scrollTop() + $(window).height();

// Handle sidebar stickiness.
Expand Down
Loading