commit
090a591074
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- Ability to create url custom fields. (thanks to [@astagi](https://github.com/astagi)).
|
- Ability to create url custom fields. (thanks to [@astagi](https://github.com/astagi)).
|
||||||
|
- Blocked projects support
|
||||||
- Moved from iconfont to SVG sprite icon system and redesign.
|
- Moved from iconfont to SVG sprite icon system and redesign.
|
||||||
- Redesign 'Admin > Project > Modules' panel.
|
- Redesign 'Admin > Project > Modules' panel.
|
||||||
- Add badge to project owners
|
- Add badge to project owners
|
||||||
|
|
|
@ -111,6 +111,16 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
$routeProvider.when("/blocked-project/:pslug/",
|
||||||
|
{
|
||||||
|
templateUrl: "projects/project/blocked-project.html",
|
||||||
|
loader: true,
|
||||||
|
controller: "Project",
|
||||||
|
controllerAs: "vm"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
$routeProvider.when("/project/:pslug/",
|
$routeProvider.when("/project/:pslug/",
|
||||||
{
|
{
|
||||||
templateUrl: "projects/project/project.html",
|
templateUrl: "projects/project/project.html",
|
||||||
|
@ -515,6 +525,42 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven
|
||||||
|
|
||||||
$httpProvider.interceptors.push("versionCheckHttpIntercept")
|
$httpProvider.interceptors.push("versionCheckHttpIntercept")
|
||||||
|
|
||||||
|
|
||||||
|
blockingIntercept = ($q, $routeParams, $location, $navUrls) ->
|
||||||
|
# API calls can return blocked elements and in that situation the user will be redirected
|
||||||
|
# to the blocked project page
|
||||||
|
# This can happens in two scenarios
|
||||||
|
# - An ok response containing a blocked_code in the data
|
||||||
|
# - An error reponse when updating/creating/deleting including a 451 error code
|
||||||
|
redirectToBlockedPage = ->
|
||||||
|
pslug = $routeParams.pslug
|
||||||
|
blockedUrl = $navUrls.resolve("blocked-project", {project: pslug})
|
||||||
|
currentUrl = $location.url()
|
||||||
|
if currentUrl.indexOf(blockedUrl) == -1
|
||||||
|
$location.replace().path(blockedUrl)
|
||||||
|
|
||||||
|
responseOk = (response) ->
|
||||||
|
if response.data.blocked_code
|
||||||
|
redirectToBlockedPage()
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
responseError = (response) ->
|
||||||
|
if response.status == 451
|
||||||
|
redirectToBlockedPage()
|
||||||
|
|
||||||
|
return $q.reject(response)
|
||||||
|
|
||||||
|
return {
|
||||||
|
response: responseOk
|
||||||
|
responseError: responseError
|
||||||
|
}
|
||||||
|
|
||||||
|
$provide.factory("blockingIntercept", ["$q", "$routeParams", "$location", "$tgNavUrls", blockingIntercept])
|
||||||
|
|
||||||
|
$httpProvider.interceptors.push("blockingIntercept")
|
||||||
|
|
||||||
|
|
||||||
$compileProvider.debugInfoEnabled(window.taigaConfig.debugInfo || false)
|
$compileProvider.debugInfoEnabled(window.taigaConfig.debugInfo || false)
|
||||||
|
|
||||||
if localStorage.userInfo
|
if localStorage.userInfo
|
||||||
|
|
|
@ -67,6 +67,7 @@ urls = {
|
||||||
"profile": "/profile"
|
"profile": "/profile"
|
||||||
"user-profile": "/profile/:username"
|
"user-profile": "/profile/:username"
|
||||||
|
|
||||||
|
"blocked-project": "/blocked-project/:project"
|
||||||
"project": "/project/:project"
|
"project": "/project/:project"
|
||||||
"project-backlog": "/project/:project/backlog"
|
"project-backlog": "/project/:project/backlog"
|
||||||
"project-taskboard": "/project/:project/taskboard/:sprint"
|
"project-taskboard": "/project/:project/taskboard/:sprint"
|
||||||
|
|
|
@ -740,6 +740,11 @@
|
||||||
"FANS_COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}",
|
"FANS_COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}",
|
||||||
"WATCHERS_COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}",
|
"WATCHERS_COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}",
|
||||||
"MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}",
|
"MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}",
|
||||||
|
"BLOCKED_PROJECT": {
|
||||||
|
"BLOCKED": "Blocked project",
|
||||||
|
"THIS_PROJECT_IS_BLOCKED": "This project is temporarily blocked",
|
||||||
|
"TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "To unblock your projects you must contact with the admin staff"
|
||||||
|
},
|
||||||
"STATS": {
|
"STATS": {
|
||||||
"PROJECT": "project<br/> points",
|
"PROJECT": "project<br/> points",
|
||||||
"DEFINED": "defined<br/> points",
|
"DEFINED": "defined<br/> points",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
a.list-itemtype-ticket(
|
a.list-itemtype-ticket(
|
||||||
href="{{ ::vm.duty.get('url') }}"
|
href="{{ ::vm.duty.get('url') }}"
|
||||||
title="{{ ::duty.get('subject') }}"
|
title="{{ ::duty.get('subject') }}"
|
||||||
ng-class="{'blocked': vm.duty.get('is_blocked')}"
|
ng-class="{'blocked': vm.duty.get('is_blocked'), 'blocked-project': vm.duty.get('blockedProject')}"
|
||||||
)
|
)
|
||||||
div.list-itemtype-avatar(ng-if="::vm.duty.get('assigned_to_extra_info')")
|
div.list-itemtype-avatar(ng-if="::vm.duty.get('assigned_to_extra_info')")
|
||||||
img(
|
img(
|
||||||
|
@ -16,8 +16,12 @@ a.list-itemtype-ticket(
|
||||||
div.list-itemtype-ticket-data
|
div.list-itemtype-ticket-data
|
||||||
p
|
p
|
||||||
span.ticket-project {{ ::vm.duty.get('projectName')}}
|
span.ticket-project {{ ::vm.duty.get('projectName')}}
|
||||||
|
|
||||||
span.ticket-type {{ ::vm.getDutyType() }}
|
span.ticket-type {{ ::vm.getDutyType() }}
|
||||||
span.ticket-status(ng-style="{'color': vm.duty.get('status_extra_info').get('color')}") {{ ::vm.duty.get('status_extra_info').get('name') }}
|
span.ticket-status(ng-style="{'color': vm.duty.get('status_extra_info').get('color')}") {{ ::vm.duty.get('status_extra_info').get('name') }}
|
||||||
|
svg.icon.icon-blocked-project(ng-if="vm.duty.get('blockedProject')")
|
||||||
|
use(xlink:href="#icon-blocked-project")
|
||||||
|
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
|
||||||
|
|
||||||
h2
|
h2
|
||||||
span.ticket-id(tg-bo-ref="duty.get('ref')")
|
span.ticket-id(tg-bo-ref="duty.get('ref')")
|
||||||
|
|
|
@ -41,6 +41,7 @@ class HomeService extends taiga.Service
|
||||||
|
|
||||||
duty = duty.set('url', url)
|
duty = duty.set('url', url)
|
||||||
duty = duty.set('projectName', project.get('name'))
|
duty = duty.set('projectName', project.get('name'))
|
||||||
|
duty = duty.set('blockedProject', project.get('blocked_code'))
|
||||||
duty = duty.set("_name", objType)
|
duty = duty.set("_name", objType)
|
||||||
|
|
||||||
return duty
|
return duty
|
||||||
|
|
|
@ -128,6 +128,7 @@ describe "tgHome", ->
|
||||||
project: '1',
|
project: '1',
|
||||||
url: '/testing-project/us/1',
|
url: '/testing-project/us/1',
|
||||||
projectName: 'fake1',
|
projectName: 'fake1',
|
||||||
|
blockedProject: undefined,
|
||||||
_name: 'userstories'
|
_name: 'userstories'
|
||||||
}]
|
}]
|
||||||
tasks: [{
|
tasks: [{
|
||||||
|
@ -136,6 +137,7 @@ describe "tgHome", ->
|
||||||
project: '1',
|
project: '1',
|
||||||
url: '/testing-project/tasks/1',
|
url: '/testing-project/tasks/1',
|
||||||
projectName: 'fake1',
|
projectName: 'fake1',
|
||||||
|
blockedProject: undefined,
|
||||||
_name: 'tasks'
|
_name: 'tasks'
|
||||||
}]
|
}]
|
||||||
issues: [{
|
issues: [{
|
||||||
|
@ -144,6 +146,7 @@ describe "tgHome", ->
|
||||||
project: '1',
|
project: '1',
|
||||||
url: '/testing-project/issues/1',
|
url: '/testing-project/issues/1',
|
||||||
projectName: 'fake1',
|
projectName: 'fake1',
|
||||||
|
blockedProject: undefined,
|
||||||
_name: 'issues'
|
_name: 'issues'
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -154,6 +157,7 @@ describe "tgHome", ->
|
||||||
project: '1',
|
project: '1',
|
||||||
url: '/testing-project/us/1',
|
url: '/testing-project/us/1',
|
||||||
projectName: 'fake1',
|
projectName: 'fake1',
|
||||||
|
blockedProject: undefined,
|
||||||
_name: 'userstories'
|
_name: 'userstories'
|
||||||
}]
|
}]
|
||||||
tasks: [{
|
tasks: [{
|
||||||
|
@ -162,6 +166,7 @@ describe "tgHome", ->
|
||||||
project: '1',
|
project: '1',
|
||||||
url: '/testing-project/tasks/1',
|
url: '/testing-project/tasks/1',
|
||||||
projectName: 'fake1',
|
projectName: 'fake1',
|
||||||
|
blockedProject: undefined,
|
||||||
_name: 'tasks'
|
_name: 'tasks'
|
||||||
}]
|
}]
|
||||||
issues: [{
|
issues: [{
|
||||||
|
@ -170,6 +175,7 @@ describe "tgHome", ->
|
||||||
project: '1',
|
project: '1',
|
||||||
url: '/testing-project/issues/1',
|
url: '/testing-project/issues/1',
|
||||||
projectName: 'fake1',
|
projectName: 'fake1',
|
||||||
|
blockedProject: undefined,
|
||||||
_name: 'issues'
|
_name: 'issues'
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
section.home-project-list(ng-if="vm.projects.size")
|
section.home-project-list(ng-if="vm.projects.size")
|
||||||
|
|
||||||
.home-project(tg-bind-scope, tg-repeat="project in vm.projects")
|
.home-project(
|
||||||
|
tg-bind-scope
|
||||||
|
tg-repeat="project in vm.projects"
|
||||||
|
ng-class="{'blocked-project': project.get('blocked_code')}"
|
||||||
|
)
|
||||||
.tags-container
|
.tags-container
|
||||||
.project-tag(
|
.project-tag(
|
||||||
style="background: {{tag.get('color')}}"
|
style="background: {{tag.get('color')}}"
|
||||||
|
@ -19,7 +23,7 @@ section.home-project-list(ng-if="vm.projects.size")
|
||||||
alt="{{::project.get('name')}}"
|
alt="{{::project.get('name')}}"
|
||||||
)
|
)
|
||||||
h2.project-card-name
|
h2.project-card-name
|
||||||
a(
|
a.project-title(
|
||||||
href="#"
|
href="#"
|
||||||
tg-nav="project:project=project.get('slug')"
|
tg-nav="project:project=project.get('slug')"
|
||||||
title="{{::project.get('name')}}"
|
title="{{::project.get('name')}}"
|
||||||
|
@ -27,6 +31,10 @@ section.home-project-list(ng-if="vm.projects.size")
|
||||||
svg.look-for-people.icon.icon-recruit(ng-if="project.get('is_looking_for_people')")
|
svg.look-for-people.icon.icon-recruit(ng-if="project.get('is_looking_for_people')")
|
||||||
use(xlink:href="#icon-recruit")
|
use(xlink:href="#icon-recruit")
|
||||||
title="{{ ::project.get('looking_for_people_note') }}"
|
title="{{ ::project.get('looking_for_people_note') }}"
|
||||||
|
svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')")
|
||||||
|
use(xlink:href="#icon-blocked-project")
|
||||||
|
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
|
||||||
|
|
||||||
p.project-card-description {{::project.get('description')| limitTo:100 }}
|
p.project-card-description {{::project.get('description')| limitTo:100 }}
|
||||||
span(ng-if="::project.get('description').length > 100") ...
|
span(ng-if="::project.get('description').length > 100") ...
|
||||||
.project-card-statistics
|
.project-card-statistics
|
||||||
|
|
|
@ -9,6 +9,20 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
border: 1px solid $primary-light;
|
border: 1px solid $primary-light;
|
||||||
}
|
}
|
||||||
|
&.blocked-project {
|
||||||
|
border: $whitish;
|
||||||
|
&:hover {
|
||||||
|
border: $whitish;
|
||||||
|
}
|
||||||
|
.tags-container,
|
||||||
|
.project-card-logo,
|
||||||
|
.project-card-name a,
|
||||||
|
.icon-recruit,
|
||||||
|
.project-card-description,
|
||||||
|
.project-card-statistics {
|
||||||
|
opacity: .3;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.projects-empty {
|
.projects-empty {
|
||||||
|
|
|
@ -20,7 +20,11 @@ section.watching-container
|
||||||
.title-bar.watching-title(translate="HOME.WATCHING_SECTION")
|
.title-bar.watching-title(translate="HOME.WATCHING_SECTION")
|
||||||
|
|
||||||
.watching(ng-if="vm.watching.size")
|
.watching(ng-if="vm.watching.size")
|
||||||
.duty-single(tg-duty="duty", tg-repeat="duty in vm.watching", ng-class="{'blocked': duty.is_blocked}")
|
.duty-single(
|
||||||
|
tg-duty="duty"
|
||||||
|
tg-repeat="duty in vm.watching"
|
||||||
|
ng-class="{'blocked': duty.is_blocked}"
|
||||||
|
)
|
||||||
|
|
||||||
.watching-empty(ng-if="vm.watching != undefined && vm.watching.size === 0")
|
.watching-empty(ng-if="vm.watching != undefined && vm.watching.size === 0")
|
||||||
p(translate="HOME.EMPTY_WATCHING")
|
p(translate="HOME.EMPTY_WATCHING")
|
||||||
|
|
|
@ -5,7 +5,15 @@ a(href="", title="Projects", tg-nav="projects")
|
||||||
div.navbar-dropdown.dropdown-project-list
|
div.navbar-dropdown.dropdown-project-list
|
||||||
ul
|
ul
|
||||||
li(tg-repeat="project in vm.projects track by project.get('id')")
|
li(tg-repeat="project in vm.projects track by project.get('id')")
|
||||||
a(href="#", tg-nav="project:project=project.get('slug')") {{::project.get("name")}}
|
a(
|
||||||
|
href="#"
|
||||||
|
tg-nav="project:project=project.get('slug')"
|
||||||
|
ng-class="{'blocked-project': project.get('blocked_code')}"
|
||||||
|
)
|
||||||
|
span {{::project.get("name")}}
|
||||||
|
svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')")
|
||||||
|
use(xlink:href="#icon-blocked-project")
|
||||||
|
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
|
||||||
|
|
||||||
a.see-more-projects-btn.button-gray(
|
a.see-more-projects-btn.button-gray(
|
||||||
href="#",
|
href="#",
|
||||||
|
|
|
@ -173,6 +173,14 @@ $dropdown-width: 350px;
|
||||||
&.create-project-btn {
|
&.create-project-btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
&.blocked-project {
|
||||||
|
color: $gray;
|
||||||
|
svg {
|
||||||
|
margin-left: .5rem;
|
||||||
|
position: relative;
|
||||||
|
top: .25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.import-project-button {
|
.import-project-button {
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
.list-itemtype-project
|
.list-itemtype-project(ng-class="{'blocked-project': vm.item.get('project_blocked_code')}")
|
||||||
.list-itemtype-project-left
|
.list-itemtype-project-left
|
||||||
.list-itemtype-project-data-wrapper
|
.list-itemtype-project-data-wrapper
|
||||||
|
|
||||||
a.list-itemtype-project-image(
|
a.list-itemtype-project-image(
|
||||||
href="#"
|
href="#"
|
||||||
tg-nav="project:project=vm.item.get('slug')"
|
tg-nav="project:project=vm.item.get('slug')"
|
||||||
|
@ -14,20 +13,21 @@
|
||||||
|
|
||||||
.list-itemtype-project-data
|
.list-itemtype-project-data
|
||||||
h2
|
h2
|
||||||
a(
|
a.list-itemtype-project-name(
|
||||||
href="#"
|
href="#"
|
||||||
tg-nav="project:project=vm.item.get('slug')"
|
tg-nav="project:project=vm.item.get('slug')"
|
||||||
title="{{ ::vm.item.get('name') }}"
|
title="{{ ::vm.item.get('name') }}"
|
||||||
) {{ ::vm.item.get('name') }}
|
) {{ ::vm.item.get('name') }}
|
||||||
span.private(ng-if="::project.get('is_private')", title="{{'PROJECT.PRIVATE' | translate}}")
|
span.private(
|
||||||
p {{ ::vm.item.get('description') }}
|
ng-if="::vm.item.get('project_is_private')"
|
||||||
|
title="{{'PROJECT.PRIVATE' | translate}}"
|
||||||
.list-itemtype-project-tags.tags-container(ng-if="::vm.item.get('tags_colors').size")
|
|
||||||
span.tag(
|
|
||||||
tg-repeat="tag in ::vm.item.get('tags_colors')"
|
|
||||||
style='border-left: 5px solid {{ ::tag.get("color") }};'
|
|
||||||
)
|
)
|
||||||
span.tag-name {{ ::tag.get('name') }}
|
svg.icon.icon-lock
|
||||||
|
use(xlink:href="#icon-lock")
|
||||||
|
svg.icon.icon-blocked-project(ng-if="vm.item.get('project_blocked_code')")
|
||||||
|
use(xlink:href="#icon-blocked-project")
|
||||||
|
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
|
||||||
|
p.list-itemtype-project-description {{ ::vm.item.get('description') }}
|
||||||
|
|
||||||
.list-itemtype-track
|
.list-itemtype-track
|
||||||
span.list-itemtype-track-likers(
|
span.list-itemtype-track-likers(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
div.list-itemtype-ticket
|
div.list-itemtype-ticket(ng-class="{'blocked-project': vm.item.get('project_blocked_code')}")
|
||||||
a.list-itemtype-avatar(
|
a.list-itemtype-avatar(
|
||||||
href=""
|
href=""
|
||||||
ng-if="::vm.item.get('assigned_to')"
|
ng-if="::vm.item.get('assigned_to')"
|
||||||
|
@ -38,6 +38,9 @@ div.list-itemtype-ticket
|
||||||
)
|
)
|
||||||
span.ticket-status(ng-style="::{'color': vm.item.get('status_color')}")
|
span.ticket-status(ng-style="::{'color': vm.item.get('status_color')}")
|
||||||
| {{:: vm.item.get('status') }}
|
| {{:: vm.item.get('status') }}
|
||||||
|
svg.icon.icon-blocked-project(ng-if="vm.item.get('project_blocked_code')")
|
||||||
|
use(xlink:href="#icon-blocked-project")
|
||||||
|
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
|
||||||
h2
|
h2
|
||||||
span.ticket-id(tg-bo-ref="vm.item.get('ref')")
|
span.ticket-id(tg-bo-ref="vm.item.get('ref')")
|
||||||
a.ticket-title(
|
a.ticket-title(
|
||||||
|
@ -45,22 +48,19 @@ div.list-itemtype-ticket
|
||||||
ng-if="::vm.item.get('type') === 'userstory'"
|
ng-if="::vm.item.get('type') === 'userstory'"
|
||||||
tg-nav="project-userstories-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')"
|
tg-nav="project-userstories-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')"
|
||||||
title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}"
|
title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}"
|
||||||
)
|
) {{ ::vm.item.get('subject') }}
|
||||||
| {{ ::vm.item.get('subject') }}
|
|
||||||
a.ticket-title(
|
a.ticket-title(
|
||||||
href="#"
|
href="#"
|
||||||
ng-if="::vm.item.get('type') === 'task'"
|
ng-if="::vm.item.get('type') === 'task'"
|
||||||
tg-nav="project-tasks-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')"
|
tg-nav="project-tasks-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')"
|
||||||
title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}"
|
title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}"
|
||||||
)
|
) {{ ::vm.item.get('subject') }}
|
||||||
| {{ ::vm.item.get('subject') }}
|
|
||||||
a.ticket-title(
|
a.ticket-title(
|
||||||
href="#"
|
href="#"
|
||||||
ng-if="::vm.item.get('type') === 'issue'"
|
ng-if="::vm.item.get('type') === 'issue'"
|
||||||
tg-nav="project-issues-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')"
|
tg-nav="project-issues-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')"
|
||||||
title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}"
|
title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}"
|
||||||
)
|
) {{ ::vm.item.get('subject') }}
|
||||||
| {{ ::vm.item.get('subject') }}
|
|
||||||
|
|
||||||
div.list-itemtype-track
|
div.list-itemtype-track
|
||||||
span.list-itemtype-track-likers(
|
span.list-itemtype-track-likers(
|
||||||
|
|
|
@ -184,4 +184,3 @@ class ProfileWatchedController extends FavsBaseController
|
||||||
|
|
||||||
angular.module("taigaProfile")
|
angular.module("taigaProfile")
|
||||||
.controller("ProfileWatched", ProfileWatchedController)
|
.controller("ProfileWatched", ProfileWatchedController)
|
||||||
|
|
||||||
|
|
|
@ -60,10 +60,26 @@ section.profile-favs
|
||||||
tg-repeat="item in vm.items track by $index"
|
tg-repeat="item in vm.items track by $index"
|
||||||
ng-switch="item.get('type')"
|
ng-switch="item.get('type')"
|
||||||
)
|
)
|
||||||
div(ng-switch-when="project", tg-fav-item="item", item-type="project")
|
div(
|
||||||
div(ng-switch-when="userstory", tg-fav-item="item", item-type="userstory")
|
ng-switch-when="project"
|
||||||
div(ng-switch-when="task", tg-fav-item="item", item-type="task")
|
tg-fav-item="item"
|
||||||
div(ng-switch-when="issue", tg-fav-item="item", item-type="issue")
|
item-type="project"
|
||||||
|
)
|
||||||
|
div(
|
||||||
|
ng-switch-when="userstory"
|
||||||
|
tg-fav-item="item"
|
||||||
|
item-type="userstory"
|
||||||
|
)
|
||||||
|
div(
|
||||||
|
ng-switch-when="task"
|
||||||
|
tg-fav-item="item"
|
||||||
|
item-type="task"
|
||||||
|
)
|
||||||
|
div(
|
||||||
|
ng-switch-when="issue"
|
||||||
|
tg-fav-item="item"
|
||||||
|
item-type="issue"
|
||||||
|
)
|
||||||
|
|
||||||
div(ng-if="vm.isLoading")
|
div(ng-if="vm.isLoading")
|
||||||
div.spin
|
div.spin
|
||||||
|
|
|
@ -11,8 +11,10 @@ section.profile-projects
|
||||||
translate="USER.PROFILE.PROJECTS_EMPTY"
|
translate="USER.PROFILE.PROJECTS_EMPTY"
|
||||||
translate-values="{username: vm.user.get('full_name_display')}"
|
translate-values="{username: vm.user.get('full_name_display')}"
|
||||||
)
|
)
|
||||||
|
.list-itemtype-project(
|
||||||
.list-itemtype-project(tg-repeat="project in vm.projects")
|
tg-repeat="project in vm.projects"
|
||||||
|
ng-class="{'blocked-project': project.get('blocked_code')}"
|
||||||
|
)
|
||||||
.list-itemtype-project-left
|
.list-itemtype-project-left
|
||||||
.project-list-single-title-wrapper
|
.project-list-single-title-wrapper
|
||||||
a.list-itemtype-project-image(
|
a.list-itemtype-project-image(
|
||||||
|
@ -26,19 +28,15 @@ section.profile-projects
|
||||||
)
|
)
|
||||||
.project-list-single-title
|
.project-list-single-title
|
||||||
h2
|
h2
|
||||||
a(
|
a.project-title(
|
||||||
href="#"
|
href="#"
|
||||||
tg-nav="project:project=project.get('slug')"
|
tg-nav="project:project=project.get('slug')"
|
||||||
title="{{ ::project.get('name') }}"
|
title="{{ ::project.get('name') }}"
|
||||||
) {{::project.get('name')}}
|
) {{::project.get('name')}}
|
||||||
p {{ ::project.get('description') | limitTo:300 }}
|
svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')")
|
||||||
|
use(xlink:href="#icon-blocked-project")
|
||||||
.list-itemtype-project-tags.tags-container(ng-if="::project.get('tags').size")
|
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
|
||||||
span.tag(
|
p.project-description {{ ::project.get('description') | limitTo:300 }}
|
||||||
style='border-left: 5px solid {{::tag.get("color")}};'
|
|
||||||
tg-repeat="tag in ::project.get('colorized_tags')"
|
|
||||||
)
|
|
||||||
span.tag-name {{::tag.get('name')}}
|
|
||||||
|
|
||||||
.list-itemtype-project-right
|
.list-itemtype-project-right
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
.timeline-wrapper {
|
.timeline-wrapper {
|
||||||
background: lighten($whitish, 10%);
|
|
||||||
margin-right: 3.5rem;
|
margin-right: 3.5rem;
|
||||||
width: 768px;
|
width: 768px;
|
||||||
> div {
|
> div {
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
###
|
||||||
|
# Copyright (C) 2014-2016 Taiga Agile LLC <taiga@taiga.io>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# File: blocked-project-explanation.directive.coffee
|
||||||
|
###
|
||||||
|
|
||||||
|
BlockedProjectExplanationDirective = () ->
|
||||||
|
return {
|
||||||
|
templateUrl: "projects/project/blocked-project-explanation.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
angular.module("taigaProjects").directive("tgBlockedProjectExplanation", BlockedProjectExplanationDirective)
|
|
@ -23,6 +23,7 @@
|
||||||
li.list-itemtype-project(
|
li.list-itemtype-project(
|
||||||
tg-bind-scope
|
tg-bind-scope
|
||||||
tg-repeat="project in vm.projects track by project.get('id')"
|
tg-repeat="project in vm.projects track by project.get('id')"
|
||||||
|
ng-class="{'blocked-project': project.get('blocked_code')}"
|
||||||
)
|
)
|
||||||
.list-itemtype-project-left
|
.list-itemtype-project-left
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
)
|
)
|
||||||
.list-itemtype-project-data
|
.list-itemtype-project-data
|
||||||
h2
|
h2
|
||||||
a(
|
a.project-title(
|
||||||
href="#"
|
href="#"
|
||||||
tg-nav="project:project=project.get('slug')"
|
tg-nav="project:project=project.get('slug')"
|
||||||
title="{{ ::project.get('name') }}"
|
title="{{ ::project.get('name') }}"
|
||||||
|
@ -53,9 +54,12 @@
|
||||||
svg.icon.icon-badge(ng-if="project.get('i_am_owner')")
|
svg.icon.icon-badge(ng-if="project.get('i_am_owner')")
|
||||||
use(xlink:href="#icon-badge")
|
use(xlink:href="#icon-badge")
|
||||||
title(translate="COMMON.OWNER")
|
title(translate="COMMON.OWNER")
|
||||||
|
svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')")
|
||||||
|
use(xlink:href="#icon-blocked-project")
|
||||||
|
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
|
||||||
|
|
||||||
|
|
||||||
p {{ ::project.get('description') | limitTo:300 }}
|
p.project-description {{ ::project.get('description') | limitTo:300 }}
|
||||||
span(ng-if="::project.get('description').length > 300") ...
|
span(ng-if="::project.get('description').length > 300") ...
|
||||||
|
|
||||||
svg.drag.icon.icon-drag
|
svg.drag.icon.icon-drag
|
||||||
|
|
|
@ -3,7 +3,16 @@
|
||||||
.list-itemtype-project {
|
.list-itemtype-project {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
min-height: 10rem;
|
min-height: 9rem;
|
||||||
|
padding: .75rem;
|
||||||
|
&.blocked-project {
|
||||||
|
.list-itemtype-project-image,
|
||||||
|
.project-title,
|
||||||
|
.project-description,
|
||||||
|
.list-itemtype-project-right {
|
||||||
|
opacity: .4;
|
||||||
|
}
|
||||||
|
}
|
||||||
.project-list-single-title-wrapper {
|
.project-list-single-title-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +23,11 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
justify-content: space-between;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
.icon-blocked-project {
|
||||||
|
@include svg-size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.icon-lock,
|
.icon-lock,
|
||||||
.icon-badge {
|
.icon-badge,
|
||||||
|
.icon-blocked-project {
|
||||||
@include svg-size();
|
@include svg-size();
|
||||||
}
|
}
|
||||||
.icon-badge {
|
.icon-badge {
|
||||||
|
@ -62,6 +63,16 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.blocked-project {
|
||||||
|
.list-itemtype-project-image,
|
||||||
|
.project-title,
|
||||||
|
.private,
|
||||||
|
.project-description,
|
||||||
|
.icon-badge,
|
||||||
|
.icon-drag {
|
||||||
|
opacity: .25;
|
||||||
|
}
|
||||||
|
}
|
||||||
.list-itemtype-project-data-wrapper {
|
.list-itemtype-project-data-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
div(ng-if="!vm.project.get('i_am_owner')")
|
||||||
|
div {{'PROJECT.BLOCKED_PROJECT.THIS_PROJECT_IS_BLOCKED' | translate}}
|
||||||
|
|
||||||
|
div(ng-if="vm.project.get('i_am_owner')")
|
||||||
|
div {{'PROJECT.BLOCKED_PROJECT.TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF' | translate}}
|
|
@ -0,0 +1,15 @@
|
||||||
|
.blocked-project-detail
|
||||||
|
.blocked-project-inner
|
||||||
|
.blocked-project-title
|
||||||
|
.project-image
|
||||||
|
img(
|
||||||
|
tg-project-logo-small-src="vm.project"
|
||||||
|
alt="{{::vm.project.get('name')}}"
|
||||||
|
)
|
||||||
|
svg.icon.icon-blocked-project
|
||||||
|
use(xlink:href="#icon-blocked-project")
|
||||||
|
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
|
||||||
|
span.project-title {{::vm.project.get("name")}}
|
||||||
|
.blocked-project-message
|
||||||
|
h1.project-block-title {{'PROJECT.BLOCKED_PROJECT.BLOCKED' | translate}}
|
||||||
|
tg-blocked-project-explanation.project-block-message
|
|
@ -0,0 +1,42 @@
|
||||||
|
.blocked-project-detail {
|
||||||
|
align-items: center;
|
||||||
|
background: url('../images/discover.png') bottom center repeat-x;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: calc(100vh - 40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.blocked-project-inner {
|
||||||
|
width: 330px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blocked-project-title {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
.project-image {
|
||||||
|
flex-basis: 6rem;
|
||||||
|
margin-right: 1rem;
|
||||||
|
max-width: 6rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.icon-blocked-project {
|
||||||
|
@include svg-size(1.5rem);
|
||||||
|
position: absolute;
|
||||||
|
right: -.5rem;
|
||||||
|
top: -.5rem;
|
||||||
|
}
|
||||||
|
.project-title {
|
||||||
|
@extend %larger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blocked-project-message {
|
||||||
|
margin-top: 4rem;
|
||||||
|
text-align: center;
|
||||||
|
.project-block-title {
|
||||||
|
@extend %xlarge;
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,9 +32,21 @@
|
||||||
.list-itemtype-project {
|
.list-itemtype-project {
|
||||||
@include list-itemtype-common;
|
@include list-itemtype-common;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
&.blocked-project {
|
||||||
|
.list-itemtype-track,
|
||||||
|
.list-itemtype-project-image,
|
||||||
|
.list-itemtype-project-name,
|
||||||
|
.list-itemtype-project-description,
|
||||||
|
.list-itemtype-project-private {
|
||||||
|
opacity: .4;
|
||||||
|
}
|
||||||
|
}
|
||||||
h2 {
|
h2 {
|
||||||
@extend %large;
|
@extend %large;
|
||||||
}
|
}
|
||||||
|
.icon-blocked-project {
|
||||||
|
@include svg-size();
|
||||||
|
}
|
||||||
.list-itemtype-project-data-wrapper {
|
.list-itemtype-project-data-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
@ -75,6 +87,20 @@
|
||||||
|
|
||||||
.list-itemtype-ticket {
|
.list-itemtype-ticket {
|
||||||
@include list-itemtype-common;
|
@include list-itemtype-common;
|
||||||
|
position: relative;
|
||||||
|
&.blocked-project {
|
||||||
|
.ticket-project,
|
||||||
|
.ticket-type,
|
||||||
|
.ticket-status,
|
||||||
|
.list-itemtype-avatar,
|
||||||
|
.list-itemtype-track,
|
||||||
|
.ticket-title {
|
||||||
|
opacity: .4;
|
||||||
|
}
|
||||||
|
.icon-blocked-project {
|
||||||
|
@include svg-size();
|
||||||
|
}
|
||||||
|
}
|
||||||
h2 {
|
h2 {
|
||||||
@extend %medium;
|
@extend %medium;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +123,6 @@
|
||||||
color: $red;
|
color: $red;
|
||||||
margin-left: .3rem;
|
margin-left: .3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -418,5 +418,12 @@
|
||||||
<path
|
<path
|
||||||
d="M165 91.5c-33 0-60 28.7-60 64 0 35.2 27 64 60 64s60-28.8 60-64c0-35.3-27-64-60-64zm0 16.2c24.8 0 44.8 21.3 44.8 47.8 0 26.5-20 47.8-44.8 47.8-25 0-45-21.3-45-47.8 0-26.5 20-47.8 45-47.8zm-77.8 13.5c-29.2 0-53 25.5-53 56.7 0 31 23.8 56.5 53 56.5 16 0 27.5-4.5 37.3-16.6-21.8-9.7-34-36-34-62.5 0-12 3-23.3 8.5-33-3.8-.8-7.7-1.3-11.8-1.3zM165 229.7c-53.3 0-95.8 50.8-96 112.5v8h192v-8c-.2-61.7-42.8-112.5-96-112.5zm-78.7 13.6c-3.4 0-5.8.3-5.8.3-47.2 0-78 45-78.3 99.5v7.3h52.2v-8c0-41.3 15.2-78.6 43.7-98.2-3.8-.6-8.2-.8-11.7-.7zM165 246c42 0 76.8 38.2 80.5 88h-161c3.6-49.8 38.6-88 80.5-88zM339.3 49.7C307 49.7 281 76 281 108.2c0 32.2 26 58.4 58.3 58.4s58.5-26.2 58.5-58.4c0-32.3-26.2-58.5-58.5-58.5zm0 7.3c28.3 0 51.2 23 51.2 51.2 0 28.3-23 51-51.2 51-28.3 0-51-22.7-51-51S311 57 339.2 57zm-.2 11.8c-7 0-14 1.7-20.5 5l3 7c3.5-1.6 6.5-2.7 9-3.3 2.7-.7 5.4-1 8-1 4.4 0 7.6 1 10 3 2.2 1.8 3.3 4.5 3.3 8 0 3-.6 5.4-1.8 7.4-1.2 2-4.2 5-9 9-3.3 2.8-5.7 5.6-7 8.2-1.2 2.6-1.8 6-1.8 10v2.8h6.7v-1.7c0-3.3.5-6 1.6-8 1-2 3.5-4.4 7-7.3 4.4-4 7.2-6.6 8.5-8.3 1.4-1.8 2.4-3.6 3-5.5.8-2 1-4.2 1-6.7 0-6-1.7-10.6-5.4-13.8-3.7-3.3-8.8-5-15.5-5zm-6.8 62.5V148h7.3v-16.7h-7.3z"></path>
|
d="M165 91.5c-33 0-60 28.7-60 64 0 35.2 27 64 60 64s60-28.8 60-64c0-35.3-27-64-60-64zm0 16.2c24.8 0 44.8 21.3 44.8 47.8 0 26.5-20 47.8-44.8 47.8-25 0-45-21.3-45-47.8 0-26.5 20-47.8 45-47.8zm-77.8 13.5c-29.2 0-53 25.5-53 56.7 0 31 23.8 56.5 53 56.5 16 0 27.5-4.5 37.3-16.6-21.8-9.7-34-36-34-62.5 0-12 3-23.3 8.5-33-3.8-.8-7.7-1.3-11.8-1.3zM165 229.7c-53.3 0-95.8 50.8-96 112.5v8h192v-8c-.2-61.7-42.8-112.5-96-112.5zm-78.7 13.6c-3.4 0-5.8.3-5.8.3-47.2 0-78 45-78.3 99.5v7.3h52.2v-8c0-41.3 15.2-78.6 43.7-98.2-3.8-.6-8.2-.8-11.7-.7zM165 246c42 0 76.8 38.2 80.5 88h-161c3.6-49.8 38.6-88 80.5-88zM339.3 49.7C307 49.7 281 76 281 108.2c0 32.2 26 58.4 58.3 58.4s58.5-26.2 58.5-58.4c0-32.3-26.2-58.5-58.5-58.5zm0 7.3c28.3 0 51.2 23 51.2 51.2 0 28.3-23 51-51.2 51-28.3 0-51-22.7-51-51S311 57 339.2 57zm-.2 11.8c-7 0-14 1.7-20.5 5l3 7c3.5-1.6 6.5-2.7 9-3.3 2.7-.7 5.4-1 8-1 4.4 0 7.6 1 10 3 2.2 1.8 3.3 4.5 3.3 8 0 3-.6 5.4-1.8 7.4-1.2 2-4.2 5-9 9-3.3 2.8-5.7 5.6-7 8.2-1.2 2.6-1.8 6-1.8 10v2.8h6.7v-1.7c0-3.3.5-6 1.6-8 1-2 3.5-4.4 7-7.3 4.4-4 7.2-6.6 8.5-8.3 1.4-1.8 2.4-3.6 3-5.5.8-2 1-4.2 1-6.7 0-6-1.7-10.6-5.4-13.8-3.7-3.3-8.8-5-15.5-5zm-6.8 62.5V148h7.3v-16.7h-7.3z"></path>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
<symbol id="icon-blocked-project" viewBox="0 0 1024 1024">
|
||||||
|
<title>Blocked Project</title>
|
||||||
|
<path fill="#ff8282" d="M1017.075 512c0 278.946-226.13 505.076-505.076 505.076s-505.076-226.13-505.076-505.076c0-278.946 226.13-505.076 505.076-505.076s505.076 226.13 505.076 505.076z"></path>
|
||||||
|
<path
|
||||||
|
fill="#fff"
|
||||||
|
d="M511.998 107.939c-222.856 0-404.061 181.204-404.061 404.061s181.205 404.061 404.061 404.061c222.856 0 404.061-181.203 404.061-404.061s-181.205-404.061-404.061-404.061zM511.998 158.447c88.671 0 169.621 32.484 231.616 86.222l-498.947 498.948c-53.74-61.998-86.223-142.945-86.223-231.617 0-195.561 157.992-353.553 353.553-353.553zM779.328 280.383c53.74 61.998 86.223 142.945 86.223 231.617 0 195.561-157.992 353.553-353.553 353.553-88.671 0-169.617-32.484-231.616-86.222l498.947-498.948z"></path>
|
||||||
|
</symbol>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
@ -138,4 +138,11 @@ describe('project home', function() {
|
||||||
expect(watchCounter).to.be.equal(watchCounterOld + 1);
|
expect(watchCounter).to.be.equal(watchCounterOld + 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('blocked project', async function() {
|
||||||
|
browser.get(browser.params.glob.host + 'project/project-6/');
|
||||||
|
await utils.common.waitLoader();
|
||||||
|
await utils.common.takeScreenshot("project", "blocked-project");
|
||||||
|
expect(browser.getCurrentUrl()).to.be.eventually.equal(browser.params.glob.host + 'blocked-project/project-6/');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue