Merge pull request #360 from taigaio/us/1913/csv-reports

US#1913: CSV Reports
stable
Juanfran 2015-03-10 03:41:48 -07:00
commit 4f86b6e19a
33 changed files with 447 additions and 399 deletions

View File

@ -5,6 +5,8 @@
### Features
- Added custom fields per project for user stories, tasks and issues.
- Add to the Admin Panel the export to CSV sections.
- Reorganized the Admin Panel.
### Misc
- New contrib plugin for hipchat (by Δndrea Stagi)

View File

@ -89,28 +89,12 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven
{templateUrl: "admin/admin-project-modules.html"})
$routeProvider.when("/project/:pslug/admin/project-profile/export",
{templateUrl: "admin/admin-project-export.html"})
# Admin Project Values
$routeProvider.when("/project/:pslug/admin/project-values/us-status",
{templateUrl: "admin/admin-project-values-us-status.html"})
$routeProvider.when("/project/:pslug/admin/project-values/us-points",
{templateUrl: "admin/admin-project-values-us-points.html"})
$routeProvider.when("/project/:pslug/admin/project-values/us-extras",
{templateUrl: "admin/admin-project-values-us-extras.html"})
$routeProvider.when("/project/:pslug/admin/project-values/task-status",
{templateUrl: "admin/admin-project-values-task-status.html"})
$routeProvider.when("/project/:pslug/admin/project-values/task-extras",
{templateUrl: "admin/admin-project-values-task-extras.html"})
$routeProvider.when("/project/:pslug/admin/project-values/issue-status",
{templateUrl: "admin/admin-project-values-issue-status.html"})
$routeProvider.when("/project/:pslug/admin/project-values/issue-types",
{templateUrl: "admin/admin-project-values-issue-types.html"})
$routeProvider.when("/project/:pslug/admin/project-values/issue-priorities",
{templateUrl: "admin/admin-project-values-issue-priorities.html"})
$routeProvider.when("/project/:pslug/admin/project-values/issue-severities",
{templateUrl: "admin/admin-project-values-issue-severities.html"})
$routeProvider.when("/project/:pslug/admin/project-values/issue-extras",
{templateUrl: "admin/admin-project-values-issue-extras.html"})
# Admin - Memberships
$routeProvider.when("/project/:pslug/admin/project-values/us",
{templateUrl: "admin/admin-project-values-us.html"})
$routeProvider.when("/project/:pslug/admin/project-values/task",
{templateUrl: "admin/admin-project-values-task.html"})
$routeProvider.when("/project/:pslug/admin/project-values/issue",
{templateUrl: "admin/admin-project-values-issue.html"})
$routeProvider.when("/project/:pslug/admin/memberships",
{templateUrl: "admin/admin-memberships.html"})
# Admin - Roles

View File

