Tribe integration in taiga
parent
e042449ca0
commit
563d69f91f
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- Show a confirmation notice when you exit edit mode by pressing ESC in the markdown inputs.
|
- Show a confirmation notice when you exit edit mode by pressing ESC in the markdown inputs.
|
||||||
|
- Add the tribe button to link stories from tree.taiga.io with gigs in tribe.taiga.io.
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
- Lots of small and not so small bugfixes.
|
- Lots of small and not so small bugfixes.
|
||||||
|
|
|
@ -3,6 +3,7 @@ window._version = "___VERSION___"
|
||||||
window.taigaConfig = {
|
window.taigaConfig = {
|
||||||
"api": "http://localhost:8000/api/v1/",
|
"api": "http://localhost:8000/api/v1/",
|
||||||
"eventsUrl": null,
|
"eventsUrl": null,
|
||||||
|
"tribeHost": null,
|
||||||
"eventsMaxMissedHeartbeats": 5,
|
"eventsMaxMissedHeartbeats": 5,
|
||||||
"eventsHeartbeatIntervalTime": 60000,
|
"eventsHeartbeatIntervalTime": 60000,
|
||||||
"debug": true,
|
"debug": true,
|
||||||
|
|
|
@ -50,15 +50,18 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
||||||
"$tgNavUrls",
|
"$tgNavUrls",
|
||||||
"$tgAnalytics",
|
"$tgAnalytics",
|
||||||
"$translate",
|
"$translate",
|
||||||
|
"$tgConfig",
|
||||||
"$tgQueueModelTransformation"
|
"$tgQueueModelTransformation"
|
||||||
]
|
]
|
||||||
|
|
||||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location,
|
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @log, @appMetaService,
|
||||||
@log, @appMetaService, @navUrls, @analytics, @translate, @modelTransform) ->
|
@navUrls, @analytics, @translate, @configService, @modelTransform) ->
|
||||||
bindMethods(@)
|
bindMethods(@)
|
||||||
|
|
||||||
@scope.usRef = @params.usref
|
@scope.usRef = @params.usref
|
||||||
@scope.sectionName = @translate.instant("US.SECTION_NAME")
|
@scope.sectionName = @translate.instant("US.SECTION_NAME")
|
||||||
|
@scope.tribeEnabled = @configService.config.tribeHost
|
||||||
|
|
||||||
@.initializeEventHandlers()
|
@.initializeEventHandlers()
|
||||||
|
|
||||||
promise = @.loadInitialData()
|
promise = @.loadInitialData()
|
||||||
|
@ -239,6 +242,17 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
||||||
|
|
||||||
return @rs.userstories.unwatch(@scope.usId).then(onSuccess, onError)
|
return @rs.userstories.unwatch(@scope.usId).then(onSuccess, onError)
|
||||||
|
|
||||||
|
onTribeInfo: ->
|
||||||
|
publishTitle = @translate.instant("US.TRIBE.PUBLISH_MORE_INFO_TITLE")
|
||||||
|
image = $('<img />')
|
||||||
|
.attr({
|
||||||
|
'src': "/#{window._version}/images/monster-fight.png",
|
||||||
|
'alt': @translate.instant("US.TRIBE.PUBLISH_MORE_INFO_TITLE")
|
||||||
|
})
|
||||||
|
text = @translate.instant("US.TRIBE.PUBLISH_MORE_INFO_TEXT")
|
||||||
|
publishDesc = $('<div></div>').append(image).append(text)
|
||||||
|
@confirm.success(publishTitle, publishDesc)
|
||||||
|
|
||||||
module.controller("UserStoryDetailController", UserStoryDetailController)
|
module.controller("UserStoryDetailController", UserStoryDetailController)
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
|
@ -993,6 +993,17 @@
|
||||||
"ASSIGN": "Assign User Story",
|
"ASSIGN": "Assign User Story",
|
||||||
"NOT_ESTIMATED": "Not estimated",
|
"NOT_ESTIMATED": "Not estimated",
|
||||||
"TOTAL_US_POINTS": "Total Us points",
|
"TOTAL_US_POINTS": "Total Us points",
|
||||||
|
"TRIBE": {
|
||||||
|
"PUBLISH": "Publish as Gig in Taiga Tribe",
|
||||||
|
"PUBLISH_INFO": "More info",
|
||||||
|
"PUBLISH_TITLE": "More info on publishing in Taiga Tribe",
|
||||||
|
"PUBLISHED_AS_GIG": "Story published as Gig in Taiga Tribe",
|
||||||
|
"EDIT_LINK": "Edit link",
|
||||||
|
"CLOSE": "Close",
|
||||||
|
"SYNCHRONIZE_LINK": "synchronize with Taiga Tribe",
|
||||||
|
"PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?",
|
||||||
|
"PUBLISH_MORE_INFO_TEXT": "<p>If you need help with a particular piece of work you can easily create gigs on<a href='taigatribe.com' title='Taiga Tribe'> Taiga Tribe </a> and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.</p><p><a href='taigatribe.com' title='Taiga Tribe'> TaigaTribe </a> was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.</p>"
|
||||||
|
},
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
"TEAM_REQUIREMENT": "Team Requirement",
|
"TEAM_REQUIREMENT": "Team Requirement",
|
||||||
"CLIENT_REQUIREMENT": "Client Requirement",
|
"CLIENT_REQUIREMENT": "Client Requirement",
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
###
|
||||||
|
# Copyright (C) 2014-2015 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: tribe-button.directive.coffee
|
||||||
|
###
|
||||||
|
|
||||||
|
TribeButtonDirective = (configService) ->
|
||||||
|
link = (scope, el, attrs) ->
|
||||||
|
|
||||||
|
scope.vm = {}
|
||||||
|
scope.vm.tribeHost = configService.config.tribeHost
|
||||||
|
|
||||||
|
return {
|
||||||
|
scope: {usId: "=", projectSlug: "="}
|
||||||
|
controllerAs: "vm",
|
||||||
|
templateUrl: "components/tribe-button/tribe-button.html",
|
||||||
|
link: link
|
||||||
|
}
|
||||||
|
|
||||||
|
TribeButtonDirective.$inject = [
|
||||||
|
"$tgConfig"
|
||||||
|
]
|
||||||
|
|
||||||
|
angular.module("taigaComponents").directive("tgTribeButton", TribeButtonDirective)
|
|
@ -0,0 +1,10 @@
|
||||||
|
a.button-tribe(
|
||||||
|
ng-href="{{::vm.tribeHost}}/gigs/import-from-taiga?project={{projectSlug}}&us={{usId}}",
|
||||||
|
title="{{ 'US.TRIBE.PUBLISH' | translate }}"
|
||||||
|
target="_blank"
|
||||||
|
)
|
||||||
|
img.tribe-logo(
|
||||||
|
src="/#{v}/images/tribe-logo.png"
|
||||||
|
alt="{{ 'US.TRIBE.PUBLISH' | translate }}"
|
||||||
|
)
|
||||||
|
span {{ 'US.TRIBE.PUBLISH' | translate }}
|
|
@ -0,0 +1,48 @@
|
||||||
|
###
|
||||||
|
# Copyright (C) 2014-2015 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: tribe-linked.directive.coffee
|
||||||
|
###
|
||||||
|
|
||||||
|
TribeLinkedDirective = (configService) ->
|
||||||
|
link = (scope, el, attrs) ->
|
||||||
|
|
||||||
|
scope.vm = {}
|
||||||
|
|
||||||
|
scope.vm.tribeHost = configService.config.tribeHost
|
||||||
|
|
||||||
|
scope.vm.show = () ->
|
||||||
|
scope.vm.open = true
|
||||||
|
|
||||||
|
scope.vm.hide = (event) ->
|
||||||
|
scope.vm.open = false
|
||||||
|
|
||||||
|
directive = {
|
||||||
|
templateUrl: "components/tribe-button/tribe-linked.html",
|
||||||
|
scope: {
|
||||||
|
gigTitle: "=",
|
||||||
|
gigId: "="
|
||||||
|
},
|
||||||
|
link: link
|
||||||
|
}
|
||||||
|
|
||||||
|
return directive
|
||||||
|
|
||||||
|
TribeLinkedDirective.$inject = [
|
||||||
|
"$tgConfig"
|
||||||
|
]
|
||||||
|
|
||||||
|
angular.module("taigaComponents").directive("tgTribeLinked", TribeLinkedDirective)
|
|
@ -0,0 +1,33 @@
|
||||||
|
.tribe-linked.js-tribe-linked(ng-class="{'is-active': vm.open, 'is-inactive': vm.open == false}")
|
||||||
|
.tribe-linked-inner
|
||||||
|
.tribe-linked-header
|
||||||
|
img.tribe-logo(
|
||||||
|
ng-click="vm.show()"
|
||||||
|
alt=""
|
||||||
|
title="{{ 'US.TRIBE.PUBLISHED_AS_GIG' | translate }}"
|
||||||
|
src="/#{v}/images/tribe-logo.png"
|
||||||
|
)
|
||||||
|
p.title {{ "US.TRIBE.PUBLISHED_AS_GIG" | translate }}
|
||||||
|
a.close(
|
||||||
|
ng-click="vm.hide()"
|
||||||
|
href=""
|
||||||
|
title="{{ 'US.TRIBE.CLOSE' | translate }}"
|
||||||
|
)
|
||||||
|
svg.icon.icon-remove
|
||||||
|
use(xlink:href="#icon-remove")
|
||||||
|
|
||||||
|
a.gig-title(
|
||||||
|
href="{{::vm.tribeHost}}/gigs/{{gigId}}"
|
||||||
|
title="gigTitle"
|
||||||
|
target="_blank"
|
||||||
|
) {{gigTitle}}
|
||||||
|
|
||||||
|
a.delete-link(
|
||||||
|
href="{{::vm.tribeHost}}/gigs/{{gigId}}/link-with-taiga?from=taiga"
|
||||||
|
title="{{ 'US.TRIBE.EDIT_LINK' | translate }}"
|
||||||
|
) {{ 'US.TRIBE.EDIT_LINK' | translate }}
|
||||||
|
|
||||||
|
a.synchronize-link.button-tribe(
|
||||||
|
ng-href="{{::vm.tribeHost}}/gigs/sync/{{gigId}}?from=taiga"
|
||||||
|
title="{{ 'US.TRIBE.SINCHRONIZE_LINK' }}"
|
||||||
|
) {{ 'US.TRIBE.SYNCHRONIZE_LINK' | translate }}
|
|
@ -0,0 +1,123 @@
|
||||||
|
.tribe-linked {
|
||||||
|
margin-left: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 99;
|
||||||
|
.tribe-linked-inner {
|
||||||
|
padding: .5rem;
|
||||||
|
transition: .2s;
|
||||||
|
&:hover {
|
||||||
|
background: $white;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.title,
|
||||||
|
.gig-title,
|
||||||
|
.delete-link,
|
||||||
|
.synchronize-link,
|
||||||
|
.close {
|
||||||
|
display: none;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tribe-logo {
|
||||||
|
height: 2rem;
|
||||||
|
width: 2rem;
|
||||||
|
}
|
||||||
|
&.is-active {
|
||||||
|
animation-duration: 1s;
|
||||||
|
animation-name: slideTribeInner;
|
||||||
|
background: $white;
|
||||||
|
box-shadow: 1px 1px 5px rgba($grayer, .2);
|
||||||
|
overflow: hidden;
|
||||||
|
.tribe-linked-inner {
|
||||||
|
height: 100%;
|
||||||
|
min-width: 300px;
|
||||||
|
.title,
|
||||||
|
.gig-title,
|
||||||
|
.delete-link,
|
||||||
|
.synchronize-link,
|
||||||
|
.close {
|
||||||
|
animation-duration: 1.25s;
|
||||||
|
animation-name: fadeInFromNone;
|
||||||
|
display: block;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tribe-linked-header {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.tribe-logo {
|
||||||
|
margin-right: .5rem;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
fill: $red-light;
|
||||||
|
height: 1.5rem;
|
||||||
|
max-height: 1.5rem;
|
||||||
|
max-width: 1.5rem;
|
||||||
|
transition: all .2s;
|
||||||
|
width: 1.5rem;
|
||||||
|
&:hover {
|
||||||
|
fill: $red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.gig-title {
|
||||||
|
@include font-type(light);
|
||||||
|
color: $tribe-primary;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
}
|
||||||
|
.delete-link {
|
||||||
|
@include font-type(light);
|
||||||
|
@include font-size(small);
|
||||||
|
color: $primary;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.synchronize-link {
|
||||||
|
display: block;
|
||||||
|
padding: .5rem;
|
||||||
|
}
|
||||||
|
.close {
|
||||||
|
align-self: flex-start;
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideTribeInner {
|
||||||
|
0% {
|
||||||
|
max-height: 60px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
max-height: 60px;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
max-height: 225px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInFromNone {
|
||||||
|
0% {
|
||||||
|
display: none;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
display: block;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,12 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 480px;
|
width: 480px;
|
||||||
.logo {
|
.logo {
|
||||||
height: 6rem;
|
height: 4rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 6rem;
|
width: 4rem;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
@include svg-size(4rem);
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
|
@ -107,6 +107,12 @@ div.wrapper(
|
||||||
ng-model="us"
|
ng-model="us"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tg-tribe-linked(
|
||||||
|
ng-if="tribeEnabled && us.tribe_gig",
|
||||||
|
gig-title="us.tribe_gig.title"
|
||||||
|
gig-id="us.tribe_gig.id"
|
||||||
|
)
|
||||||
|
|
||||||
tg-us-estimation.ticket-estimation(ng-model="us")
|
tg-us-estimation.ticket-estimation(ng-model="us")
|
||||||
|
|
||||||
section.ticket-assigned-to(
|
section.ticket-assigned-to(
|
||||||
|
@ -129,6 +135,16 @@ div.wrapper(
|
||||||
required-perm="modify_us"
|
required-perm="modify_us"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
section.ticket-to-tribe(ng-if="tribeEnabled && !us.tribe_gig")
|
||||||
|
tg-tribe-button(
|
||||||
|
us-id="us.id"
|
||||||
|
project-slug="project.slug"
|
||||||
|
)
|
||||||
|
a.tribe-more-info(
|
||||||
|
href=""
|
||||||
|
title="{{'US.TRIBE.PUBLISH_TITLE' | translate}}"
|
||||||
|
ng-click="ctrl.onTribeInfo()"
|
||||||
|
) {{'US.TRIBE.PUBLISH_INFO' | translate}}
|
||||||
|
|
||||||
section.ticket-detail-settings
|
section.ticket-detail-settings
|
||||||
tg-us-team-requirement-button(ng-model="us")
|
tg-us-team-requirement-button(ng-model="us")
|
||||||
|
|
|
@ -130,3 +130,28 @@ a.button-gray {
|
||||||
background: $black;
|
background: $black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-tribe {
|
||||||
|
@extend %button;
|
||||||
|
align-items: center;
|
||||||
|
background: $tribe-primary;
|
||||||
|
display: flex;
|
||||||
|
padding: .4rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
&:hover,
|
||||||
|
&.active {
|
||||||
|
background: $tribe-secondary;
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
.tribe-logo {
|
||||||
|
margin-right: .5rem;
|
||||||
|
width: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tribe-more-info {
|
||||||
|
@include font-size(small);
|
||||||
|
color: $primary;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: .5rem;
|
||||||
|
}
|
||||||
|
|
|
@ -31,8 +31,8 @@ $red-amaranth: #e91e63;
|
||||||
$purple-eggplant: #9c27b0;
|
$purple-eggplant: #9c27b0;
|
||||||
$yellow-pear: #ffc107;
|
$yellow-pear: #ffc107;
|
||||||
|
|
||||||
$tribe-primary: #98e0eb;
|
$tribe-primary: #107a8a;
|
||||||
$tribe-secondary: #107a8a;
|
$tribe-secondary: darken($tribe-primary, 10%);
|
||||||
|
|
||||||
$top-icon-color: $white;
|
$top-icon-color: $white;
|
||||||
$dropdown-color: rgba(darken($primary-dark, 20%), 1);
|
$dropdown-color: rgba(darken($primary-dark, 20%), 1);
|
||||||
|
|
|
@ -31,8 +31,8 @@ $red-amaranth: #e91e63;
|
||||||
$purple-eggplant: #9c27b0;
|
$purple-eggplant: #9c27b0;
|
||||||
$yellow-pear: #ffc107;
|
$yellow-pear: #ffc107;
|
||||||
|
|
||||||
$tribe-primary: #98e0eb;
|
$tribe-primary: #107a8a;
|
||||||
$tribe-secondary: #107a8a;
|
$tribe-secondary: darken($tribe-primary, 10%);
|
||||||
|
|
||||||
$top-icon-color: $white;
|
$top-icon-color: $white;
|
||||||
$dropdown-color: rgba(darken($primary-dark, 20%), 1);
|
$dropdown-color: rgba(darken($primary-dark, 20%), 1);
|
||||||
|
|
|
@ -31,8 +31,8 @@ $red-amaranth: #e43050;
|
||||||
$purple-eggplant: #810061;
|
$purple-eggplant: #810061;
|
||||||
$yellow-pear: #bbe831;
|
$yellow-pear: #bbe831;
|
||||||
|
|
||||||
$tribe-primary: #98e0eb;
|
$tribe-primary: #107a8a;
|
||||||
$tribe-secondary: #107a8a;
|
$tribe-secondary: darken($tribe-primary, 10%);
|
||||||
|
|
||||||
$top-icon-color: #11241f;
|
$top-icon-color: #11241f;
|
||||||
$dropdown-color: rgba(darken($grayer, 20%), 1);
|
$dropdown-color: rgba(darken($grayer, 20%), 1);
|
||||||
|
|
|
@ -13,5 +13,6 @@
|
||||||
"privacyPolicyUrl": null,
|
"privacyPolicyUrl": null,
|
||||||
"termsOfServiceUrl": null,
|
"termsOfServiceUrl": null,
|
||||||
"maxUploadFileSize": null,
|
"maxUploadFileSize": null,
|
||||||
"contribPlugins": []
|
"contribPlugins": [],
|
||||||
|
"tribeHost": null
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue