diff --git a/public/css/octocat.less b/public/css/octocat.less new file mode 100644 index 00000000..58848822 --- /dev/null +++ b/public/css/octocat.less @@ -0,0 +1,33 @@ +.github-corner svg { + position: fixed; + left: 0; + bottom: 0; + transform: rotate(360deg) scale(-1,-1); + mix-blend-mode: darken; + color: #ffffff; + fill: #000000; +} +.octo-body { + transform: rotate(-226deg) translate(-250px, -260px); +} +.octo-arm { + transform: rotate(-226deg) translate(-250px, -260px); +} +.github-corner:hover .octo-arm { + animation:octocat-wave .56s; +} + +@keyframes octocat-wave { + 0%, + 100% { + transform: rotate(-226deg) translate(-250px, -260px); + } + 20%, + 60% { + transform: rotate(-227deg) translate(-250px, -260px); + } + 40%, + 80% { + transform: rotate(-226deg) translate(-250px, -260px); + } +} \ No newline at end of file diff --git a/public/css/semaphore.css b/public/css/semaphore.css index 36318ff5..e4cb3cfd 100644 --- a/public/css/semaphore.css +++ b/public/css/semaphore.css @@ -9548,6 +9548,41 @@ button.close { .login-page { margin-top: 30vh; } +.github-corner svg { + position: fixed; + left: 0; + bottom: 0; + transform: rotate(360deg) scale(-1, -1); + mix-blend-mode: darken; + color: #ffffff; + fill: #000000; +} +.octo-body { + transform: rotate(-226deg) translate(-250px, -260px); +} +.octo-arm { + transform: rotate(-226deg) translate(-250px, -260px); +} +.github-corner:hover .octo-arm { + animation: octocat-wave 0.56s; +} +@keyframes octocat-wave { + 0%, + 100% { + transform: rotate(-226deg) translate(-250px, -260px); + } + 20%, + 60% { + transform: rotate(-227deg) translate(-250px, -260px); + } + 40%, + 80% { + transform: rotate(-226deg) translate(-250px, -260px); + } +} +body { + padding-bottom: 75px; +} input, button.btn { font-weight: 300; @@ -9579,35 +9614,15 @@ h6.no-top-margin { ul.nav > li.active a { background-color: #eee; } -.github-corner svg { - position: absolute; - left: 0; - bottom: 0; - transform: rotate(360deg) scale(-1, -1); - mix-blend-mode: darken; - color: #ffffff; - fill: #000000; +ul.nav.nav-pills li > a { + border-bottom: 1px solid #EEE; } -.octo-body { - transform: rotate(-226deg) translate(-250px, -260px); +ul.nav.nav-pills li > a:hover { + background: none; + border-bottom: 1px solid #00ab54; } -.octo-arm { - transform: rotate(-226deg) translate(-250px, -260px); -} -.github-corner:hover .octo-arm { - animation: octocat-wave 0.56s; -} -@keyframes octocat-wave { - 0%, - 100% { - transform: rotate(-226deg) translate(-250px, -260px); - } - 20%, - 60% { - transform: rotate(-227deg) translate(-250px, -260px); - } - 40%, - 80% { - transform: rotate(-226deg) translate(-250px, -260px); - } +ul.nav.nav-pills li.active > a { + background: none; + border-bottom: 1px solid #0058ab; + color: #003e78; } diff --git a/public/css/semaphore.less b/public/css/semaphore.less index 83495a2a..a056d575 100644 --- a/public/css/semaphore.less +++ b/public/css/semaphore.less @@ -26,6 +26,11 @@ @import (less) '../vendor/sweetalert/sweetalert.css'; @import 'login.less'; +@import 'octocat.less'; + +body { + padding-bottom: 75px; +} input, button.btn { font-weight: @headings-font-weight; @@ -59,36 +64,17 @@ ul.nav { } } -.github-corner svg{ - position: absolute; - left: 0; - bottom: 0; - transform: rotate(360deg) scale(-1,-1); - mix-blend-mode: darken; - color: #ffffff; - fill: #000000; -} -.octo-body { - transform: rotate(-226deg) translate(-250px, -260px); -} -.octo-arm { - transform: rotate(-226deg) translate(-250px, -260px); -} -.github-corner:hover .octo-arm{ - animation:octocat-wave .56s; +ul.nav.nav-pills li > a { + border-bottom: 1px solid #EEE; } -@keyframes octocat-wave { - 0%, - 100% { - transform: rotate(-226deg) translate(-250px, -260px); - } - 20%, - 60% { - transform: rotate(-227deg) translate(-250px, -260px); - } - 40%, - 80% { - transform: rotate(-226deg) translate(-250px, -260px); - } +ul.nav.nav-pills li > a:hover { + background: none; + border-bottom: 1px solid @brand-primary; } + +ul.nav.nav-pills li.active > a { + background: none; + border-bottom: 1px solid @brand-success; + color: darken(@brand-success, 10%); +} \ No newline at end of file diff --git a/public/html/projects/add.jade b/public/html/projects/add.jade index 71c172fe..1046c9ee 100644 --- a/public/html/projects/add.jade +++ b/public/html/projects/add.jade @@ -1,13 +1,13 @@ .modal-header - h4.modal-title Add Project + h4.modal-title New Project .modal-body form.form-horizontal .form-group - label.control-label.col-sm-4 Name + label.control-label.col-sm-4 Project Name .col-sm-6 input.form-control(type="text" placeholder="Project Name" ng-model="project.name" required) .modal-footer button.btn.btn-default.pull-left(ng-click="$dismiss()") Dismiss - button.btn.btn-success(ng-click="$close(project)") Save \ No newline at end of file + button.btn.btn-success(ng-click="$close(project)") Create \ No newline at end of file diff --git a/public/html/projects/container.jade b/public/html/projects/container.jade index 603f28aa..9573d1c9 100644 --- a/public/html/projects/container.jade +++ b/public/html/projects/container.jade @@ -1,14 +1,14 @@ .container-fluid: .row .col-sm-4.col-md-3 h3.no-top-margin {{ project.name }} - ul.list-group - li.list-group-item: a(ui-sref="project.dashboard") Dashboard - li.list-group-item: a(ui-sref="project.templates") Task Templates - li.list-group-item: a(ui-sref="project.inventory") Inventory - li.list-group-item: a(ui-sref="project.environment") Environment - li.list-group-item: a(ui-sref="project.keys") Key Store - li.list-group-item: a(ui-sref="project.repositories") Playbook Repositories - //- li.list-group-item: a(ui-sref="project.schedule") Task Schedule - li.list-group-item: a(ui-sref="project.users") Team + ul.nav.nav-pills.nav-stacked + li(ng-class="{ active: $state.includes('project.dashboard') }"): a(ui-sref="project.dashboard") Dashboard + li(ng-class="{ active: $state.includes('project.templates') }"): a(ui-sref="project.templates") Task Templates + li(ng-class="{ active: $state.includes('project.inventory') }"): a(ui-sref="project.inventory") Inventory + li(ng-class="{ active: $state.includes('project.environment') }"): a(ui-sref="project.environment") Environment + li(ng-class="{ active: $state.includes('project.keys') }"): a(ui-sref="project.keys") Key Store + li(ng-class="{ active: $state.includes('project.repositories') }"): a(ui-sref="project.repositories") Playbook Repositories + //- li(ng-class="{ active: $state.includes('project.schedule') }"): a(ui-sref="project.schedule") Task Schedule + li(ng-class="{ active: $state.includes('project.users') }"): a(ui-sref="project.users") Team .col-sm-8.col-md-9 ui-view \ No newline at end of file diff --git a/public/html/projects/dashboard.jade b/public/html/projects/dashboard.jade index 20659f7e..3fdca984 100644 --- a/public/html/projects/dashboard.jade +++ b/public/html/projects/dashboard.jade @@ -10,8 +10,8 @@ span {{ event.description }} .col-sm-5 h4.no-top-margin Task history - ul.list-group - li.list-group-item(ng-repeat="task in tasks"): a(ng-click="openTask(task)" href="#") + ul.nav.nav-pills.nav-stacked + li(ng-repeat="task in tasks"): a(ng-click="openTask(task)" href="#") i.fa.fa-fw.fa-clock-o.text-warning(ng-if="task.status == 'waiting'") i.fa.fa-fw.fa-times.text-danger(ng-if="task.status == 'error'") i.fa.fa-fw.fa-check.text-success(ng-if="task.status == 'success'") diff --git a/public/js/controllers/projects/taskRunner.js b/public/js/controllers/projects/taskRunner.js index 5d450e5a..ef0ad075 100644 --- a/public/js/controllers/projects/taskRunner.js +++ b/public/js/controllers/projects/taskRunner.js @@ -7,6 +7,7 @@ define(function () { task.template_id = Template.id; $http.post(Project.getURL() + '/tasks', task).success(function (t) { + $scope.$close(t); }).error(function (_, status) { swal('Error', 'error launching task: HTTP ' + status, 'error'); }); @@ -15,7 +16,10 @@ define(function () { app.registerController('TaskCtrl', ['$scope', '$http', function ($scope, $http) { $scope.$on('remote.log', function (evt, data) { - $scope.output_formatted.splice(0, 0, data); + console.log('data'); + $scope.output_formatted += moment(data.time).format('HH:mm:ss') + ': ' + data.output + '\n'; + + if (!$scope.$$phase) $scope.$digest(); }); $http.get($scope.project.getURL() + '/tasks/' + $scope.task.id + '/output') diff --git a/public/js/controllers/projects/templates.js b/public/js/controllers/projects/templates.js index 4503e748..d1b67248 100644 --- a/public/js/controllers/projects/templates.js +++ b/public/js/controllers/projects/templates.js @@ -78,6 +78,17 @@ define(['controllers/projects/taskRunner'], function () { return tpl; } } + }).result.then(function (task) { + var scope = $rootScope.$new(); + scope.task = task; + scope.project = Project; + + $modal.open({ + templateUrl: '/tpl/projects/taskModal.html', + controller: 'TaskCtrl', + scope: scope, + size: 'lg' + }); }) } diff --git a/routes/tasks/logging.go b/routes/tasks/logging.go index a6d84c89..610bb861 100644 --- a/routes/tasks/logging.go +++ b/routes/tasks/logging.go @@ -4,6 +4,7 @@ import ( "bufio" "encoding/json" "os/exec" + "time" "github.com/ansible-semaphore/semaphore/database" "github.com/ansible-semaphore/semaphore/routes/sockets" @@ -13,7 +14,8 @@ func (t *task) log(msg string) { for _, user := range t.users { b, err := json.Marshal(&map[string]interface{}{ "type": "log", - "m": msg, + "output": msg, + "time": time.Now(), "task_id": t.task.ID, "project_id": t.projectID, })