@ -32,10 +32,10 @@ debounce = @.taiga.debounce
module = angular.module("taigaAdmin")
#############################################################################
## Project values Controller
## Project values section Controller
#############################################################################
class ProjectValuesController extends mixOf(taiga.Controller, taiga.PageMixin)
class ProjectValuesSectionController extends mixOf(taiga.Controller, taiga.PageMixin)
@.$inject = [
"$scope",
"$rootScope",
@ -59,29 +59,44 @@ class ProjectValuesController extends mixOf(taiga.Controller, taiga.PageMixin)
promise.then null, @.onInitialDataError.bind(@)
@scope.$on("admin:project-values:move", @.moveValue)
loadProject: ->
return @rs.projects.get(@scope.projectId).then (project) =>
@scope.project = project
@scope.$emit('project:loaded', project)
return project
loadValues: ->
return @rs[@scope.resource].listValues(@scope.projectId, @scope.type).then (values) =>
@scope.values = values
@scope.maxValueOrder = _.max(values, "order").order
return values
loadInitialData: ->
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
@scope.projectId = data.project
return data
return promise.then( => @q.all([
@.loadProject(),
@.loadValues(),
]))
return promise.then => @.loadProject()
module.controller("ProjectValuesSectionController", ProjectValuesSectionController)
#############################################################################
## Project values Controller
#############################################################################
class ProjectValuesController extends taiga.Controller
@.$inject = [
"$scope",
"$rootScope",
"$tgRepo",
"$tgConfirm",
"$tgResources",
]
constructor: (@scope, @rootscope, @repo, @confirm, @rs) ->
@scope.$on("admin:project-values:move", @.moveValue)
@rootscope.$on("project:loaded", @.loadValues)
loadValues: =>
return @rs[@scope.resource].listValues(@scope.projectId, @scope.type).then (values) =>
@scope.values = values
@scope.maxValueOrder = _.max(values, "order").order
return values
moveValue: (ctx, itemValue, itemIndex) =>
values = @scope.values
@ -147,7 +162,7 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame) ->
$(document.body).scrollTop(table.offset().top + table.height())
if focus
$(".new-value input").focus()
$el.find(".new-value input:visible").first().focus()
saveValue = (target) ->
form = target.parents("form").checksley()
@ -161,7 +176,25 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame) ->
row.siblings(".visualization").removeClass('hidden')
promise.then null, (data) ->
$confirm.notify("error")
form.setErrors(data)
saveNewValue = (target) ->
form = target.parents("form").checksley()
return if not form.validate()
$scope.newValue.project = $scope.project.id
$scope.newValue.order = if $scope.maxValueOrder then $scope.maxValueOrder + 1 else 1
promise = $repo.create(valueType, $scope.newValue)
promise.then (data) =>
target.addClass("hidden")
$scope.values.push(data)
$scope.maxValueOrder = data.order
initializeNewValue()
promise.then null, (data) ->
form.setErrors(data)
cancel = (target) ->
@ -180,24 +213,8 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame) ->
$el.on "click", ".add-new", debounce 2000, (event) ->
event.preventDefault()
form = $el.find(".new-value").parents("form").checksley()
return if not form.validate()
$scope.newValue.project = $scope.project.id
$scope.newValue.order = if $scope.maxValueOrder then $scope.maxValueOrder + 1 else 1
promise = $repo.create(valueType, $scope.newValue)
promise.then (data) =>
$el.find(".new-value").addClass("hidden")
$scope.values.push(data)
$scope.maxValueOrder = data.order
initializeNewValue()
promise.then null, (data) ->
$confirm.notify("error")
form.setErrors(data)
target = $el.find(".new-value")
saveNewValue(target)
$el.on "click", ".delete-new", (event) ->
event.preventDefault()
@ -223,6 +240,14 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame) ->
target = angular.element(event.currentTarget)
cancel(target)
$el.on "keyup", ".new-value input", (event) ->
if event.keyCode == 13
target = $el.find(".new-value")
saveNewValue(target)
else if event.keyCode == 27
$el.find(".new-value").addClass("hidden")
initializeNewValue()
$el.on "click", ".save", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
@ -321,7 +346,6 @@ ColorSelectionDirective = () ->
module.directive("tgColorSelection", ColorSelectionDirective)
#############################################################################
## Custom Attributes Controller
#############################################################################
@ -342,33 +366,10 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa
constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appTitle) ->
@scope.project = {}
promise = @.loadInitialData()
promise.then () =>
@rootscope.$on "project:loaded", =>
@.loadCustomAttributes()
@appTitle.set("Project Custom Attributes - " + @scope.sectionName + " - " + @scope.project.name)
promise.then null, @.onInitialDataError.bind(@)
loadInitialData: =>
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
@scope.projectId = data.project
return data
return promise.then( => @q.all([
@.loadProject(),
@.loadCustomAttributes(),
]))
#########################
# Project
#########################
loadProject: =>
return @rs.projects.get(@scope.projectId).then (project) =>
@scope.project = project
@scope.$emit('project:loaded', project)
return project
#########################
# Custom Attribute
#########################
@ -438,6 +439,7 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame) ->
showCreateForm = ->
$el.find(".js-new-custom-field").removeClass("hidden")
$el.find(".js-new-custom-field input:visible").first().focus()
hideCreateForm = ->
$el.find(".js-new-custom-field").addClass("hidden")
@ -469,7 +471,6 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame) ->
onError = (data) =>
form.setErrors(data)
$confirm.notify("error")
attr = $scope.newAttr
attr.project = $scope.projectId
@ -525,6 +526,7 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame) ->
showEditForm = (formEl) ->
formEl.find(".js-view-custom-field").addClass("hidden")
formEl.find(".js-edit-custom-field").removeClass("hidden")
formEl.find(".js-edit-custom-field input:visible").first().focus().select()
hideEditForm = (formEl) ->
formEl.find(".js-edit-custom-field").addClass("hidden")
@ -545,7 +547,6 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame) ->
onError = (data) =>
form.setErrors(data)
$confirm.notify("error")
attr = formEl.scope().attr
$ctrl.saveCustomAttribute(attr).then(onSucces, onError)
@ -616,3 +617,55 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame) ->
return {link: link}
module.directive("tgProjectCustomAttributes", ["$log", "$tgConfirm", "animationFrame", ProjectCustomAttributesDirective])
#############################################################################
## CSV Exporter directive
#############################################################################
class CsvExporterController extends taiga.Controller
@.$inject = [
"$scope",
"$rootScope",
"$tgUrls",
"$tgConfirm",
"$tgResources",
]
constructor: (@scope, @rootscope, @urls, @confirm, @rs) ->
@rootscope.$on("project:loaded", @.setCsvUuid)
@scope.$watch "csvUuid", (value) =>
if value
@scope.csvUrl = @urls.resolve("#{@.type}-csv", value)
else
@scope.csvUrl = ""
setCsvUuid: =>
@scope.csvUuid = @scope.project["#{@.type}_csv_uuid"]
regenerateUuid: ->
#TODO: i18n
@confirm.ask("Change URL", "You going to change the CSV data access url. The previous url will be disabled. Are you sure?").then (finish) =>
promise = @rs.projects["regenerate_#{@.type}_csv_uuid"](@scope.projectId)
promise.then (data) =>
@scope.csvUuid = data.data?.uuid
promise.then null, =>
@confirm.notify("error")
promise.finally ->
finish()
return promise
class CsvExporterUserstoriesController extends CsvExporterController
type: "userstories"
class CsvExporterTasksController extends CsvExporterController
type: "tasks"
class CsvExporterIssuesController extends CsvExporterController
type: "issues"
module.controller("CsvExporterUserstoriesController", CsvExporterUserstoriesController)
module.controller("CsvExporterTasksController", CsvExporterTasksController)
module.controller("CsvExporterIssuesController", CsvExporterIssuesController)

View File

@ -84,16 +84,9 @@ urls = {
"project-admin-project-profile-default-values": "/project/:project/admin/project-profile/default-values"
"project-admin-project-profile-modules": "/project/:project/admin/project-profile/modules"
"project-admin-project-profile-export": "/project/:project/admin/project-profile/export"
"project-admin-project-values-us-status": "/project/:project/admin/project-values/us-status"
"project-admin-project-values-us-points": "/project/:project/admin/project-values/us-points"
"project-admin-project-values-us-extras": "/project/:project/admin/project-values/us-extras"
"project-admin-project-values-task-status": "/project/:project/admin/project-values/task-status"
"project-admin-project-values-task-extras": "/project/:project/admin/project-values/task-extras"
"project-admin-project-values-issue-status": "/project/:project/admin/project-values/issue-status"
"project-admin-project-values-issue-types": "/project/:project/admin/project-values/issue-types"
"project-admin-project-values-issue-priorities": "/project/:project/admin/project-values/issue-priorities"
"project-admin-project-values-issue-severities": "/project/:project/admin/project-values/issue-severities"
"project-admin-project-values-issue-extras": "/project/:project/admin/project-values/issue-extras"
"project-admin-project-values-us": "/project/:project/admin/project-values/us"
"project-admin-project-values-task": "/project/:project/admin/project-values/task"
"project-admin-project-values-issue": "/project/:project/admin/project-values/issue"
"project-admin-memberships": "/project/:project/admin/memberships"
"project-admin-roles": "/project/:project/admin/roles"
"project-admin-third-parties-webhooks": "/project/:project/admin/third-parties/webhooks"

View File

@ -118,6 +118,11 @@ urls = {
# Export/Import
"exporter": "/exporter"
"importer": "/importer/load_dump"
# CSV
"userstories-csv": "/userstories/csv?uuid=%s"
"tasks-csv": "/tasks/csv?uuid=%s"
"issues-csv": "/issues/csv?uuid=%s"
}
# Initialize api urls service

View File

@ -50,6 +50,18 @@ resourceProvider = ($config, $repo, $http, $urls, $auth, $q, $rootScope) ->
service.stats = (projectId) ->
return $repo.queryOneRaw("projects", "#{projectId}/stats")
service.regenerate_userstories_csv_uuid = (projectId) ->
url = "#{$urls.resolve("projects")}/#{projectId}/regenerate_userstories_csv_uuid"
return $http.post(url)
service.regenerate_issues_csv_uuid = (projectId) ->
url = "#{$urls.resolve("projects")}/#{projectId}/regenerate_issues_csv_uuid"
return $http.post(url)
service.regenerate_tasks_csv_uuid = (projectId) ->
url = "#{$urls.resolve("projects")}/#{projectId}/regenerate_tasks_csv_uuid"
return $http.post(url)
service.leave = (projectId) ->
url = "#{$urls.resolve("projects")}/#{projectId}/leave"
return $http.post(url)

View File

@ -1,17 +0,0 @@
div.wrapper(tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl",
ng-init="section='admin'; type='issue'; sectionName='Issue extra'")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-issue-extras")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify here issue custom fields. The new field will appear on your issue detail.
div.custom-field-options
a.button.button-green.js-add-custom-field-button(href="",title="Add a custom field in issues")
| Add custom field
include ../includes/modules/admin/admin-custom-attributes

View File

@ -1,18 +0,0 @@
div.wrapper(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='issues'; type='priorities'; sectionName='Issue Priorities'",
type="priorities")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-priorities")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify the priority levels users can assign to issues
div.project-values-options
a.button-green.show-add-new(href="", title="Add New")
span Add new priority
include ../includes/modules/admin/project-types

View File

@ -1,18 +0,0 @@
div.wrapper(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='issues'; type='severities'; sectionName='Issue severities'",
type="severities")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-severities")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify the severity level users can select to classify issues
div.project-values-options
a.button-green.show-add-new(href="", title="Add New")
span Add new severity
include ../includes/modules/admin/project-types

View File

@ -1,18 +0,0 @@
div.wrapper(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='issues'; type='issue-statuses'; sectionName='Issue Statuses'",
type="issue-statuses")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-issue-status")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify the column headers that you will use to classify Issues
div.project-values-options
a.button-green.show-add-new(href="", title="Add New")
span Add new status
include ../includes/modules/admin/project-status

View File

@ -1,18 +0,0 @@
div.wrapper(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='issues'; type='issue-types'; sectionName='Issue Types'",
type="issue-types")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-issue-types")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify the categories users can select to classify issues
div.project-values-options
a.button-green.show-add-new(href="", title="Add New")
span Add new type
include ../includes/modules/admin/project-types

View File

@ -0,0 +1,41 @@
div.wrapper(ng-controller="ProjectValuesSectionController")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-issue")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common.admin-attributes
include ../includes/components/mainTitle
p.admin-subtitle Specify the column headers that you will use to classify Issues
div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='issues'; type='issue-statuses'; sectionName='Status'",
type="issue-statuses")
include ../includes/modules/admin/project-status
div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='issues'; type='priorities'; sectionName='Priorities'; objName='priority'",
type="priorities")
include ../includes/modules/admin/project-types
div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='issues'; type='severities'; sectionName='Severities'; objName='severity'",
type="severities")
include ../includes/modules/admin/project-types
div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='issues'; type='issue-types'; sectionName='Types'; objName='type'",
type="issue-types")
include ../includes/modules/admin/project-types
div.admin-attributes-section(tg-project-custom-attributes,
ng-controller="ProjectCustomAttributesController as ctrl",
ng-init="type='issue';")
- var customFieldButtonTitle = "Add a custom field in tasks"
include ../includes/modules/admin/admin-custom-attributes
- var csvType = "Issues";
- var controller = "CsvExporterIssuesController";
div.admin-attributes-section
include ../includes/modules/admin/project-csv

