Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit 8ea4bee

Browse files
BoykoAlexghillert
authored andcommitted
Read-only stream graph definition and deploy state graph colouring
1 parent 2d55d83 commit 8ea4bee

File tree

8 files changed

+266
-10
lines changed

8 files changed

+266
-10
lines changed

ui/app/images/collapsed.svg

Lines changed: 3 additions & 0 deletions
Loading

ui/app/images/expanded.svg

Lines changed: 3 additions & 0 deletions
Loading

ui/app/scripts/stream/controllers.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ define(['angular'], function (angular) {
4242
$injector.invoke(createStreamsDialogController, this, {'$scope': $scope, '$modalInstance': $modalInstance, 'definitionData': definitionData});
4343
});
4444
}])
45+
.controller('StreamController',
46+
['$scope','$injector', function ($scope, $injector) {
47+
require(['stream/controllers/stream'], function (streamController) {
48+
$injector.invoke(streamController, this, {'$scope': $scope});
49+
});
50+
}])
4551
.controller('PropertiesDialogController',
4652
['$scope','$injector', '$modalInstance', 'cell', 'streamInfo', function ($scope, $injector, $modalInstance, cell, streamInfo) {
4753
require(['stream/controllers/properties-dialog'], function (propertiesDialogController) {

ui/app/scripts/stream/controllers/definitions.js

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2014 the original author or authors.
2+
* Copyright 2013-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,11 +18,17 @@
1818
* Stream Definition controller
1919
*
2020
* @author Ilayaperumal Gopinathan
21+
* @author Alex Boyko
2122
*/
2223
define(['model/pageable'], function (Pageable) {
2324
'use strict';
24-
return ['$scope', 'StreamService', 'DataflowUtils', '$timeout', '$rootScope', '$state',
25-
function ($scope, streamService, utils, $timeout, $rootScope, $state) {
25+
26+
var EXPANDED_STATE_COOKIE_KEY = 'stremDefs.expandedState';
27+
28+
return ['$scope', 'StreamService', 'DataflowUtils', '$timeout', '$rootScope', '$state', '$cookieStore',
29+
function ($scope, streamService, utils, $timeout, $rootScope, $state, $cookieStore) {
30+
31+
var getStreamDefinitions;
2632

2733
function loadStreamDefinitions(pageable, showGrowl) {
2834
//utils.$log.info('pageable', pageable);
@@ -37,7 +43,7 @@ define(['model/pageable'], function (Pageable) {
3743
$scope.pageable.items = result._embedded.streamDefinitionResourceList;
3844
}
3945
$scope.pageable.total = result.page.totalElements;
40-
var getStreamDefinitions = $timeout(function() {
46+
getStreamDefinitions = $timeout(function() {
4147
loadStreamDefinitions($scope.pageable, false);
4248
}, $rootScope.pageRefreshTime);
4349
$scope.$on('$destroy', function(){
@@ -49,11 +55,37 @@ define(['model/pageable'], function (Pageable) {
4955
);
5056
}
5157

58+
var expandedState = $cookieStore.get(EXPANDED_STATE_COOKIE_KEY) || {};
59+
5260
$scope.pageable = new Pageable();
5361
$scope.pagination = {
5462
current: 1
5563
};
5664

65+
$scope.toggleExpanded = function(name) {
66+
if (expandedState[name]) {
67+
delete expandedState[name];
68+
} else {
69+
expandedState[name] = true;
70+
}
71+
};
72+
73+
$scope.isExpanded = function(name) {
74+
return expandedState[name];
75+
};
76+
77+
$scope.collapsePage = function() {
78+
$scope.pageable.items.forEach(function(item) {
79+
delete expandedState[item.name];
80+
});
81+
};
82+
83+
$scope.expandPage = function() {
84+
$scope.pageable.items.forEach(function(item) {
85+
expandedState[item.name] = true;
86+
});
87+
};
88+
5789
$scope.pageChanged = function(newPage) {
5890
$scope.pageable.pageNumber = newPage-1;
5991
loadStreamDefinitions($scope.pageable);
@@ -84,6 +116,7 @@ define(['model/pageable'], function (Pageable) {
84116
streamService.destroy(streamDefinition).$promise.then(
85117
function () {
86118
utils.growl.success('Destroy Request Sent.');
119+
delete expandedState[streamDefinition.name];
87120
streamDefinition.inactive = true;
88121
$scope.closeModal();
89122
},
@@ -94,6 +127,18 @@ define(['model/pageable'], function (Pageable) {
94127
);
95128
};
96129

130+
$scope.$on('$destroy', function() {
131+
if (Object.keys(expandedState).length === 0) {
132+
$cookieStore.remove(EXPANDED_STATE_COOKIE_KEY);
133+
} else {
134+
$cookieStore.put(EXPANDED_STATE_COOKIE_KEY, expandedState);
135+
}
136+
if (getStreamDefinitions) {
137+
$timeout.cancel(getStreamDefinitions);
138+
}
139+
});
140+
97141
loadStreamDefinitions($scope.pageable);
142+
98143
}];
99144
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright 2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
define(function (require) {
18+
'use strict';
19+
20+
var joint = require('joint');
21+
22+
var ANIMATION_DURATION = 1500;
23+
24+
var statusToFilter = {
25+
undeployed: 'grayscale',
26+
deploying: 'grayscale',
27+
partial: 'grayscale',
28+
incomplete: 'orangescale',
29+
failed: 'redscale'
30+
};
31+
32+
return ['$scope', function ($scope) {
33+
34+
function isFlashing() {
35+
return $scope.item.status === 'deploying' || $scope.item.status === 'partial';
36+
}
37+
38+
// End of transition callback
39+
function endTransition(cell, transition) {
40+
// Consider only at animations that are done on appropriate color filter
41+
if (transition === 'attrs/.shape/filter/args/amount') {
42+
// Color filter turned off -> remove colour filter
43+
if (cell.attr('.shape/filter/args/amount') === 0) {
44+
cell.attr('.shape/filter', null);
45+
}
46+
// Remove end of transition event callback
47+
cell.off('transition:end', endTransition);
48+
if (isFlashing()) {
49+
// Switch on/off colour filter if shape should be flashing
50+
transitionFilter(cell, cell.attr('.shape/filter') ? undefined : statusToFilter[$scope.item.status]);
51+
}
52+
}
53+
}
54+
55+
// Stop colour filter animation
56+
function stopAnimation(cell) {
57+
// Remove end of transition event callback
58+
cell.off('transition:end', endTransition);
59+
// Stop the colour filter animation
60+
cell.stopTransitions('attrs/.shape/filter/args/amount');
61+
}
62+
63+
// Transitions between filters applying animation where appropriate
64+
function transitionFilter(cell, newFilter) { // jshint ignore:line
65+
var oldFilter = cell.attr('.shape/filter/name');
66+
if (newFilter !== oldFilter) {
67+
if (!oldFilter) {
68+
stopAnimation(cell);
69+
cell.attr('.shape/filter', {name: newFilter, args: {amount: 0}});
70+
cell.transition('attrs/.shape/filter/args/amount', 1, {
71+
delay: 0,
72+
duration: ANIMATION_DURATION,
73+
valueFunction: joint.util.interpolate.number,
74+
timingFunction: joint.util.timing.quad
75+
});
76+
cell.on('transition:end', endTransition);
77+
} else if (!newFilter) {
78+
// Ensure that filter amount is set explicitly!
79+
stopAnimation(cell);
80+
cell.attr('.shape/filter/args/amount', 1);
81+
cell.transition('attrs/.shape/filter/args/amount', 0, {
82+
delay: 0,
83+
duration: ANIMATION_DURATION,
84+
valueFunction: joint.util.interpolate.number,
85+
timingFunction: joint.util.timing.quad
86+
});
87+
cell.on('transition:end', endTransition);
88+
} else {
89+
cell.attr('.shape/filter', {name: newFilter});
90+
}
91+
}
92+
}
93+
94+
// Initial setting of the colour feedback for an app shape
95+
function initAppColouring(cell) {
96+
// Check if it one the apps, destination or tap shapes
97+
if (cell.attr('metadata/group')) {
98+
// Stop any color filter animation if there is any in progress
99+
stopAnimation(cell);
100+
// Unset color filter
101+
cell.removeAttr('.shape/filter');
102+
var status = $scope.item.status;
103+
var filter = statusToFilter[status];
104+
// If filter needs to be applied, do so.
105+
if (filter) {
106+
if (isFlashing()) {
107+
// If shape needs to be flashed, start animation of the color filter.
108+
transitionFilter(cell, filter);
109+
} else {
110+
// Otherwise, set the colour filter
111+
cell.attr('.shape/filter', {name: filter});
112+
}
113+
}
114+
}
115+
}
116+
117+
// Assign the right color filter to graph cells based on module status
118+
// Graph is populated once meta-model promise is resolved, hence at this moment there might be no graph
119+
// contents. Therefore, just add a listener to track when cells are added to the graph and adjust the color
120+
// filter for the newly added cell.
121+
$scope.flo.getGraph().on('add', function (cell) {
122+
initAppColouring(cell);
123+
});
124+
125+
$scope.$watch(function () {
126+
return $scope.item.status;
127+
}, function (newValue, oldValue) {
128+
if (newValue !== oldValue) {
129+
$scope.flo.getGraph().getElements().forEach(function (cell) {
130+
transitionFilter(cell, statusToFilter[$scope.item.status]);
131+
});
132+
}
133+
});
134+
135+
$scope.flo.getGraph().getElements().forEach(function (cell) {
136+
initAppColouring(cell);
137+
});
138+
139+
}];
140+
});

ui/app/scripts/stream/views/definitions.html

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
<div class="row">
22
<div class="col-md-12">
33
<div class="col-md-12 table-filter">
4-
<div class="col-md-4 col-md-offset-8">
5-
<input type="text" class="form-control" ng-model="filterQuery" id="filterTable"
6-
placeholder="Quick filter">
7-
</div>
4+
<table class="col-lg-12 tab-content-header">
5+
<tr>
6+
<td class="col-xs-8">
7+
<button type="button" ng-click="expandPage();"
8+
class="btn btn-default"
9+
><span class="glyphicon glyphicon-collapse-down"></span>
10+
Expand All
11+
</button>
12+
<button type="button" ng-click="collapsePage();"
13+
class="btn btn-default"
14+
><span class="glyphicon glyphicon-expand"></span>
15+
Collapse All
16+
</button>
17+
</td>
18+
<td>
19+
<input type="text" class="form-control" ng-model="filterQuery" id="filterTable"
20+
placeholder="Quick filter">
21+
</td>
22+
</tr>
23+
</table>
824
</div>
925
</div>
1026
</div>
11-
<table class="table table-striped table-hover">
27+
<table class="table table-double-striped table-hover">
1228
<thead>
1329
<tr>
30+
<th></th>
1431
<th>Name</th>
1532
<th>Definition</th>
1633
<th>Status <a class="status-help" dataflow-popover=".status-help-content" title="Available Deployment Statuses"><span class="glyphicon glyphicon-question-sign"></span></a></th>
@@ -19,7 +36,10 @@
1936
</thead>
2037
<tbody>
2138

22-
<tr dir-paginate="item in pageable.items | itemsPerPage: pageable.pageSize | filter:filterQuery" total-items="pageable.total" ng-show="!item.inactive">
39+
<tr dir-paginate-start="item in pageable.items | itemsPerPage: pageable.pageSize | filter:filterQuery track by item.name" total-items="pageable.total" ng-show="!item.inactive">
40+
<td>
41+
<button class="collapse-handle-button" ng-click="toggleExpanded(item.name)" ng-class="{on:isExpanded(item.name)}"></button>
42+
</td>
2343
<td>{{item.name}}</td>
2444
<td>{{item.dslText}}</td>
2545
<td>{{item.status}}</td>
@@ -44,6 +64,12 @@
4464
</button>
4565
</td>
4666
</tr>
67+
<tr dir-paginate-end ng-show="!item.inactive">
68+
<td ng-if="isExpanded(item.name)" colspan="7" ng-class="{undeployed: item.status !== 'deployed'}">
69+
<flo-editor ng-controller="StreamController" init-read-only-canvas="true" metamodel-service-name="StreamMetamodelService" render-service-name="StreamRenderService" init-read-only-canvas="true"
70+
ng-init="paperPadding=65; definition.text=item.dslText; flo.noPalette=true; canvasControls={zoom:true};"></flo-editor>
71+
</td>
72+
</tr>
4773
</tbody>
4874
</table>
4975
<dir-pagination-controls template-url="scripts/directives/dirPagination.tpl.html"

ui/app/styles/flo.less

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,12 @@ input.btn.ng-invalid {
302302
.IntNode .box {
303303
stroke: @spring-green;
304304
}
305+
306+
.table .flow-view {
307+
height: 225px;
308+
}
309+
310+
.undeployed .canvas {
311+
border-color: @spring-grey;
312+
}
313+

ui/app/styles/main.less

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,30 @@ hr {
363363
margin: 5px 0px 5px 0px;
364364
}
365365

366+
.collapse-handle-button {
367+
width: 24px;
368+
height: 24px;
369+
background: transparent url(../images/collapsed.svg) no-repeat;
370+
border: 0px;
371+
outline: none;
372+
}
373+
374+
.collapse-handle-button.on {
375+
background-image: url(../images/expanded.svg);
376+
}
377+
378+
.table-double-striped > tbody > tr:nth-child(4n-1) > td {
379+
background-color: @spring-light-grey;
380+
}
381+
382+
.table-double-striped > tbody > tr:nth-child(4n) > td {
383+
background-color: @spring-light-grey;
384+
}
385+
386+
.table-double-striped > tbody > tr:nth-child(2n) > td {
387+
border-top-width: 0px;
388+
}
389+
366390
@import (less) "../lib/spring-flo/spring-flo.css";
367391

368392
@import "analytics.less";

0 commit comments

Comments
 (0)