Merge pull request #491 from sharelatex/pr-project-list-improvements

Project list improvements
This commit is contained in:
Paulo Jorge Reis 2017-05-04 09:59:02 +01:00 committed by GitHub
commit 9d2d217d35
6 changed files with 124 additions and 12 deletions

View file

@ -140,23 +140,35 @@
ng-repeat="project in visibleProjects | orderBy:predicate:reverse", ng-repeat="project in visibleProjects | orderBy:predicate:reverse",
ng-controller="ProjectListItemController" ng-controller="ProjectListItemController"
) )
.row .row(select-row)
.col-xs-6 .col-xs-6
input.select-item( input.select-item(
select-individual, select-individual,
type="checkbox", type="checkbox",
ng-model="project.selected" ng-model="project.selected"
stop-propagation="click"
) )
span span
a.projectName(href="/project/{{project.id}}") {{project.name}} a.projectName(
href="/project/{{project.id}}"
stop-propagation="click"
) {{project.name}}
span( span(
ng-controller="TagListController" ng-controller="TagListController"
) )
a.label.label-default.tag-label( .tag-label(
ng-repeat='tag in project.tags'
stop-propagation="click"
)
a.label.label-default.tag-label-name(
href, href,
ng-repeat='tag in project.tags',
ng-click="selectTag(tag)" ng-click="selectTag(tag)"
) {{tag.name}} ) {{tag.name}}
a.label.label-default.tag-label-remove(
href
ng-click="removeProjectFromTag(project, tag)"
) ×
.col-xs-2 .col-xs-2
span.owner {{ownerName()}} span.owner {{ownerName()}}
.col-xs-4 .col-xs-4

View file

@ -79,6 +79,15 @@
li li
a(href, ng-click="deleteTag(tag)", stop-propagation="click") a(href, ng-click="deleteTag(tag)", stop-propagation="click")
| #{translate("delete")} | #{translate("delete")}
li.tag.untagged(
ng-if="tags.length",
ng-cloak,
ng-click="selectUntagged()"
ng-class="{active: filter === 'untagged'}",
)
a.tag-name(href)
| #{translate("uncategorized")}
span.subdued ({{ nUntagged }})
li(ng-cloak) li(ng-cloak)
a.tag(href, ng-click="openNewTagModal()") a.tag(href, ng-click="openNewTagModal()")
i.fa.fa-fw.fa-plus i.fa.fa-fw.fa-plus

View file

@ -58,4 +58,18 @@ define [
scope.$apply () -> scope.$apply () ->
scope.ngModel = false scope.ngModel = false
ignoreChanges = false ignoreChanges = false
scope.$on "select-all:row-clicked", () ->
ignoreChanges = true
scope.$apply () ->
scope.ngModel = !scope.ngModel
ignoreChanges = false
}
App.directive "selectRow", () ->
return {
scope: true
link: (scope, element, attrs) ->
element.on "click", (e) ->
scope.$broadcast "select-all:row-clicked"
} }

View file

@ -2,7 +2,7 @@ define [
"base" "base"
], (App) -> ], (App) ->
App.controller "ProjectPageController", ($scope, $modal, $q, $window, queuedHttp, event_tracking, $timeout) -> App.controller "ProjectPageController", ($scope, $modal, $q, $window, queuedHttp, event_tracking, $timeout, localStorage) ->
$scope.projects = window.data.projects $scope.projects = window.data.projects
$scope.tags = window.data.tags $scope.tags = window.data.tags
$scope.notifications = window.data.notifications $scope.notifications = window.data.notifications
@ -10,6 +10,7 @@ define [
$scope.selectedProjects = [] $scope.selectedProjects = []
$scope.filter = "all" $scope.filter = "all"
$scope.predicate = "lastUpdated" $scope.predicate = "lastUpdated"
$scope.nUntagged = 0
$scope.reverse = true $scope.reverse = true
$scope.searchText = $scope.searchText =
value : "" value : ""
@ -18,6 +19,12 @@ define [
recalculateProjectListHeight() recalculateProjectListHeight()
, 10 , 10
$scope.$watch((
() -> $scope.projects.filter((project) -> !project.tags? or project.tags.length == 0).length
), (newVal) -> $scope.nUntagged = newVal)
storedUIOpts = JSON.parse(localStorage("project_list"))
recalculateProjectListHeight = () -> recalculateProjectListHeight = () ->
topOffset = $(".project-list-card")?.offset()?.top topOffset = $(".project-list-card")?.offset()?.top
bottomOffset = $("footer").outerHeight() + 25 bottomOffset = $("footer").outerHeight() + 25
@ -52,6 +59,13 @@ define [
project.tags ||= [] project.tags ||= []
project.tags.push tag project.tags.push tag
markTagAsSelected = (id) ->
for tag in $scope.tags
if tag._id == id
tag.selected = true
else
tag.selected = false
$scope.changePredicate = (newPredicate)-> $scope.changePredicate = (newPredicate)->
if $scope.predicate == newPredicate if $scope.predicate == newPredicate
$scope.reverse = !$scope.reverse $scope.reverse = !$scope.reverse
@ -104,6 +118,10 @@ define [
if $scope.filter == "tag" and selectedTag? and project.id not in selectedTag.project_ids if $scope.filter == "tag" and selectedTag? and project.id not in selectedTag.project_ids
visible = false visible = false
# Hide tagged projects if we only want to see the uncategorized ones
if $scope.filter == "untagged" and project.tags?.length > 0
visible = false
# Hide projects we own if we only want to see shared projects # Hide projects we own if we only want to see shared projects
if $scope.filter == "shared" and project.accessLevel == "owner" if $scope.filter == "shared" and project.accessLevel == "owner"
visible = false visible = false
@ -126,6 +144,11 @@ define [
else else
# We don't want hidden selections # We don't want hidden selections
project.selected = false project.selected = false
localStorage("project_list", JSON.stringify({
filter: $scope.filter,
selectedTagId: selectedTag?._id
}))
$scope.updateSelectedProjects() $scope.updateSelectedProjects()
$scope.getSelectedTag = () -> $scope.getSelectedTag = () ->
@ -178,6 +201,23 @@ define [
# the projects from view # the projects from view
$scope.updateVisibleProjects() $scope.updateVisibleProjects()
$scope.removeProjectFromTag = (project, tag) ->
tag.showWhenEmpty = true
project.tags ||= []
index = project.tags.indexOf tag
if index > -1
$scope._removeProjectIdsFromTagArray(tag, [ project.id ])
project.tags.splice(index, 1)
queuedHttp({
method: "DELETE"
url: "/tag/#{tag._id}/project/#{project.id}"
headers:
"X-CSRF-Token": window.csrfToken
})
$scope.updateVisibleProjects()
$scope.addSelectedProjectsToTag = (tag) -> $scope.addSelectedProjectsToTag = (tag) ->
selected_projects = $scope.getSelectedProjects() selected_projects = $scope.getSelectedProjects()
event_tracking.send 'project-list-page-interaction', 'project action', 'addSelectedProjectsToTag' event_tracking.send 'project-list-page-interaction', 'project action', 'addSelectedProjectsToTag'
@ -425,6 +465,11 @@ define [
window.location = path window.location = path
if storedUIOpts?.filter?
if storedUIOpts.filter == "tag" and storedUIOpts.selectedTagId?
markTagAsSelected(storedUIOpts.selectedTagId)
$scope.setFilter(storedUIOpts.filter)
else
$scope.updateVisibleProjects() $scope.updateVisibleProjects()
App.controller "ProjectListItemController", ($scope) -> App.controller "ProjectListItemController", ($scope) ->

View file

@ -16,6 +16,10 @@ define [
tag.selected = true tag.selected = true
$scope.setFilter("tag") $scope.setFilter("tag")
$scope.selectUntagged = () ->
$scope._clearTags()
$scope.setFilter("untagged")
$scope.deleteTag = (tag) -> $scope.deleteTag = (tag) ->
modalInstance = $modal.open( modalInstance = $modal.open(
templateUrl: "deleteTagModalTemplate" templateUrl: "deleteTagModalTemplate"

View file

@ -124,6 +124,20 @@ ul.folders-menu {
} }
} }
} }
&.untagged {
font-style: italic;
margin-bottom: @line-height-computed / 4;
a {
line-height: 1.7;
&:hover,
&:focus {
text-decoration: none;
}
}
span.subdued {
font-style: normal;
}
}
&:hover { &:hover {
&:not(.active) { &:not(.active) {
background-color: darken(@gray-lightest, 2%); background-color: darken(@gray-lightest, 2%);
@ -246,9 +260,23 @@ ul.project-list {
margin-left: @line-height-computed / 4; margin-left: @line-height-computed / 4;
position: relative; position: relative;
top: -2px; top: -2px;
padding-top: 0.25em;
display: inline-block; display: inline-block;
color: white; }
.tag-label-name,
.tag-label-remove {
display: inline-block;
padding-top: 0.3em;
color: #FFF;
}
.tag-label-name {
padding-right: 0.3em;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.tag-label-remove {
padding-left: 0.3em;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
} }
} }
i.tablesort { i.tablesort {