View File

@ -1,17 +0,0 @@
div.wrapper(tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl",
ng-init="section='admin'; type='task'; sectionName='Task extra'")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-task-extras")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify here task custom fields. The new field will appear on your task detail.
div.custom-field-options
a.button.button-green.js-add-custom-field-button(href="",title="Add a custom field in tasks")
| Add custom field
include ../includes/modules/admin/admin-custom-attributes

View File

@ -1,18 +0,0 @@
div.wrapper(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='tasks'; type='task-statuses'; sectionName='Task Statuses'",
type="task-statuses")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-task-status")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify the column headers that you will use to classify Tasks related to each User Stories
div.project-values-options
a.button-green.show-add-new(href="", title="Add New")
span Add new status
include ../includes/modules/admin/project-status

View File

@ -0,0 +1,26 @@
div.wrapper(ng-controller="ProjectValuesSectionController")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-task")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common.admin-attributes
include ../includes/components/mainTitle
p.admin-subtitle Specify the column headers that you will use to classify Tasks related to each User Stories
div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='tasks'; type='task-statuses'; sectionName='Task Statuses'",
type="task-statuses")
include ../includes/modules/admin/project-status
div.admin-attributes-section(tg-project-custom-attributes,
ng-controller="ProjectCustomAttributesController as ctrl",
ng-init="type='task';")
- var customFieldButtonTitle = "Add a custom field in tasks"
include ../includes/modules/admin/admin-custom-attributes
- var csvType = "Task";
- var controller = "CsvExporterTasksController";
div.admin-attributes-section
include ../includes/modules/admin/project-csv

View File

@ -1,17 +0,0 @@
div.wrapper(tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl",
ng-init="section='admin'; type='userstory'; sectionName='US extra'")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-us-extras")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify here user story custom fields. The new field will appear on your user story detail.
div.custom-field-options
a.button.button-green.js-add-custom-field-button(href="",title="Add a custom field in user stories")
| Add custom field
include ../includes/modules/admin/admin-custom-attributes

View File

@ -1,24 +0,0 @@
div.wrapper(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='userstories'; type='points'; sectionName='Us points'",
type="points")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-us-points")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify the numerical system you will use to indicate the level of difficulty for each User Story
- var helpLightboxId = "notion-admin-project-values-us-points"
include ../includes/components/help-notion-button
div.project-values-options
a.button-green.show-add-new(href="", title="Add New")
span Add new point
include ../includes/modules/admin/project-points
div.lightbox.lightbox-generic-notion.notion-admin-project-values-us-points(id="notion-admin-project-values-us-points", tg-lb-notion)
include ../includes/modules/help-notions/lightbox-notion-admin-project-values-us-points

View File

@ -1,18 +0,0 @@
div.wrapper(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='userstories'; type='userstory-statuses'; sectionName='Us Statuses'",
type="userstory-statuses")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-us-status")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common
include ../includes/components/mainTitle
p.admin-subtitle Specify the column headers that you will use to classify User Stories
div.project-values-options
a.button-green.show-add-new(href="", title="Add New")
span Add new status
include ../includes/modules/admin/project-us-status

View File

@ -0,0 +1,31 @@
div.wrapper(ng-controller="ProjectValuesSectionController")
sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values")
include ../includes/modules/admin-menu
sidebar.menu-tertiary.sidebar(tg-admin-navigation="values-us")
include ../includes/modules/admin-submenu-project-values
section.main.admin-common.admin-attributes
include ../includes/components/mainTitle
p.admin-subtitle Specify the column headers that you will use to classify User Stories
div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='userstories'; type='userstory-statuses'; sectionName='Us Statuses'",
type="userstory-statuses")
include ../includes/modules/admin/project-us-status
div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl",
ng-init="section='admin'; resource='userstories'; type='points'; sectionName='Us points'",
type="points")
include ../includes/modules/admin/project-points
div.admin-attributes-section(tg-project-custom-attributes,
ng-controller="ProjectCustomAttributesController as ctrl",
ng-init="type='userstory';")
- var customFieldButtonTitle = "Add a custom field in tasks"
include ../includes/modules/admin/admin-custom-attributes
- var csvType = "US";
- var controller = "CsvExporterUserstoriesController";
div.admin-attributes-section
include ../includes/modules/admin/project-csv

View File

@ -6,19 +6,19 @@ section.admin-menu
ul
li#adminmenu-project-profile
a(href="", tg-nav="project-admin-project-profile-details:project=project.slug")
span.title Project profile
span.title Project
span.icon.icon-arrow-right
li#adminmenu-project-values
a(href="", tg-nav="project-admin-project-values-us-status:project=project.slug")
span.title Custom Attributes
a(href="", tg-nav="project-admin-project-values-us:project=project.slug")
span.title Attributes
span.icon.icon-arrow-right
li#adminmenu-memberships
a(href="" tg-nav="project-admin-memberships:project=project.slug")
span.title Manage members
span.title Members
span.icon.icon-arrow-right
li#adminmenu-roles
a(href="" tg-nav="project-admin-roles:project=project.slug")
span.title Roles & Permissions
span.title Permissions
span.icon.icon-arrow-right
li#adminmenu-third-parties
a(href="" tg-nav="project-admin-third-parties-webhooks:project=project.slug")

View File

@ -1,55 +1,20 @@
section.admin-submenu
header
h1 Custom Attributes
h1 Attributes
nav
ul
li#adminmenu-values-us-status
a(href="", tg-nav="project-admin-project-values-us-status:project=project.slug")
span.title US statuses
li#adminmenu-values-us
a(href="", tg-nav="project-admin-project-values-us:project=project.slug")
span.title US
span.icon.icon-arrow-right
li#adminmenu-values-us-points
a(href="", tg-nav="project-admin-project-values-us-points:project=project.slug")
span.title US points
li#adminmenu-values-task
a(href="", tg-nav="project-admin-project-values-task:project=project.slug")
span.title Task
span.icon.icon-arrow-right
li#adminmenu-values-us-extras
a(href="", tg-nav="project-admin-project-values-us-extras:project=project.slug")
span.title US extras
span.icon.icon-arrow-right
li#adminmenu-values-task-status
a(href="", tg-nav="project-admin-project-values-task-status:project=project.slug")
span.title Task statuses
span.icon.icon-arrow-right
li#adminmenu-values-task-extras
a(href="", tg-nav="project-admin-project-values-task-extras:project=project.slug")
span.title Task extras
span.icon.icon-arrow-right
li#adminmenu-values-issue-status
a(href="", tg-nav="project-admin-project-values-issue-status:project=project.slug")
span.title Issue statuses
span.icon.icon-arrow-right
li#adminmenu-values-issue-types
a(href="", tg-nav="project-admin-project-values-issue-types:project=project.slug")
span.title Issue types
span.icon.icon-arrow-right
li#adminmenu-values-priorities
a(href="", tg-nav="project-admin-project-values-issue-priorities:project=project.slug")
span.title Issue Priorities
span.icon.icon-arrow-right
li#adminmenu-values-severities
a(href="", tg-nav="project-admin-project-values-issue-severities:project=project.slug")
span.title Issue Severities
span.icon.icon-arrow-right
li#adminmenu-values-issue-extras
a(href="", tg-nav="project-admin-project-values-issue-extras:project=project.slug")
span.title Issue extras
li#adminmenu-values-issue
a(href="", tg-nav="project-admin-project-values-issue:project=project.slug")
span.title Issue
span.icon.icon-arrow-right

View File

@ -1,4 +1,9 @@
section.custom-fields-table.basic-table
div.project-values-title
h2 Custom fields
a.button.button-gray.show-add-new.js-add-custom-field-button(href="", title="#{customFieldButtonTitle}")
span Add custom field
div.table-header
div.row
div.custom-name

View File

@ -0,0 +1,21 @@
section.project-csv(ng-controller='#{controller} as ctrl', tg-select-input-text)
div.project-values-title
h2 Export #{csvType} Data
span (.csv format)
a.button.button-gray(title="Download #{csvType} CSV", ng-href="{{csvUrl}}")
span Download CSV
p Get all information about your project #{csvType}. Save all your data to a <em>.csv</em> file and open it in your favourite text editor or spreadsheet. You will be able to visualize and analize all your data easily.
div.csv-regenerate-field
.field-with-options
input(type="text", placeholder="Please regenerate CSV url", readonly, ng-model="csvUrl")
.option-wrapper.select-input-content
.icon.icon-copy
a(href="", title="Regenerate CSV url", ng-click="ctrl.regenerateUuid()")
span.icon.icon-reload
span Regenerate
a.help-button(href="", target="_blank")
span.icon.icon-help
span How to use this on my own spreadsheet?

