commit
a880f1bcd3
|
@ -3,6 +3,8 @@
|
||||||
## 1.5.0 Betula Pendula - FOSDEM 2015 (unreleased)
|
## 1.5.0 Betula Pendula - FOSDEM 2015 (unreleased)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
- Taiga webhooks
|
||||||
|
+ Created admin panel with webhook settings.
|
||||||
- Not showing closed milestones by default in backlog view.
|
- Not showing closed milestones by default in backlog view.
|
||||||
- In kanban view an archived user story status doesn't show his content by default.
|
- In kanban view an archived user story status doesn't show his content by default.
|
||||||
- Now you can export and import projects between Taiga instances.
|
- Now you can export and import projects between Taiga instances.
|
||||||
|
|
|
@ -101,6 +101,8 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven
|
||||||
{templateUrl: "admin/admin-memberships.html"})
|
{templateUrl: "admin/admin-memberships.html"})
|
||||||
$routeProvider.when("/project/:pslug/admin/roles",
|
$routeProvider.when("/project/:pslug/admin/roles",
|
||||||
{templateUrl: "admin/admin-roles.html"})
|
{templateUrl: "admin/admin-roles.html"})
|
||||||
|
$routeProvider.when("/project/:pslug/admin/third-parties/webhooks",
|
||||||
|
{templateUrl: "admin/admin-third-parties-webhooks.html"})
|
||||||
$routeProvider.when("/project/:pslug/admin/third-parties/github",
|
$routeProvider.when("/project/:pslug/admin/third-parties/github",
|
||||||
{templateUrl: "admin/admin-third-parties-github.html"})
|
{templateUrl: "admin/admin-third-parties-github.html"})
|
||||||
$routeProvider.when("/project/:pslug/admin/third-parties/gitlab",
|
$routeProvider.when("/project/:pslug/admin/third-parties/gitlab",
|
||||||
|
|
|
@ -24,9 +24,240 @@ taiga = @.taiga
|
||||||
mixOf = @.taiga.mixOf
|
mixOf = @.taiga.mixOf
|
||||||
bindMethods = @.taiga.bindMethods
|
bindMethods = @.taiga.bindMethods
|
||||||
debounce = @.taiga.debounce
|
debounce = @.taiga.debounce
|
||||||
|
timeout = @.taiga.timeout
|
||||||
|
|
||||||
module = angular.module("taigaAdmin")
|
module = angular.module("taigaAdmin")
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## Webhooks
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
class WebhooksController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin)
|
||||||
|
@.$inject = [
|
||||||
|
"$scope",
|
||||||
|
"$tgRepo",
|
||||||
|
"$tgResources",
|
||||||
|
"$routeParams",
|
||||||
|
"$appTitle"
|
||||||
|
]
|
||||||
|
|
||||||
|
constructor: (@scope, @repo, @rs, @params, @appTitle) ->
|
||||||
|
bindMethods(@)
|
||||||
|
|
||||||
|
@scope.sectionName = "Webhooks" #i18n
|
||||||
|
@scope.project = {}
|
||||||
|
|
||||||
|
promise = @.loadInitialData()
|
||||||
|
|
||||||
|
promise.then () =>
|
||||||
|
@appTitle.set("Webhooks - " + @scope.project.name)
|
||||||
|
|
||||||
|
promise.then null, @.onInitialDataError.bind(@)
|
||||||
|
|
||||||
|
@scope.$on "webhooks:reload", @.loadWebhooks
|
||||||
|
|
||||||
|
loadWebhooks: ->
|
||||||
|
return @rs.webhooks.list(@scope.projectId).then (webhooks) =>
|
||||||
|
@scope.webhooks = webhooks
|
||||||
|
|
||||||
|
loadProject: ->
|
||||||
|
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||||
|
@scope.project = project
|
||||||
|
@scope.$emit('project:loaded', project)
|
||||||
|
return project
|
||||||
|
|
||||||
|
loadInitialData: ->
|
||||||
|
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||||
|
@scope.projectId = data.project
|
||||||
|
return data
|
||||||
|
|
||||||
|
return promise.then(=> @.loadProject())
|
||||||
|
.then(=> @.loadWebhooks())
|
||||||
|
|
||||||
|
module.controller("WebhooksController", WebhooksController)
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## Webhook Directive
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
WebhookDirective = ($rs, $repo, $confirm, $loading) ->
|
||||||
|
link = ($scope, $el, $attrs) ->
|
||||||
|
webhook = $scope.$eval($attrs.tgWebhook)
|
||||||
|
|
||||||
|
updateLogs = () ->
|
||||||
|
$rs.webhooklogs.list(webhook.id).then (webhooklogs) =>
|
||||||
|
for log in webhooklogs
|
||||||
|
log.validStatus = 200 <= log.status < 300
|
||||||
|
log.prettySentHeaders = _.map(_.pairs(log.request_headers), ([header, value]) -> "#{header}: #{value}").join("\n")
|
||||||
|
log.prettySentData = JSON.stringify(log.request_data.data, undefined, 2)
|
||||||
|
log.prettyDate = moment(log.created).format("DD MMM YYYY [at] hh:mm:ss") # TODO: i18n
|
||||||
|
|
||||||
|
webhook.logs_counter = webhooklogs.length
|
||||||
|
webhook.logs = webhooklogs
|
||||||
|
updateShowHideHistoryText()
|
||||||
|
|
||||||
|
updateShowHideHistoryText = () ->
|
||||||
|
textElement = $el.find(".toggle-history")
|
||||||
|
historyElement = textElement.parents(".single-webhook-wrapper").find(".webhooks-history")
|
||||||
|
if historyElement.hasClass("open")
|
||||||
|
textElement.text("(Hide history)") # TODO: i18n
|
||||||
|
else
|
||||||
|
textElement.text("(Show history)") # TODO: i18n
|
||||||
|
|
||||||
|
showVisualizationMode = () ->
|
||||||
|
$el.find(".edition-mode").addClass("hidden")
|
||||||
|
$el.find(".visualization-mode").removeClass("hidden")
|
||||||
|
|
||||||
|
showEditMode = () ->
|
||||||
|
$el.find(".visualization-mode").addClass("hidden")
|
||||||
|
$el.find(".edition-mode").removeClass("hidden")
|
||||||
|
|
||||||
|
openHistory = () ->
|
||||||
|
$el.find(".webhooks-history").addClass("open")
|
||||||
|
|
||||||
|
cancel = () ->
|
||||||
|
showVisualizationMode()
|
||||||
|
$scope.$apply ->
|
||||||
|
webhook.revert()
|
||||||
|
|
||||||
|
save = debounce 2000, (target) ->
|
||||||
|
form = target.parents("form").checksley()
|
||||||
|
return if not form.validate()
|
||||||
|
|
||||||
|
value = target.scope().value
|
||||||
|
promise = $repo.save(webhook)
|
||||||
|
promise.then =>
|
||||||
|
showVisualizationMode()
|
||||||
|
|
||||||
|
promise.then null, (data) ->
|
||||||
|
$confirm.notify("error")
|
||||||
|
form.setErrors(data)
|
||||||
|
|
||||||
|
$el.on "click", ".test-webhook", () ->
|
||||||
|
openHistory()
|
||||||
|
$rs.webhooks.test(webhook.id).then =>
|
||||||
|
updateLogs()
|
||||||
|
|
||||||
|
$el.on "click", ".edit-webhook", () ->
|
||||||
|
showEditMode()
|
||||||
|
|
||||||
|
$el.on "click", ".cancel-existing", () ->
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
$el.on "click", ".edit-existing", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
save(target)
|
||||||
|
|
||||||
|
$el.on "keyup", ".edition-mode input", (event) ->
|
||||||
|
if event.keyCode == 13
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
saveWebhook(target)
|
||||||
|
else if event.keyCode == 27
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
cancel(target)
|
||||||
|
|
||||||
|
$el.on "click", ".delete-webhook", () ->
|
||||||
|
title = "Delete webhook" #TODO: i18n
|
||||||
|
message = "Webhook '#{webhook.name}'" #TODO: i18n
|
||||||
|
|
||||||
|
$confirm.askOnDelete(title, message).then (finish) =>
|
||||||
|
onSucces = ->
|
||||||
|
finish()
|
||||||
|
$scope.$emit("webhooks:reload")
|
||||||
|
|
||||||
|
onError = ->
|
||||||
|
finish(false)
|
||||||
|
$confirm.notify("error")
|
||||||
|
|
||||||
|
$repo.remove(webhook).then(onSucces, onError)
|
||||||
|
|
||||||
|
$el.on "click", ".toggle-history", (event) ->
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
if not webhook.logs? or webhook.logs.length == 0
|
||||||
|
updateLogs().then ->
|
||||||
|
#Waiting for ng-repeat to finish
|
||||||
|
timeout 0, ->
|
||||||
|
$el.find(".webhooks-history").toggleClass("open")
|
||||||
|
updateShowHideHistoryText()
|
||||||
|
|
||||||
|
else
|
||||||
|
$el.find(".webhooks-history").toggleClass("open")
|
||||||
|
$scope.$apply () ->
|
||||||
|
updateShowHideHistoryText()
|
||||||
|
|
||||||
|
|
||||||
|
$el.on "click", ".history-single", (event) ->
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
target.toggleClass("history-single-open")
|
||||||
|
target.siblings(".history-single-response").toggleClass("open")
|
||||||
|
|
||||||
|
$el.on "click", ".resend-request", (event) ->
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
log = target.data("log")
|
||||||
|
$rs.webhooklogs.resend(log).then () =>
|
||||||
|
updateLogs()
|
||||||
|
|
||||||
|
return {link:link}
|
||||||
|
|
||||||
|
module.directive("tgWebhook", ["$tgResources", "$tgRepo", "$tgConfirm", "$tgLoading", WebhookDirective])
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## New webhook Directive
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
NewWebhookDirective = ($rs, $repo, $confirm, $loading) ->
|
||||||
|
link = ($scope, $el, $attrs) ->
|
||||||
|
webhook = $scope.$eval($attrs.tgWebhook)
|
||||||
|
formDOMNode = $el.find(".new-webhook-form")
|
||||||
|
addWebhookDOMNode = $el.find(".add-webhook")
|
||||||
|
initializeNewValue = ->
|
||||||
|
$scope.newValue = {
|
||||||
|
"name": ""
|
||||||
|
"url": ""
|
||||||
|
"key": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeNewValue()
|
||||||
|
|
||||||
|
$scope.$watch "webhooks", (webhooks) ->
|
||||||
|
if webhooks?
|
||||||
|
if webhooks.length == 0
|
||||||
|
formDOMNode.removeClass("hidden")
|
||||||
|
addWebhookDOMNode.addClass("hidden")
|
||||||
|
formDOMNode.find("input")[0].focus()
|
||||||
|
else
|
||||||
|
formDOMNode.addClass("hidden")
|
||||||
|
addWebhookDOMNode.removeClass("hidden")
|
||||||
|
|
||||||
|
formDOMNode.on "click", ".add-new", debounce 2000, (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
form = formDOMNode.checksley()
|
||||||
|
return if not form.validate()
|
||||||
|
|
||||||
|
$scope.newValue.project = $scope.project.id
|
||||||
|
promise = $repo.create("webhooks", $scope.newValue)
|
||||||
|
promise.then =>
|
||||||
|
$scope.$emit("webhooks:reload")
|
||||||
|
initializeNewValue()
|
||||||
|
|
||||||
|
promise.then null, (data) ->
|
||||||
|
$confirm.notify("error")
|
||||||
|
form.setErrors(data)
|
||||||
|
|
||||||
|
formDOMNode.on "click", ".cancel-new", (event) ->
|
||||||
|
$scope.$apply ->
|
||||||
|
initializeNewValue()
|
||||||
|
|
||||||
|
addWebhookDOMNode.on "click", (event) ->
|
||||||
|
formDOMNode.removeClass("hidden")
|
||||||
|
formDOMNode.find("input")[0].focus()
|
||||||
|
|
||||||
|
return {link:link}
|
||||||
|
|
||||||
|
module.directive("tgNewWebhook", ["$tgResources", "$tgRepo", "$tgConfirm", "$tgLoading", NewWebhookDirective])
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## Github Controller
|
## Github Controller
|
||||||
|
|
|
@ -93,6 +93,7 @@ urls = {
|
||||||
"project-admin-project-values-issue-severities": "/project/:project/admin/project-values/issue-severities"
|
"project-admin-project-values-issue-severities": "/project/:project/admin/project-values/issue-severities"
|
||||||
"project-admin-memberships": "/project/:project/admin/memberships"
|
"project-admin-memberships": "/project/:project/admin/memberships"
|
||||||
"project-admin-roles": "/project/:project/admin/roles"
|
"project-admin-roles": "/project/:project/admin/roles"
|
||||||
|
"project-admin-third-parties-webhooks": "/project/:project/admin/third-parties/webhooks"
|
||||||
"project-admin-third-parties-github": "/project/:project/admin/third-parties/github"
|
"project-admin-third-parties-github": "/project/:project/admin/third-parties/github"
|
||||||
"project-admin-third-parties-gitlab": "/project/:project/admin/third-parties/gitlab"
|
"project-admin-third-parties-gitlab": "/project/:project/admin/third-parties/gitlab"
|
||||||
"project-admin-third-parties-bitbucket": "/project/:project/admin/third-parties/bitbucket"
|
"project-admin-third-parties-bitbucket": "/project/:project/admin/third-parties/bitbucket"
|
||||||
|
|
|
@ -27,7 +27,6 @@ class TgLoadingService extends taiga.Service
|
||||||
target.data('loading-old-content', target.html())
|
target.data('loading-old-content', target.html())
|
||||||
target.addClass('loading')
|
target.addClass('loading')
|
||||||
target.html("<img class='loading-spinner' src='/svg/spinner-circle.svg' alt='loading...' />")
|
target.html("<img class='loading-spinner' src='/svg/spinner-circle.svg' alt='loading...' />")
|
||||||
debugger
|
|
||||||
|
|
||||||
finish: (target) ->
|
finish: (target) ->
|
||||||
if target.hasClass('loading')
|
if target.hasClass('loading')
|
||||||
|
|
|
@ -85,6 +85,10 @@ urls = {
|
||||||
"priorities": "/priorities"
|
"priorities": "/priorities"
|
||||||
"severities": "/severities"
|
"severities": "/severities"
|
||||||
"project-modules": "/projects/%s/modules"
|
"project-modules": "/projects/%s/modules"
|
||||||
|
"webhooks": "/webhooks"
|
||||||
|
"webhooks-test": "/webhooks/%s/test"
|
||||||
|
"webhooklogs": "/webhooklogs"
|
||||||
|
"webhooklogs-resend": "/webhooklogs/%s/resend"
|
||||||
|
|
||||||
# History
|
# History
|
||||||
"history/us": "/history/userstory"
|
"history/us": "/history/userstory"
|
||||||
|
@ -145,5 +149,7 @@ module.run([
|
||||||
"$tgHistoryResourcesProvider",
|
"$tgHistoryResourcesProvider",
|
||||||
"$tgKanbanResourcesProvider",
|
"$tgKanbanResourcesProvider",
|
||||||
"$tgModulesResourcesProvider",
|
"$tgModulesResourcesProvider",
|
||||||
|
"$tgWebhooksResourcesProvider",
|
||||||
|
"$tgWebhookLogsResourcesProvider",
|
||||||
initResources
|
initResources
|
||||||
])
|
])
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
resourceProvider = ($repo, $urls, $http) ->
|
||||||
|
service = {}
|
||||||
|
|
||||||
|
service.list = (webhookId) ->
|
||||||
|
params = {webhook: webhookId}
|
||||||
|
return $repo.queryMany("webhooklogs", params)
|
||||||
|
|
||||||
|
service.resend = (webhooklogId) ->
|
||||||
|
url = $urls.resolve("webhooklogs-resend", webhooklogId)
|
||||||
|
return $http.post(url)
|
||||||
|
|
||||||
|
return (instance) ->
|
||||||
|
instance.webhooklogs = service
|
||||||
|
|
||||||
|
|
||||||
|
module = angular.module("taigaResources")
|
||||||
|
module.factory("$tgWebhookLogsResourcesProvider", ["$tgRepo", "$tgUrls", "$tgHttp", resourceProvider])
|
|
@ -0,0 +1,17 @@
|
||||||
|
resourceProvider = ($repo, $urls, $http) ->
|
||||||
|
service = {}
|
||||||
|
|
||||||
|
service.list = (projectId) ->
|
||||||
|
params = {project: projectId}
|
||||||
|
return $repo.queryMany("webhooks", params)
|
||||||
|
|
||||||
|
service.test = (webhookId) ->
|
||||||
|
url = $urls.resolve("webhooks-test", webhookId)
|
||||||
|
return $http.post(url)
|
||||||
|
|
||||||
|
return (instance) ->
|
||||||
|
instance.webhooks = service
|
||||||
|
|
||||||
|
|
||||||
|
module = angular.module("taigaResources")
|
||||||
|
module.factory("$tgWebhooksResourcesProvider", ["$tgRepo", "$tgUrls", "$tgHttp", resourceProvider])
|
|
@ -0,0 +1,99 @@
|
||||||
|
block head
|
||||||
|
title Taiga Your agile, free, and open source project management tool
|
||||||
|
|
||||||
|
block content
|
||||||
|
div.wrapper.roles(ng-controller="WebhooksController as ctrl",
|
||||||
|
ng-init="section='admin'")
|
||||||
|
sidebar.menu-secondary.sidebar(tg-admin-navigation="Webhooks")
|
||||||
|
include ../includes/modules/admin-menu
|
||||||
|
sidebar.menu-tertiary.sidebar(tg-admin-navigation="third-parties-webhooks")
|
||||||
|
include ../includes/modules/admin-submenu-third-parties
|
||||||
|
|
||||||
|
section.main.admin-common.admin-webhooks(tg-new-webhook)
|
||||||
|
include ../includes/components/mainTitle
|
||||||
|
|
||||||
|
p.admin-subtitle Webhooks notify external services about events in Taiga, like comments, user stories....
|
||||||
|
div.webhooks-options
|
||||||
|
a.button.button-green.hidden.add-webhook(href="",title="Add a New Webhook") Add Webhook
|
||||||
|
|
||||||
|
section.webhooks-table.basic-table
|
||||||
|
div.table-header
|
||||||
|
div.row
|
||||||
|
div.webhook-service Name
|
||||||
|
div.webhook-url URL
|
||||||
|
div.webhook-options
|
||||||
|
div.table-body
|
||||||
|
div.single-webhook-wrapper(tg-webhook="webhook", ng-repeat="webhook in webhooks")
|
||||||
|
div.edition-mode.hidden
|
||||||
|
form.row
|
||||||
|
fieldset.webhook-service
|
||||||
|
input(type="text", name="name", placeholder="Type the service name", data-required="true", ng-model="webhook.name")
|
||||||
|
div.webhook-url
|
||||||
|
div.webhook-url-inputs
|
||||||
|
fieldset
|
||||||
|
input(type="text", name="url", data-type="url", placeholder="Type the service payload url", data-required="true", ng-model="webhook.url")
|
||||||
|
fieldset
|
||||||
|
input(type="text", name="key", placeholder="Type the service secret key", data-required="true", ng-model="webhook.key")
|
||||||
|
div.webhook-options
|
||||||
|
a.edit-existing.icon.icon-floppy(href="", title="Save Webhook")
|
||||||
|
a.cancel-existing.icon.icon-delete(href="", title="Cancel Webhook")
|
||||||
|
|
||||||
|
div.visualization-mode
|
||||||
|
div.row
|
||||||
|
div.webhook-service
|
||||||
|
span(ng-bind="webhook.name")
|
||||||
|
div.webhook-url
|
||||||
|
span(ng-bind="webhook.url")
|
||||||
|
a.show-history.toggle-history(href="", title="Toggle history", ng-show="webhook.logs_counter") (Show history)
|
||||||
|
|
||||||
|
div.webhook-options
|
||||||
|
div.webhook-options-wrapper
|
||||||
|
a.test-webhook.icon.icon-check-square(href="", title="Test Webhook")
|
||||||
|
a.edit-webhook.icon.icon-edit(href="", title="Edit Webhook")
|
||||||
|
a.delete-webhook.icon.icon-delete(href="", title="Delete Webhook")
|
||||||
|
|
||||||
|
div.webhooks-history(ng-show="webhook.logs")
|
||||||
|
div.history-single-wrapper(ng-repeat="log in webhook.logs")
|
||||||
|
div.history-single
|
||||||
|
div
|
||||||
|
span.history-response-icon(ng-class="log.validStatus ? 'history-success' : 'history-error'", title="{{log.status}}")
|
||||||
|
span.history-date(ng-bind="log.prettyDate")
|
||||||
|
span.toggle-log.icon.icon-arrow-bottom
|
||||||
|
|
||||||
|
div.history-single-response
|
||||||
|
div.history-single-request-header
|
||||||
|
span Request
|
||||||
|
a.resend-request(href="", title="Resend request", data-log="{{log.id}}")
|
||||||
|
span.icon.icon-reload
|
||||||
|
span Resend request
|
||||||
|
div.history-single-request-body
|
||||||
|
div.response-container
|
||||||
|
span.response-title Headers
|
||||||
|
textarea(name="headers", ng-bind="log.prettySentHeaders")
|
||||||
|
|
||||||
|
div.response-container
|
||||||
|
span.response-title Payload
|
||||||
|
textarea(name="payload", ng-bind="log.prettySentData")
|
||||||
|
|
||||||
|
div.history-single-response-header
|
||||||
|
span Response
|
||||||
|
div.history-single-response-body
|
||||||
|
div.response-container
|
||||||
|
textarea(name="response-data", ng-bind="log.response_data")
|
||||||
|
|
||||||
|
form.new-webhook-form.row.hidden
|
||||||
|
fieldset.webhook-service
|
||||||
|
input(type="text", name="name", placeholder="Type the service name", data-required="true", ng-model="newValue.name")
|
||||||
|
div.webhook-url
|
||||||
|
div.webhook-url-inputs
|
||||||
|
fieldset
|
||||||
|
input(type="text", name="url", data-type="url", placeholder="Type the service payload url", data-required="true", ng-model="newValue.url")
|
||||||
|
fieldset
|
||||||
|
input(type="text", name="key", placeholder="Type the service secret key", data-required="true", ng-model="newValue.key")
|
||||||
|
div.webhook-options
|
||||||
|
a.add-new.icon.icon-floppy(href="", title="Save Webhook")
|
||||||
|
a.cancel-new.icon.icon-delete(href="", title="Cancel Webhook")
|
||||||
|
|
||||||
|
a.help-button(href="https://taiga.io/support/webhooks/", target="_blank")
|
||||||
|
span.icon.icon-help
|
||||||
|
span Do you need help? Check out our support page!
|
|
@ -21,8 +21,8 @@ section.admin-menu
|
||||||
span.title Roles & Permissions
|
span.title Roles & Permissions
|
||||||
span.icon.icon-arrow-right
|
span.icon.icon-arrow-right
|
||||||
li#adminmenu-third-parties
|
li#adminmenu-third-parties
|
||||||
a(href="" tg-nav="project-admin-third-parties-github:project=project.slug")
|
a(href="" tg-nav="project-admin-third-parties-webhooks:project=project.slug")
|
||||||
span.title Third parties
|
span.title Integrations
|
||||||
span.icon.icon-arrow-right
|
span.icon.icon-arrow-right
|
||||||
li#adminmenu-contrib(ng-show="contribPlugins.length > 0")
|
li#adminmenu-contrib(ng-show="contribPlugins.length > 0")
|
||||||
a(href="" tg-nav="project-admin-contrib:project=project.slug,plugin=contribPlugins[0].slug")
|
a(href="" tg-nav="project-admin-contrib:project=project.slug,plugin=contribPlugins[0].slug")
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
section.admin-submenu
|
section.admin-submenu
|
||||||
header
|
header
|
||||||
h1 Third parties
|
h1 Services
|
||||||
|
|
||||||
nav
|
nav
|
||||||
ul
|
ul
|
||||||
|
li#adminmenu-third-parties-webhooks.third-parties-webhooks
|
||||||
|
a(href="", tg-nav="project-admin-third-parties-webhooks:project=project.slug")
|
||||||
|
span.title Webhooks
|
||||||
|
span.icon.icon-arrow-right
|
||||||
li#adminmenu-third-parties-github
|
li#adminmenu-third-parties-github
|
||||||
a(href="", tg-nav="project-admin-third-parties-github:project=project.slug")
|
a(href="", tg-nav="project-admin-third-parties-github:project=project.slug")
|
||||||
span.title Github
|
span.title Github
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
%text {font-family: 'opensans-regular', Arial, Helvetica, sans-serif; line-height: 1.3rem;}
|
%text {font-family: 'opensans-regular', Arial, Helvetica, sans-serif; line-height: 1.3rem;}
|
||||||
%bold {font-family: 'opensans-semibold', Arial, Helvetica, sans-serif;}
|
%bold {font-family: 'opensans-semibold', Arial, Helvetica, sans-serif;}
|
||||||
%taiga {font-family: 'taiga';}
|
%taiga {font-family: 'taiga';}
|
||||||
|
%mono {font-family: 'courier new', 'monospace';}
|
||||||
|
|
||||||
%lightbox {
|
%lightbox {
|
||||||
background: rgba($white, .95);
|
background: rgba($white, .95);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
@mixin slide($max, $overflow, $min: 0) {
|
@mixin slide($max, $overflow, $min: 0) {
|
||||||
max-height: $min;
|
max-height: $min;
|
||||||
transition: max-height .5s ease-in;
|
transition: max-height .5s ease-in;
|
||||||
#{$overflow}: hidden;
|
overflow: #{$overflow};
|
||||||
&.open {
|
&.open {
|
||||||
transition: max-height .5s ease-in;
|
transition: max-height .5s ease-in;
|
||||||
max-height: $max;
|
max-height: $max;
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
a {
|
a {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 1rem 0 1rem 1rem;
|
padding: 1rem 0 1rem 1rem;
|
||||||
&.active,
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.icon {
|
.icon {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
@ -19,6 +18,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.active {
|
||||||
|
.icon {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity .3s linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
.icon {
|
.icon {
|
||||||
color: $blackish;
|
color: $blackish;
|
||||||
float: right;
|
float: right;
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
.admin-webhooks {
|
||||||
|
.webhooks-table {
|
||||||
|
.row {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding: .5rem 0;
|
||||||
|
}
|
||||||
|
.row:hover {
|
||||||
|
.webhook-options-wrapper {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity .2s linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header {
|
||||||
|
@extend %bold;
|
||||||
|
border-bottom: 1px solid $gray-light;
|
||||||
|
}
|
||||||
|
.table-body {
|
||||||
|
.webhook-service {
|
||||||
|
color: $gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.single-webhook-wrapper {
|
||||||
|
border-bottom: 1px solid $whitish;
|
||||||
|
}
|
||||||
|
.webhooks-options {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webhook-service,
|
||||||
|
.webhook-url {
|
||||||
|
margin-right: .5rem;
|
||||||
|
}
|
||||||
|
.webhook-service {
|
||||||
|
flex-basis: 20%;
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
.webhook-url {
|
||||||
|
flex-basis: 400px;
|
||||||
|
flex-grow: 8;
|
||||||
|
span {
|
||||||
|
@include ellipsis($width: 65%);
|
||||||
|
color: $gray-light;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: $green-taiga;
|
||||||
|
margin-left: .5rem;
|
||||||
|
&:hover {
|
||||||
|
color: $fresh-taiga;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.webhook-options {
|
||||||
|
flex-basis: 100px;
|
||||||
|
flex-grow: 0;
|
||||||
|
min-width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
a {
|
||||||
|
color: $gray-light;
|
||||||
|
margin-right: .5rem;
|
||||||
|
transition: color .2s linear;
|
||||||
|
vertical-align: middle;
|
||||||
|
&:hover {
|
||||||
|
color: $green-taiga;
|
||||||
|
transition: color .2s linear;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.webhook-options-wrapper {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .3s linear;
|
||||||
|
}
|
||||||
|
.webhook-url-inputs {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
fieldset {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-right: .3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webhooks-history{
|
||||||
|
@include slide(1000px, hidden, $min: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-single-wrapper {
|
||||||
|
border-bottom: 1px solid $whitish;
|
||||||
|
margin-left: 22%;
|
||||||
|
}
|
||||||
|
.history-single {
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: .5rem;
|
||||||
|
transition: background .2s linear;
|
||||||
|
&:hover {
|
||||||
|
background: rgba($fresh-taiga, .1);
|
||||||
|
transition: background .2s linear;
|
||||||
|
}
|
||||||
|
&.history-single-open {
|
||||||
|
&:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.icon-arrow-bottom {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
transition: transform .3s linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon-arrow-bottom {
|
||||||
|
transform: rotate(0);
|
||||||
|
transition: transform .3s linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.history-response-icon {
|
||||||
|
background: $gray;
|
||||||
|
border-radius: 25%;
|
||||||
|
display: inline-block;
|
||||||
|
height: .8rem;
|
||||||
|
margin-right: .5rem;
|
||||||
|
width: .8rem;
|
||||||
|
&.history-success {
|
||||||
|
background: $fresh-taiga;
|
||||||
|
}
|
||||||
|
&.history-error {
|
||||||
|
background: $red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.history-single-response {
|
||||||
|
@include slide(1000px, hidden, $min: 0);
|
||||||
|
}
|
||||||
|
.history-single-request-header,
|
||||||
|
.history-single-response-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1.5rem 0 .5rem 0;
|
||||||
|
span:first-child {
|
||||||
|
@extend %bold;
|
||||||
|
color: $gray-light;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
@extend %small;
|
||||||
|
color: $gray-light;
|
||||||
|
&:hover {
|
||||||
|
color: $fresh-taiga;
|
||||||
|
transition: color .2s linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
margin-right: .3rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.history-single-request-body,
|
||||||
|
.history-single-response-body {
|
||||||
|
.response-container {
|
||||||
|
@extend %mono;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: $whitish;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
@extend %small;
|
||||||
|
color: $gray-light;
|
||||||
|
flex-basis: 20%;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
@extend %mono;
|
||||||
|
border: 0;
|
||||||
|
flex-grow: 2;
|
||||||
|
min-height: 7.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.history-single-response-body {
|
||||||
|
textarea {
|
||||||
|
min-height: 10rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@
|
||||||
textarea {
|
textarea {
|
||||||
height: 10rem;
|
height: 10rem;
|
||||||
}
|
}
|
||||||
.button-green {
|
.submit-button {
|
||||||
color: $white;
|
color: $white;
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -125,6 +125,7 @@ exports.files = function () {
|
||||||
'modules/admin/default-values',
|
'modules/admin/default-values',
|
||||||
'modules/admin/project-values',
|
'modules/admin/project-values',
|
||||||
'modules/admin/third-parties',
|
'modules/admin/third-parties',
|
||||||
|
'modules/admin/admin-third-parties-webhooks',
|
||||||
'modules/admin/contrib',
|
'modules/admin/contrib',
|
||||||
|
|
||||||
//Modules user Settings
|
//Modules user Settings
|
||||||
|
|
Loading…
Reference in New Issue