From e0ffcada7af03bd0f09d8b1afab118945438f0d6 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 3 Jul 2014 15:25:30 +0200 Subject: [PATCH] Initial work on issues list filters. --- app/coffee/modules/controllerMixins.coffee | 12 +- app/coffee/modules/issues/list.coffee | 192 ++++++++++++++++++++- app/coffee/modules/resources/issues.coffee | 2 +- app/partials/issues.jade | 5 +- app/partials/views/modules/filters.jade | 37 ++-- 5 files changed, 216 insertions(+), 32 deletions(-) diff --git a/app/coffee/modules/controllerMixins.coffee b/app/coffee/modules/controllerMixins.coffee index ee02dc8a..90e7807c 100644 --- a/app/coffee/modules/controllerMixins.coffee +++ b/app/coffee/modules/controllerMixins.coffee @@ -22,6 +22,9 @@ taiga = @.taiga groupBy = @.taiga.groupBy +joinStr = @.taiga.joinStr +trim = @.taiga.trim +toString = @.taiga.toString class PageMixin @@ -52,9 +55,8 @@ class FiltersMixin selectFilter: (name, value, load=false) -> params = @location.search() if params[name] != undefined and name != "page" - existing = _.map(params[name].split(","), trim) - existing.push(value) - + existing = _.map(taiga.toString(params[name]).split(","), trim) + existing.push(taiga.toString(value)) value = joinStr(",", _.uniq(existing)) location = if load then @location else @location.noreload(@scope) @@ -69,8 +71,8 @@ class FiltersMixin if value is undefined or value is null delete params[name] - parsedValues = _.map(params[name].split(","), trim) - newValues = _.reject(parsedValues, (x) -> x == toString(value)) + parsedValues = _.map(taiga.toString(params[name]).split(","), trim) + newValues = _.reject(parsedValues, (x) -> x == taiga.toString(value)) if _.isEmpty(newValues) value = null diff --git a/app/coffee/modules/issues/list.coffee b/app/coffee/modules/issues/list.coffee index 7430dff2..435431cf 100644 --- a/app/coffee/modules/issues/list.coffee +++ b/app/coffee/modules/issues/list.coffee @@ -55,9 +55,48 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi console.log "FAIL" #TODO loadFilters: -> - defered = @q.defer() - defered.resolve() - return defered.promise + return @rs.issues.filtersData(@scope.projectId).then (data) => + console.log data + + # Build selected filters (from url) fast lookup data structure + searchdata = {} + for name, value of @.getFilters() + if name == "page" + continue + + if not searchdata[name]? + searchdata[name] = {} + + for val in value.split(",") + searchdata[name][val] = true + + isSelected = (type, id) -> + if searchdata[type]? and searchdata[type][id] + return true + return false + + console.log "2222", searchdata + + # Build filters data structure + filters = {} + filters.tags = _.map data.tags, (t) => + obj = {id:t[0], name:t[0], count: t[1], type:"tags"} + obj.selected = true if isSelected("tags", obj.id) + return obj + + filters.priorities = _.map data.priorities, (t) => + obj = {id:t[0], name:@scope.priorityById[t[0]].name, count:t[1], type:"priorities"} + obj.selected = true if isSelected("priorities", obj.id) + return obj + + filters.severities = _.map data.severities, (t) => + obj = {id:t[0], name:@scope.severityById[t[0]].name, count:t[1], type:"severities"} + obj.selected = true if isSelected("severities", obj.id) + return obj + + @scope.filters = filters + @rootscope.$broadcast("filters:loaded", filters) + return data loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => @@ -69,12 +108,31 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi return project getFilters: -> - filters = _.pick(@location.search(), "page", "tags", "status", "type") + filters = _.pick(@location.search(), "page", "tags", "status", "type", + "severities", "priorities") filters.page = 1 if not filters.page return filters + # Convert stored filters to http parameters + # ready filters (the name difference exists + # because of some automatic lookups and is + # the simplest way todo it without adding + # additional complexity to code. + prepareFilters: -> + filters = {} + + for name, values of @.getFilters() + if name == "severities" + name = "severity" + else if name == "priorities" + name = "priority" + + filters[name] = values + return filters + loadIssues: -> - filters = @.getFilters() + filters = @.prepareFilters() + console.log filters promise = @rs.issues.list(@scope.projectId, filters).then (data) => @scope.issues = data.models @@ -221,7 +279,8 @@ IssuesDirective = ($log, $location) -> ######################### linkFilters = ($scope, $el, $attrs, $ctrl) -> - $log.debug "IssuesDirective:linkFilters" + $scope.filters = {} + $scope.selectedFilters = [] ######################### ## Issues Link @@ -235,4 +294,125 @@ IssuesDirective = ($log, $location) -> return {link:link} + +IssuesFiltersDirective = ($log, $location) -> + template = _.template(""" + <% _.each(filters, function(f) { %> + <% if (f.selected) { %> + + <%- f.name %> + <%- f.count %> + + <% } else { %> + + <%- f.name %> + <%- f.count %> + + <% } %> + <% }) %> + """) + + templateSelected = _.template(""" + <% _.each(filters, function(f) { %> + + <%- f.name %> + + + <% }) %> + """) + + selectedFilters = [] + + showFilters = ($el) -> + $el.find(".filters-cats").hide() + $el.find(".filter-list").show() + + showCategories = ($el) -> + $el.find(".filters-cats").show() + $el.find(".filter-list").hide() + + initializeSelectedFilters = ($el, filters) -> + for name, values of filters + for val in values + console.log "klkk", val.selected + selectedFilters.push(val) if val.selected + + renderSelectedFilters($el) + + renderSelectedFilters = ($el) -> + html = templateSelected({filters:selectedFilters}) + $el.find(".filters-applied").html(html) + + renderFilters = ($el, filters) -> + html = template({filters:filters}) + $el.find(".filter-list").html(html) + + link = ($scope, $el, $attrs) -> + $ctrl = $el.closest(".wrapper").controller() + + $scope.$on "filters:loaded", (ctx, filters) -> + initializeSelectedFilters($el, filters) + + toggleFilterSelection = (type, id) -> + filters = $scope.filters[type] + filter = _.find(filters, {id:id}) + filter.selected = (not filter.selected) + if filter.selected + selectedFilters.push(filter) + $scope.$apply -> + $ctrl.selectFilter(type, id) + $ctrl.selectFilter("page", 1) + $ctrl.loadIssues() + else + selectedFilters = _.reject(selectedFilters, filter) + $scope.$apply -> + $ctrl.unselectFilter(type, id) + $ctrl.selectFilter("page", 1) + $ctrl.loadIssues() + + renderSelectedFilters($el, selectedFilters) + renderFilters($el, filters) + + $el.on "click", ".filters-cats > ul > li > a", (event) -> + event.preventDefault() + target = angular.element(event.currentTarget) + tags = $scope.filters[target.data("type")] + + renderFilters($el, tags) + showFilters($el) + + $el.on "click", ".filters-inner > h1 > a.title", (event) -> + event.preventDefault() + showCategories($el) + + $el.on "click", ".filters-applied a", (event) -> + event.preventDefault() + target = angular.element(event.currentTarget) + + id = target.data("id") + type = target.data("type") + toggleFilterSelection(type, id) + + $el.on "click", ".filter-list .single-filter", (event) -> + event.preventDefault() + target = angular.element(event.currentTarget) + if target.hasClass("active") + target.removeClass("active") + # target.css("background-color") + else + target.addClass("active") + + id = target.data("id") + type = target.data("type") + toggleFilterSelection(type, id) + + return {link:link} + +module.directive("tgIssuesFilters", ["$log", "$tgLocation", IssuesFiltersDirective]) module.directive("tgIssues", ["$log", "$tgLocation", IssuesDirective]) diff --git a/app/coffee/modules/resources/issues.coffee b/app/coffee/modules/resources/issues.coffee index cf0966e5..f06ea9e3 100644 --- a/app/coffee/modules/resources/issues.coffee +++ b/app/coffee/modules/resources/issues.coffee @@ -37,7 +37,7 @@ resourceProvider = ($repo) -> return $repo.queryOneRaw("projects", "#{projectId}/issues_stats") service.filtersData = (projectId) -> - return $repo.queryOneRaw("projects", "#{projectId}/issues_filters_data") + return $repo.queryOneRaw("projects", "#{projectId}/issue_filters_data") return (instance) -> instance.issues = service diff --git a/app/partials/issues.jade b/app/partials/issues.jade index fddd0899..870fd4ec 100644 --- a/app/partials/issues.jade +++ b/app/partials/issues.jade @@ -5,7 +5,7 @@ block head block content div.wrapper.issues(tg-issues, ng-controller="IssuesController as ctrl", ng-init="section='issues'") - sidebar.menu-secondary.extrabar.filters-bar + sidebar.menu-secondary.extrabar.filters-bar(tg-issues-filters) include views/modules/filters section.main.issues-page @@ -20,5 +20,6 @@ block content div.hidden.lightbox.lightbox_add-issue include views/modules/lightbox_add-issue - div.lightbox.lightbox_add-bulk.hidden + + div.hidden.lightbox.lightbox_add-bulk include views/modules/lightbox_add-bulk diff --git a/app/partials/views/modules/filters.jade b/app/partials/views/modules/filters.jade index 4795019e..a74e6beb 100644 --- a/app/partials/views/modules/filters.jade +++ b/app/partials/views/modules/filters.jade @@ -7,37 +7,38 @@ section.filters span status form fieldset - input(type="text", placeholder="Filter Filters", ng-model="filters.subject") + input(type="text", placeholder="Search by subject...", ng-model="filters.subject") a.icon.icon-search(href="", title="search") //- First step for selecting category div.filters-step-cat //- $(.filters-applied) only visible when filters are being applied div.filters-applied - a.single-filter.selected - span.name Filter23 - span.icon.icon-delete + // a.single-filter.selected + // span.name Filter23 + // span.icon.icon-delete div.filters-cats ul + // li + // a(href="", title="Status", data-type="status") + // span.title Status + // span.icon.icon-arrow-right + // li + // a(href="", title="Type", data-type="types") + // span.title Type + // span.icon.icon-arrow-right li - a(href="", title="status") - span Status + a(href="", title="Severity", data-type="severities") + span.title Severity span.icon.icon-arrow-right li - a(href="", title="type") - span Type + a(href="", title="Priorities", data-type="priorities") + span.title Priorities span.icon.icon-arrow-right li - a(href="", title="Severity") - span Severity - span.icon.icon-arrow-right - li - a(href="", title="blablabla") - span Blablabla + a(href="", title="Tags", data-type="tags") + span.title Tags span.icon.icon-arrow-right //- Second step for selecting single filters to apply - div.filter-list - a.single-filter(ng-repeat="tag in filters.tags|filter:filtersSearch:strict" ng-class="{selected: tag.selected}") - span.name(tg-bo-html="tag.name") - span.number(tg-bo-html="tag.count") + div.filter-list.hidden