View File

@ -1,4 +1,10 @@
section.project-values-table
div.project-values-title
h2 Points
a.button.button-gray.show-add-new(href="", title="Add New")
span Add new point
div.project-values-header
div.project-values-row
div.project-values-name

View File

@ -1,4 +1,9 @@
section.colors-table
section.colors-table.admin-status-table
div.project-values-title
h2 Status
a.button.button-gray.show-add-new(href="", title="Add New")
span Add new status
div.table-header
div.row
div.color-column Color

View File

@ -1,4 +1,10 @@
section.colors-table
div.project-values-title
h2 {{ sectionName }}
a.button.button-gray.show-add-new(href="", title="Add New")
span Add new {{ objName }}
div.table-header
div.row
div.color-column Color

View File

@ -1,89 +1,96 @@
section.colors-table
div.table-header
div.row
div.color-column Color
div.status-name Name
div.status-slug Slug
div.is-closed-column Is closed?
div.is-archived-column Is archived?
div.status-wip-limit WIP Limit
div.options-column
section.project-us-status
div.table-main
div.sortable
form(ng-repeat="value in values")
div.row.table-main.visualization
span.icon.icon-drag-v
div.project-values-title
h2 Status
a.button.button-gray.show-add-new(href="", title="Add New")
span Add new status
div.color-column
div.current-color(style="background: {{ value.color }}")
div.colors-table
div.table-header
div.row
div.color-column Color
div.status-name Name
div.status-slug Slug
div.is-closed-column Is closed?
div.is-archived-column Is archived?
div.status-wip-limit WIP Limit
div.options-column
div.status-name
span {{ value.name }}
div.table-main
div.sortable
form(ng-repeat="value in values")
div.row.table-main.visualization
span.icon.icon-drag-v
div.status-slug
span {{ value.slug }}
div.color-column
div.current-color(style="background: {{ value.color }}")
div.is-closed-column
div.icon.icon-check-square(ng-show="value.is_closed")
div.status-name
span {{ value.name }}
div.is-archived-column
div.icon.icon-check-square(ng-show="value.is_archived")
div.status-slug
span {{ value.slug }}
div.status-wip-limit
span {{ value.wip_limit }}
div.is-closed-column
div.icon.icon-check-square(ng-show="value.is_closed")
div.options-column
a.edit-value.icon.icon-edit(href="", title="Edit value")
a.delete-value.icon.icon-delete(href="", title="Delete value")
div.is-archived-column
div.icon.icon-check-square(ng-show="value.is_archived")
div.row.table-main.edition.hidden
div.color-column(tg-color-selection, ng-model="value")
div.current-color(style="background: {{ value.color }}")
div.status-wip-limit
span {{ value.wip_limit }}
div.options-column
a.edit-value.icon.icon-edit(href="", title="Edit value")
a.delete-value.icon.icon-delete(href="", title="Delete value")
div.row.table-main.edition.hidden
div.color-column(tg-color-selection, ng-model="value")
div.current-color(style="background: {{ value.color }}")
include ../../components/select-color
div.status-name
input(name="name", type="text", placeholder="Write a name for the new status",
ng-model="value.name", data-required="true", data-maxlength="255")
div.is-closed-column
select(name="is_closed", ng-model="value.is_closed", data-required="true",
ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]")
div.is-archived-column
select(name="is_archived", ng-model="value.is_archived", data-required="true",
ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]")
div.status-wip-limit
input(name="wip_limit", type="number", placeholder="WIP Limit",
ng-model="value.wip_limit", data-type="digits")
div.options-column
a.save.icon.icon-floppy(href="", title="Save changes")
a.cancel.icon.icon-delete(href="", title="Cancel")
form
div.row.table-main.new-value.hidden
div.color-column(tg-color-selection, ng-model="newValue")
div.current-color(style="background: {{ newValue.color }}")
include ../../components/select-color
div.status-name
input(name="name", type="text", placeholder="Write a name for the new status",
ng-model="value.name", data-required="true", data-maxlength="255")
ng-model="newValue.name", data-required="true", data-maxlength="255")
div.is-closed-column
select(name="is_closed", ng-model="value.is_closed", data-required="true",
select(name="is_closed", ng-model="newValue.is_closed", data-required="true",
ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]")
div.is-archived-column
select(name="is_archived", ng-model="value.is_archived", data-required="true",
select(name="is_archived", ng-model="newValue.is_archived", data-required="true",
ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]")
div.status-wip-limit
input(name="wip_limit", type="number", placeholder="WIP Limit",
ng-model="value.wip_limit", data-type="digits")
ng-model="newValue.wip_limit", data-type="digits")
div.options-column
a.save.icon.icon-floppy(href="", title="Save changes")
a.cancel.icon.icon-delete(href="", title="Cancel")
form
div.row.table-main.new-value.hidden
div.color-column(tg-color-selection, ng-model="newValue")
div.current-color(style="background: {{ newValue.color }}")
include ../../components/select-color
div.status-name
input(name="name", type="text", placeholder="Write a name for the new status",
ng-model="newValue.name", data-required="true", data-maxlength="255")
div.is-closed-column
select(name="is_closed", ng-model="newValue.is_closed", data-required="true",
ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]")
div.is-archived-column
select(name="is_archived", ng-model="newValue.is_archived", data-required="true",
ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]")
div.status-wip-limit
input(name="wip_limit", type="number", placeholder="WIP Limit",
ng-model="newValue.wip_limit", data-type="digits")
div.options-column
a.add-new.icon.icon-floppy(href="", title="Add")
a.delete-new.icon.icon-delete(href="", title="Cancel")
a.add-new.icon.icon-floppy(href="", title="Add")
a.delete-new.icon.icon-delete(href="", title="Cancel")

View File

@ -60,7 +60,8 @@
}
}
.button-gray {
.button-gray,
a.button-gray {
@extend %button;
background: $gray;
&:hover,

View File

@ -1,3 +1,9 @@
.admin-attributes {
.admin-attributes-section {
margin-bottom: 2rem;
}
}
.admin-roles {
header {
position: relative;
@ -12,7 +18,27 @@
}
}
.project-values-options {
margin-bottom: 1rem;
text-align: right;
.project-values-title {
align-content: center;
align-items: center;
background: $whitish;
display: flex;
justify-content: space-between;
padding: .5rem 1rem;
text-transform: uppercase;
h2 {
margin: 0;
span {
margin-left: .5rem;
text-transform: none;
}
}
a {
display: inline-block;
}
}
//.project-values-options {
// margin-bottom: 1rem;
// text-align: right;
//}

View File

@ -6,7 +6,7 @@
}
.admin-subtitle {
color: $gray-light;
margin: 0;
margin-bottom: 2rem;
}
.total {
@extend %large;

View File

@ -0,0 +1,41 @@
.project-csv {
.project-values-title {
margin-bottom: 1rem;
}
.csv-regenerate-field {
align-content: center;
align-items: center;
display: flex;
justify-content: space-between;
margin-bottom: 1rem;
a {
@extend %small;
}
span:first-child {
margin-right: .3rem;
}
}
.field-with-options {
display: flex;
margin-right: 1rem;
width: 100%;
input {
flex-grow: 1;
}
}
.option-wrapper {
align-items: center;
border: 1px solid $gray-light;
border-left: 0;
border-radius: 0 5px 5px 0;
cursor: pointer;
display: flex;
padding: 0 1rem;
}
.button {
padding: .5rem 1rem;
span {
margin: 0;
}
}
}

View File

@ -87,7 +87,7 @@
}
}
.table-main {
border-bottom: 1px solid $gray-light;
border-bottom: 1px solid $whitish;
.row {
&:hover {
background: lighten($green-taiga, 60%);

View File

@ -131,6 +131,7 @@ exports.files = function () {
'modules/admin/third-parties',
'modules/admin/admin-third-parties-webhooks',
'modules/admin/contrib',
'modules/admin/project-csv',
//Modules user Settings
'modules/user-settings/user-profile',