diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee
index 2c5275f9..b7a4f1a1 100644
--- a/app/coffee/app.coffee
+++ b/app/coffee/app.coffee
@@ -39,7 +39,7 @@ taiga.sessionId = taiga.generateUniqueSessionIdentifier()
configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEventsProvider, tgLoaderProvider,
$compileProvider, $translateProvider) ->
$routeProvider.when("/",
- {templateUrl: "home/home-page.html"})
+ {templateUrl: "home/home-page.html", resolve: {loader: tgLoaderProvider.add()}})
$routeProvider.when("/projects/",
{templateUrl: "projects/projects-page.html", resolve: {loader: tgLoaderProvider.add()}})
@@ -320,6 +320,7 @@ modules = [
"taigaEvents",
# Specific Modules
+ "taigaHome",
"taigaNavigationBar",
"taigaProjects",
"taigaRelatedTasks",
diff --git a/app/coffee/modules/base.coffee b/app/coffee/modules/base.coffee
index 5aef4043..b74f30bf 100644
--- a/app/coffee/modules/base.coffee
+++ b/app/coffee/modules/base.coffee
@@ -69,9 +69,7 @@ urls = {
"project-search": "/project/:project/search"
"project-userstories-detail": "/project/:project/us/:ref"
-
"project-tasks-detail": "/project/:project/task/:ref"
-
"project-issues-detail": "/project/:project/issue/:ref"
"project-wiki": "/project/:project/wiki"
diff --git a/app/coffee/modules/resources/issues.coffee b/app/coffee/modules/resources/issues.coffee
index 0cbb99de..bf7c27df 100644
--- a/app/coffee/modules/resources/issues.coffee
+++ b/app/coffee/modules/resources/issues.coffee
@@ -41,6 +41,9 @@ resourceProvider = ($repo, $http, $urls, $storage, $q) ->
params.ref = ref
return $repo.queryOne("issues", "by_ref", params)
+ service.listInAllProjects = (filters) ->
+ return $repo.queryMany("issues", filters)
+
service.list = (projectId, filters, options) ->
params = {project: projectId}
params = _.extend({}, params, filters or {})
diff --git a/app/coffee/modules/resources/tasks.coffee b/app/coffee/modules/resources/tasks.coffee
index 56a00de3..7069012c 100644
--- a/app/coffee/modules/resources/tasks.coffee
+++ b/app/coffee/modules/resources/tasks.coffee
@@ -41,6 +41,9 @@ resourceProvider = ($repo, $http, $urls, $storage) ->
params.ref = ref
return $repo.queryOne("tasks", "by_ref", params)
+ service.listInAllProjects = (filters) ->
+ return $repo.queryMany("tasks", filters)
+
service.list = (projectId, sprintId=null, userStoryId=null) ->
params = {project: projectId}
params.milestone = sprintId if sprintId
diff --git a/app/coffee/modules/resources/userstories.coffee b/app/coffee/modules/resources/userstories.coffee
index ac43dfff..de2f8c9b 100644
--- a/app/coffee/modules/resources/userstories.coffee
+++ b/app/coffee/modules/resources/userstories.coffee
@@ -38,6 +38,9 @@ resourceProvider = ($repo, $http, $urls, $storage) ->
params.ref = ref
return $repo.queryOne("userstories", "by_ref", params)
+ service.listInAllProjects = (filters) ->
+ return $repo.queryMany("userstories", filters)
+
service.listUnassigned = (projectId, filters) ->
params = {"project": projectId, "milestone": "null"}
params = _.extend({}, params, filters or {})
diff --git a/app/locales/locale-en.json b/app/locales/locale-en.json
index 19f7268e..4dc5faf1 100644
--- a/app/locales/locale-en.json
+++ b/app/locales/locale-en.json
@@ -101,6 +101,9 @@
}
},
"SEE_USER_PROFILE": "See {{username }} profile",
+ "USER_STORY": "User story",
+ "TASK": "Task",
+ "ISSUE": "Issue",
"TAGS": {
"PLACEHOLDER": "I'm it! Tag me...",
"DELETE": "Delete tag",
@@ -241,6 +244,9 @@
"REGISTER": "Register",
"CREATE_ACCOUNT": "create your free account here"
},
+ "HOME": {
+ "EMPTY_WATCHING": "Follow the projects, User Stories, Tasks, Issues... that you want to know about :)"
+ },
"ATTACHMENT": {
"SECTION_NAME": "attachments",
"TITLE": "{{ fileName }} uploaded on {{ date }}",
diff --git a/app/modules/home/duties/duty-directive.coffee b/app/modules/home/duties/duty-directive.coffee
new file mode 100644
index 00000000..72f544a3
--- /dev/null
+++ b/app/modules/home/duties/duty-directive.coffee
@@ -0,0 +1,37 @@
+DutyDirective = (navurls, projectsService, $translate) ->
+ link = (scope, el, attrs, ctrl) ->
+ scope.vm = {}
+ scope.vm.duty = scope.duty
+
+ scope.vm.getDutyType = () ->
+ if scope.vm.duty
+ if scope.vm.duty._name == "userstories"
+ return $translate.instant("COMMON.USER_STORY")
+ if scope.vm.duty._name == "tasks"
+ return $translate.instant("COMMON.TASK")
+ if scope.vm.duty._name == "issues"
+ return $translate.instant("COMMON.ISSUE")
+
+ scope.vm.getUrl = () ->
+ if scope.vm.duty
+ ctx = {
+ project: projectsService.projectsById.get(String(scope.vm.duty.project)).slug
+ ref: scope.vm.duty.ref
+ }
+ return navurls.resolve("project-#{scope.vm.duty._name}-detail", ctx)
+
+ scope.vm.getProjectName = () ->
+ if scope.vm.duty
+ return projectsService.projectsById.get(String(scope.vm.duty.project)).name
+
+ directive = {
+ templateUrl: "home/duties/duty.html"
+ scope: {
+ "duty": "=tgDuty"
+ }
+ link: link
+ }
+
+ return directive
+
+angular.module("taigaHome").directive("tgDuty", ["$tgNavUrls", "tgProjects", "$translate", DutyDirective])
diff --git a/app/modules/home/duties/duty.jade b/app/modules/home/duties/duty.jade
new file mode 100644
index 00000000..dcb8fa5e
--- /dev/null
+++ b/app/modules/home/duties/duty.jade
@@ -0,0 +1,12 @@
+img.avatar(
+ src="https://s3.amazonaws.com/uifaces/faces/twitter/rem/128.jpg"
+ title="{{ user.fullname }}")
+
+div.duty-data
+ div
+ span.duty-type {{ vm.getDutyType() }}
+ span.duty-status(ng-style="{'color': vm.duty.status_color}") {{ ::vm.duty.status_name }}
+ a.duty-title(href="{{ vm.getUrl() }}")
+ span.duty-id(tg-bo-ref="duty.ref")
+ span.duty-name {{ ::duty.subject }}
+div.duty-project {{ ::vm.getProjectName()}}
diff --git a/app/modules/home/home-directive.coffee b/app/modules/home/home-directive.coffee
index c5218db5..a929d370 100644
--- a/app/modules/home/home-directive.coffee
+++ b/app/modules/home/home-directive.coffee
@@ -1,9 +1,26 @@
-HomeDirective = ->
+HomeDirective = (homeService) ->
+ link = (scope, el, attrs, ctrl) ->
+ scope.vm = {}
+ taiga.defineImmutableProperty(scope.vm, "workInProgress", () -> homeService.workInProgress)
+
+ scope.$watch "vm.workInProgress", (workInProgress) ->
+ if workInProgress.size > 0
+ userStories = workInProgress.get("assignedTo").get("userStories")
+ tasks = workInProgress.get("assignedTo").get("tasks")
+ issues = workInProgress.get("assignedTo").get("issues")
+ scope.vm.assignedTo = userStories.concat(tasks).concat(issues)
+
+ userStories = workInProgress.get("watching").get("userStories")
+ tasks = workInProgress.get("watching").get("tasks")
+ issues = workInProgress.get("watching").get("issues")
+ scope.vm.watching = userStories.concat(tasks).concat(issues)
+
directive = {
templateUrl: "home/home.html"
scope: {}
+ link: link
}
return directive
-angular.module("taigaProjects").directive("tgHome", HomeDirective)
+angular.module("taigaHome").directive("tgHome", ["tgHomeService", HomeDirective])
diff --git a/app/modules/home/home-page.controller.coffee b/app/modules/home/home-page.controller.coffee
index eddc1b65..36eeba8f 100644
--- a/app/modules/home/home-page.controller.coffee
+++ b/app/modules/home/home-page.controller.coffee
@@ -12,22 +12,28 @@ class ProjectsPageController extends taiga.Controller
"$tgConfig",
"tgLoader",
"tgProjects",
+ "tgHomeService",
"$translate"
]
constructor: (@scope, @q, @rs, @rootscope, @navUrls, @auth, @location,
- @appTitle, @projectUrl, @config, tgLoader, @projects, @translate) ->
+ @appTitle, @projectUrl, @config, tgLoader, @projectsService, @homeService,
+ @translate) ->
@appTitle.set(@translate.instant("PROJECT.WELCOME"))
if !@auth.isAuthenticated()
@location.path(@navUrls.resolve("login"))
#Projects
- promise = @projects.fetchProjects()
+ projectsPromise = @projectsService.fetchProjects()
+
+ #In progress work
+ user = @auth.getUser()
+ workInProgressPromise = @homeService.fetchWorkInProgress(user.id)
# Finally
- promise.finally tgLoader.pageLoaded
+ @q.all([projectsPromise, workInProgressPromise]).finally tgLoader.pageLoaded
angular.module("taigaHome").controller("HomePage", ProjectsPageController)
diff --git a/app/modules/home/home-service.coffee b/app/modules/home/home-service.coffee
new file mode 100644
index 00000000..a3b97fce
--- /dev/null
+++ b/app/modules/home/home-service.coffee
@@ -0,0 +1,59 @@
+class HomeService extends taiga.Service
+ @.$inject = ["$q", "$tgResources", "$rootScope", "$projectUrl"]
+
+ constructor: (@q, @rs, @rootScope, @projectUrl) ->
+ @.workInProgress = Immutable.Map()
+ @.inProgress = false
+
+ fetchWorkInProgress: (userId) ->
+ if not @.inProgress
+ @.inProgress = true
+ params = {
+ status__is_closed: false
+ assigned_to: userId
+ }
+ assignedUserStoriesPromise = @rs.userstories.listInAllProjects(params).then (userstories) =>
+ @.assignedToUserStories = userstories
+
+ assignedTasksPromise = @rs.tasks.listInAllProjects(params).then (tasks) =>
+ @.assignedToTasks = tasks
+
+ assignedIssuesPromise = @rs.issues.listInAllProjects(params).then (issues) =>
+ @.assignedToIssues = issues
+
+ params = {
+ status__is_closed: false
+ watchers: userId
+ }
+ watchingUserStoriesPromise = @rs.userstories.listInAllProjects(params).then (userstories) =>
+ @.watchingUserStories = userstories
+
+ watchingTasksPromise = @rs.tasks.listInAllProjects(params).then (tasks) =>
+ @.watchingTasks = tasks
+
+ watchingIssuesPromise = @rs.issues.listInAllProjects(params).then (issues) =>
+ @.watchingIssues = issues
+
+ workPromise = @q.all([assignedUserStoriesPromise, assignedTasksPromise,
+ assignedIssuesPromise, watchingUserStoriesPromise,
+ watchingUserStoriesPromise, watchingIssuesPromise])
+
+ workPromise.then =>
+ @.workInProgress = Immutable.fromJS({
+ assignedTo: {
+ userStories: @.assignedToUserStories
+ tasks: @.assignedToTasks
+ issues: @.assignedToIssues
+ }
+ watching: {
+ userStories: @.watchingUserStories
+ tasks: @.watchingTasks
+ issues: @.watchingIssues
+ }
+ })
+
+ @.inProgress = false
+
+ return workPromise
+
+angular.module("taigaHome").service("tgHomeService", HomeService)
diff --git a/app/modules/home/home.jade b/app/modules/home/home.jade
index de24aac1..ccb73a9d 100644
--- a/app/modules/home/home.jade
+++ b/app/modules/home/home.jade
@@ -1,68 +1,22 @@
doctype html
include ../../partials/includes/components/beta
-div.home-wrapper.centered(ng-controller="HomePage")
+div.home-wrapper.centered
div.duty-summary
- // TODO Hide if ASSIGNED TO ==== false
- div.title-bar.working-on-title Working on
- // TODO Hide if ASSIGNED TO ==== false
- section.working-on
- // TODO Remove and replace for an angular repeat
- - for (var x = 0; x < 2; x++)
- div.duty-single
- img.avatar(src="https://s3.amazonaws.com/uifaces/faces/twitter/rem/128.jpg", title="{{ user.fullname }}")
- div.duty-data
- div
- // TODO, ADD THEIR COLOR TO THE DUTY TYPE AND STATUS
- span.duty-type User Story
- span.duty-status New
- a.duty-title(href="")
- span.duty-id #1504
- span.duty-name Documentación III: (notificaciones asíncronas + plugins front/back)
- div.duty-project Taiga
- div.duty-single.blocked
- img.avatar(src="https://s3.amazonaws.com/uifaces/faces/twitter/rem/128.jpg", title="{{ user.fullname }}")
- div.duty-data
- div
- // TODO, ADD THEIR COLOR TO THE DUTY TYPE AND STATUS
- span.duty-type User Story
- span.duty-status Blocked
- a.duty-title(href="")
- span.duty-id #1504
- span.duty-name Documentación III: (notificaciones asíncronas + plugins front/back) Documentación III: (notificaciones asíncronas + plugins front/back)
- div.duty-project Whatever
+ // TODO: if not assigned to items?
+ // TODO: i18n
+ div.title-bar.working-on-title(ng-show="vm.assignedTo") Working on
+ section.working-on(ng-show="vm.assignedTo")
+ div.duty-single(tg-duty="duty", tg-repeat="duty in vm.assignedTo", ng-class="{blocked: duty.is_blocked}")
div.title-bar.watching-title Watching
- // TODO Show if WATCHERS ==== false
- section.watching-empty.hidden
+ section.watching-empty(ng-show="!vm.watching.size")
include ../../svg/hide.svg
- p Follow the projects, User Stories, Tasks, Issues... that you want to know about :)
+ // TODO: i18n
+ p(translate="HOME.EMPTY_WATCHING")
+
+ section.watching(ng-show="vm.watching")
+ div.duty-single(tg-duty="duty", tg-repeat="duty in vm.watching", ng-class="{blocked: duty.is_blocked}")
- // TODO Show if WATCHERS ==== true
- section.watching
- - for (var x = 0; x < 20; x++)
- div.duty-single
- img.avatar(src="https://s3.amazonaws.com/uifaces/faces/twitter/annapickard/128.jpg", title="{{ user.fullname }}")
- div.duty-data
- div
- // TODO, ADD THEIR COLOR TO THE DUTY TYPE AND STATUS
- span.duty-type User Story
- span.duty-status New
- a.duty-title(href="")
- span.duty-id #1504
- span.duty-name Documentación III: (notificaciones asíncronas + plugins front/back)
- div.duty-project Taiga
- div.duty-single
- img.avatar(src="https://s3.amazonaws.com/uifaces/faces/twitter/sircookieface/128.jpg", title="{{ user.fullname }}")
- div.duty-data
- div
- // TODO, ADD THEIR COLOR TO THE DUTY TYPE AND STATUS
- span.duty-type Bug
- span.duty-status Ready for test
- a.duty-title(href="")
- span.duty-id #28
- span.duty-name It is not possible to re-order stories in the sprint view .
- div.duty-project Teletransportation hubs
- a.button-gray.see-more(href="#", title="See more Watching US") See more
aside.project-list(tg-home-project-list)
diff --git a/app/modules/home/projects/list.jade b/app/modules/home/projects/list.jade
index e76b6ed3..5fadc4d1 100644
--- a/app/modules/home/projects/list.jade
+++ b/app/modules/home/projects/list.jade
@@ -1,4 +1,4 @@
-ul.home-project-list(ng-show="vm.projects.length")
+ul.home-project-list(ng-show="vm.projects.size")
li.home-project-list-single(tg-bind-scope, tg-repeat="project in vm.projects")
a(href="#", tg-nav="project:project=project.slug")
h2.home-project-list-single-title
@@ -7,8 +7,8 @@ ul.home-project-list(ng-show="vm.projects.length")
include ../../../svg/lock.svg
p {{ ::project.description | limitTo:150 }}
span(ng-if="::project.description.length > 150") ...
-a.see-more-projects-btn.button-gray(ng-show="vm.projects.length", href="#", tg-nav="projects", title="{{'PROJECT.NAVIGATION.SEE_MORE_PROJECTS' | translate}}", translate="PROJECT.NAVIGATION.SEE_MORE_PROJECTS")
-section.projects-empty(ng-hide="vm.projects.length")
+a.see-more-projects-btn.button-gray(ng-show="vm.projects.size", href="#", tg-nav="projects", title="{{'PROJECT.NAVIGATION.SEE_MORE_PROJECTS' | translate}}", translate="PROJECT.NAVIGATION.SEE_MORE_PROJECTS")
+section.projects-empty(ng-hide="vm.projects.size")
include ../../../svg/empty-project.svg
p You don't have any projects yet
a.create-project-btn.button-green(
@@ -16,5 +16,3 @@ section.projects-empty(ng-hide="vm.projects.length")
ng-click="vm.newProject()",
title="{{'PROJECT.NAVIGATION.ACTION_CREATE_PROJECT' | translate}}",
translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT")
-
-
diff --git a/app/modules/projects/projects-page.controller.coffee b/app/modules/projects/projects-page.controller.coffee
index 1496e80a..97cafb50 100644
--- a/app/modules/projects/projects-page.controller.coffee
+++ b/app/modules/projects/projects-page.controller.coffee
@@ -11,12 +11,13 @@ class ProjectsPageController extends taiga.Controller
"$projectUrl",
"$tgConfig",
"tgLoader",
- "tgProjects"
+ "tgProjects",
+ "$translate"
]
constructor: (@scope, @q, @rs, @rootscope, @navUrls, @auth, @location,
- @appTitle, @projectUrl, @config, tgLoader, @projects) ->
- @appTitle.set("Projects")
+ @appTitle, @projectUrl, @config, tgLoader, @projects, @translate) ->
+ @appTitle.set(@translate.instant("PROJECT.SECTION_PROJECTS"))
if !@auth.isAuthenticated()
@location.path(@navUrls.resolve("login"))
diff --git a/app/modules/projects/projects.service.coffee b/app/modules/projects/projects.service.coffee
index 0ed2e2c4..65edc942 100644
--- a/app/modules/projects/projects.service.coffee
+++ b/app/modules/projects/projects.service.coffee
@@ -1,8 +1,12 @@
+taiga = @.taiga
+groupBy = @.taiga.groupBy
+
class ProjectsService extends taiga.Service
@.$inject = ["$q", "$tgResources", "$rootScope", "$projectUrl", "tgLightboxFactory"]
constructor: (@q, @rs, @rootScope, @projectUrl, @lightboxFactory) ->
@.projects = Immutable.Map()
+ @.projectsById = Immutable.Map()
@.inProgress = false
@.projectsPromise = null
@.fetchProjects()
@@ -19,6 +23,8 @@ class ProjectsService extends taiga.Service
recents: projects.slice(0, 10)
})
+ @.projectsById = Immutable.fromJS(groupBy(projects, (p) -> p.id))
+
return @.projects
@.projectsPromise.then () =>