commit
3ff78cd5bb
|
@ -4,6 +4,7 @@
|
||||||
## 1.9.1 Taiga Tribe (unreleased)
|
## 1.9.1 Taiga Tribe (unreleased)
|
||||||
- [118n] Now taiga plugins can be translatable.
|
- [118n] Now taiga plugins can be translatable.
|
||||||
- New Taiga plugins system.
|
- New Taiga plugins system.
|
||||||
|
- Now superadmins can send notifications (live announcement) to the user (through taiga-events).
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
- Statics folder hash to prevent cache problems when a new version is released.
|
- Statics folder hash to prevent cache problems when a new version is released.
|
||||||
|
|
|
@ -573,9 +573,10 @@ init = ($log, $rootscope, $auth, $events, $analytics, $translate, $location, $na
|
||||||
Promise.setScheduler (cb) ->
|
Promise.setScheduler (cb) ->
|
||||||
$rootscope.$evalAsync(cb)
|
$rootscope.$evalAsync(cb)
|
||||||
|
|
||||||
|
$events.setupConnection()
|
||||||
|
|
||||||
# Load user
|
# Load user
|
||||||
if $auth.isAuthenticated()
|
if $auth.isAuthenticated()
|
||||||
$events.setupConnection()
|
|
||||||
user = $auth.getUser()
|
user = $auth.getUser()
|
||||||
|
|
||||||
# Analytics
|
# Analytics
|
||||||
|
|
|
@ -27,7 +27,7 @@ module = angular.module("taigaEvents", [])
|
||||||
|
|
||||||
|
|
||||||
class EventsService
|
class EventsService
|
||||||
constructor: (@win, @log, @config, @auth) ->
|
constructor: (@win, @log, @config, @auth, @liveAnnouncementService, @rootScope) ->
|
||||||
bindMethods(@)
|
bindMethods(@)
|
||||||
|
|
||||||
initialize: (sessionId) ->
|
initialize: (sessionId) ->
|
||||||
|
@ -78,6 +78,11 @@ class EventsService
|
||||||
|
|
||||||
delete @.ws
|
delete @.ws
|
||||||
|
|
||||||
|
notifications: ->
|
||||||
|
@.subscribe null, 'notifications', (data) =>
|
||||||
|
@liveAnnouncementService.show(data.title, data.desc)
|
||||||
|
@rootScope.$digest()
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
# Heartbeat (Ping - Pong)
|
# Heartbeat (Ping - Pong)
|
||||||
###########################################
|
###########################################
|
||||||
|
@ -144,7 +149,12 @@ class EventsService
|
||||||
return
|
return
|
||||||
|
|
||||||
subscription = @.subscriptions[routingKey]
|
subscription = @.subscriptions[routingKey]
|
||||||
subscription.scope.$apply ->
|
|
||||||
|
if subscription.scope
|
||||||
|
subscription.scope.$apply ->
|
||||||
|
subscription.callback(data.data)
|
||||||
|
|
||||||
|
else
|
||||||
subscription.callback(data.data)
|
subscription.callback(data.data)
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
|
@ -168,7 +178,8 @@ class EventsService
|
||||||
|
|
||||||
@.subscriptions[routingKey] = subscription
|
@.subscriptions[routingKey] = subscription
|
||||||
@.sendMessage(message)
|
@.sendMessage(message)
|
||||||
scope.$on("$destroy", => @.unsubscribe(routingKey))
|
|
||||||
|
scope.$on("$destroy", => @.unsubscribe(routingKey)) if scope
|
||||||
|
|
||||||
unsubscribe: (routingKey) ->
|
unsubscribe: (routingKey) ->
|
||||||
if @.error
|
if @.error
|
||||||
|
@ -189,6 +200,7 @@ class EventsService
|
||||||
onOpen: ->
|
onOpen: ->
|
||||||
@.connected = true
|
@.connected = true
|
||||||
@.startHeartBeatMessages()
|
@.startHeartBeatMessages()
|
||||||
|
@.notifications()
|
||||||
|
|
||||||
@log.debug("WebSocket connection opened")
|
@log.debug("WebSocket connection opened")
|
||||||
token = @auth.getToken()
|
token = @auth.getToken()
|
||||||
|
@ -204,6 +216,7 @@ class EventsService
|
||||||
@.log.debug "WebSocket message received: #{event.data}"
|
@.log.debug "WebSocket message received: #{event.data}"
|
||||||
|
|
||||||
data = JSON.parse(event.data)
|
data = JSON.parse(event.data)
|
||||||
|
|
||||||
if data.cmd == "pong"
|
if data.cmd == "pong"
|
||||||
@.processHeartBeatPongMessage(data)
|
@.processHeartBeatPongMessage(data)
|
||||||
else
|
else
|
||||||
|
@ -223,11 +236,18 @@ class EventsProvider
|
||||||
setSessionId: (sessionId) ->
|
setSessionId: (sessionId) ->
|
||||||
@.sessionId = sessionId
|
@.sessionId = sessionId
|
||||||
|
|
||||||
$get: ($win, $log, $conf, $auth) ->
|
$get: ($win, $log, $conf, $auth, liveAnnouncementService, $rootScope) ->
|
||||||
service = new EventsService($win, $log, $conf, $auth)
|
service = new EventsService($win, $log, $conf, $auth, liveAnnouncementService, $rootScope)
|
||||||
service.initialize(@.sessionId)
|
service.initialize(@.sessionId)
|
||||||
return service
|
return service
|
||||||
|
|
||||||
@.prototype.$get.$inject = ["$window", "$log", "$tgConfig", "$tgAuth"]
|
@.prototype.$get.$inject = [
|
||||||
|
"$window",
|
||||||
|
"$log",
|
||||||
|
"$tgConfig",
|
||||||
|
"$tgAuth",
|
||||||
|
"tgLiveAnnouncementService",
|
||||||
|
"$rootScope"
|
||||||
|
]
|
||||||
|
|
||||||
module.provider("$tgEvents", EventsProvider)
|
module.provider("$tgEvents", EventsProvider)
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -38,6 +38,7 @@ html(lang="en")
|
||||||
include partials/includes/components/notification-message
|
include partials/includes/components/notification-message
|
||||||
|
|
||||||
div(tg-joy-ride)
|
div(tg-joy-ride)
|
||||||
|
div(tg-live-announcement)
|
||||||
|
|
||||||
script(src="/#{v}/js/libs.js")
|
script(src="/#{v}/js/libs.js")
|
||||||
script(src="/#{v}/js/templates.js")
|
script(src="/#{v}/js/templates.js")
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
###
|
||||||
|
# Copyright (C) 2014-2015 Andrey Antukh <niwi@niwi.be>
|
||||||
|
# Copyright (C) 2014-2015 Jesús Espino Garcia <jespinog@gmail.com>
|
||||||
|
# Copyright (C) 2014-2015 David Barragán Merino <bameda@dbarragan.com>
|
||||||
|
#
|
||||||
|
# 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: live-announcement.directive.coffee
|
||||||
|
###
|
||||||
|
|
||||||
|
|
||||||
|
LiveAnnouncementDirective = (liveAnnouncementService) ->
|
||||||
|
link = (scope, el, attrs) ->
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: "AE",
|
||||||
|
scope: {},
|
||||||
|
controllerAs: 'vm',
|
||||||
|
controller: () ->
|
||||||
|
this.close = () ->
|
||||||
|
liveAnnouncementService.open = false
|
||||||
|
|
||||||
|
Object.defineProperties(this, {
|
||||||
|
open: {
|
||||||
|
get: () -> return liveAnnouncementService.open
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
get: () -> return liveAnnouncementService.title
|
||||||
|
},
|
||||||
|
desc: {
|
||||||
|
get: () -> return liveAnnouncementService.desc
|
||||||
|
}
|
||||||
|
})
|
||||||
|
link: link,
|
||||||
|
templateUrl: "components/live-announcement/live-announcement.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveAnnouncementDirective.$inject = [
|
||||||
|
"tgLiveAnnouncementService"
|
||||||
|
]
|
||||||
|
|
||||||
|
angular.module("taigaComponents")
|
||||||
|
.directive("tgLiveAnnouncement", LiveAnnouncementDirective)
|
|
@ -0,0 +1,12 @@
|
||||||
|
.live-announcement(ng-class="{visible: vm.open}")
|
||||||
|
.live-announcement-inner
|
||||||
|
img.anouncement-decoration(src="/#{v}/images/notification-decoration.png", alt="Loading...")
|
||||||
|
.text
|
||||||
|
h2.title {{vm.title}}
|
||||||
|
p.warning(ng-bind-html="vm.desc")
|
||||||
|
a.close(
|
||||||
|
ng-click="vm.close()"
|
||||||
|
href=""
|
||||||
|
title="{{ COMMON.CLOSE | translate }}"
|
||||||
|
)
|
||||||
|
include ../../../svg/remove.svg
|
|
@ -0,0 +1,72 @@
|
||||||
|
.live-announcement {
|
||||||
|
$animation-steps-duration: .5s;
|
||||||
|
align-content: center;
|
||||||
|
background: $tribe-primary;
|
||||||
|
display: flex;
|
||||||
|
height: 0;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
transition: width $animation-steps-duration, height $animation-steps-duration;
|
||||||
|
transition-delay: $animation-steps-duration;
|
||||||
|
width: 0;
|
||||||
|
z-index: 99;
|
||||||
|
.live-announcement-inner {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity $animation-steps-duration;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
&.visible {
|
||||||
|
height: 146px;
|
||||||
|
pointer-events: auto;
|
||||||
|
transition-delay: 0s;
|
||||||
|
width: 100%;
|
||||||
|
.live-announcement-inner {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity $animation-steps-duration $animation-steps-duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-announcement-inner {
|
||||||
|
display: flex;
|
||||||
|
max-width: 1200px;
|
||||||
|
.announcement-decoration {
|
||||||
|
align-self: flex-end;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
padding: 1.25rem 3rem 1.25rem 2rem;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
@extend %bold;
|
||||||
|
@extend %larger;
|
||||||
|
color: $tribe-secondary;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
color: $tribe-secondary;
|
||||||
|
a {
|
||||||
|
@extend %bold;
|
||||||
|
color: $tribe-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.close {
|
||||||
|
height: 2.5rem;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 1rem;
|
||||||
|
width: 2.5rem;
|
||||||
|
svg {
|
||||||
|
fill: lighten($tribe-secondary, 15%);
|
||||||
|
transition: fill .2s;
|
||||||
|
&:hover {
|
||||||
|
fill: $tribe-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
###
|
||||||
|
# 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: notification.service.coffee
|
||||||
|
###
|
||||||
|
|
||||||
|
class LiveAnnouncementService extends taiga.Service
|
||||||
|
constructor: () ->
|
||||||
|
@.open = false
|
||||||
|
@.title = ""
|
||||||
|
@.desc = ""
|
||||||
|
|
||||||
|
show: (title, desc) ->
|
||||||
|
@.open = true
|
||||||
|
@.title = title
|
||||||
|
@.desc = desc
|
||||||
|
|
||||||
|
angular.module("taigaComponents").service("tgLiveAnnouncementService", LiveAnnouncementService)
|
|
@ -1,6 +1,6 @@
|
||||||
div.wrapper
|
div.wrapper
|
||||||
tg-project-menu
|
tg-project-menu
|
||||||
div.centered.single-project
|
div.single-project.centered
|
||||||
section.single-project-intro
|
section.single-project-intro
|
||||||
div.intro-options
|
div.intro-options
|
||||||
h1
|
h1
|
||||||
|
|
|
@ -31,6 +31,10 @@ $red-amaranth: #e43050;
|
||||||
$purple-eggplant: #810061;
|
$purple-eggplant: #810061;
|
||||||
$yellow-pear: #bbe831;
|
$yellow-pear: #bbe831;
|
||||||
|
|
||||||
|
$tribe-primary: #98e0eb;
|
||||||
|
$tribe-secondary: #107a8a;
|
||||||
|
|
||||||
|
|
||||||
$top-icon-color: #11241f;
|
$top-icon-color: #11241f;
|
||||||
$dropdown-color: rgba(darken($grayer, 20%), 1);
|
$dropdown-color: rgba(darken($grayer, 20%), 1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue