├── img
├── .gitkeep
├── Play.svg
├── Pause.svg
├── SelectOne.svg
├── icons
│ ├── Image.svg
│ ├── Container.svg
│ ├── Service.svg
│ ├── Controller.svg
│ ├── ReplicationController.svg
│ ├── Pod.svg
│ ├── Cluster.svg
│ ├── Process.svg
│ └── Node.svg
├── BackButton.svg
├── SelectMany.svg
├── Refresh.svg
├── Collapse.svg
├── Expand.svg
├── Search.svg
├── LiveData.svg
├── SampleData.svg
└── Pin.svg
├── js
├── .gitkeep
└── modules
│ ├── .gitkeep
│ ├── services
│ ├── .gitkeep
│ ├── inspectNodeService.js
│ ├── d3.js
│ ├── d3UtilitiesService.js
│ ├── viewModelService.js
│ └── d3RenderingService.js
│ ├── controllers
│ ├── .gitkeep
│ ├── inspectNode.js
│ └── graph.js
│ └── directives
│ ├── .gitkeep
│ └── d3.js
├── less
├── .gitkeep
└── graph.less
├── pages
├── .gitkeep
├── inspect.html
└── home.html
├── views
├── .gitkeep
└── partials
│ └── .gitkeep
├── protractor
├── .gitkeep
└── smoke.spec.js
├── test
└── modules
│ ├── controllers
│ ├── .gitkeep
│ ├── graph.spec.js
│ └── inspectNode.spec.js
│ ├── directives
│ ├── .gitkeep
│ └── d3.spec.js
│ └── services
│ ├── .gitkeep
│ ├── viewModelService.spec.js
│ ├── inspectNodeService.spec.js
│ ├── d3UtilitiesService.spec.js
│ └── d3RenderingService.spec.js
├── config
└── development.example.json
├── GraphTab.png
├── manifest.json
├── README.md
├── css
└── show-details-table.css
└── assets
├── legend.json
├── transforms.json
└── transforms
└── templateTransform.js
/img/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/js/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/less/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pages/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/views/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/js/modules/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/protractor/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/views/partials/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/js/modules/services/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/js/modules/controllers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/js/modules/directives/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/modules/controllers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/modules/directives/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/modules/services/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/config/development.example.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/GraphTab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kubernetes-ui/graph/HEAD/GraphTab.png
--------------------------------------------------------------------------------
/img/Play.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/Pause.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/SelectOne.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/icons/Image.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/BackButton.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/icons/Container.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/SelectMany.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/icons/Service.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/icons/Controller.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/icons/ReplicationController.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/Refresh.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/icons/Pod.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/Collapse.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/Expand.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/Search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/LiveData.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Force-directed graph for visualizing the Kubernetes cluster configuration and scheduling.",
3 | "routes": [
4 | {
5 | "description": "Force-directed graph visualization.",
6 | "url": "/",
7 | "templateUrl": "components/graph/pages/home.html"
8 | },
9 | {
10 | "description": "Inspection panel with detailed information about Kubernetes cluster entities.",
11 | "url": "/inspect",
12 | "templateUrl": "components/graph/pages/inspect.html",
13 | "css": "components/graph/css/show-details-table.css"
14 | }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/img/icons/Cluster.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/SampleData.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/modules/services/viewModelService.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | 'use strict';
18 |
19 | describe("View model service", function() { it("should work as intended", function() {}); });
20 |
--------------------------------------------------------------------------------
/test/modules/controllers/graph.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | 'use strict';
18 |
19 | describe("Graph controller", function() {
20 |
21 | beforeEach(module("kubernetesApp.components.graph"));
22 |
23 | it("should work as intended", function() {});
24 | });
25 |
--------------------------------------------------------------------------------
/img/Pin.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/icons/Process.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/icons/Node.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/modules/services/inspectNodeService.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | 'use strict';
18 |
19 | describe("Inspect node service", function() {
20 | var inspectNodeService;
21 |
22 | beforeEach(module('kubernetesApp.components.graph.services'));
23 | beforeEach(inject(function(_inspectNodeService_) { inspectNodeService = _inspectNodeService_; }));
24 |
25 | it("should set and get data as intended", function() {
26 | var data = {
27 | 'name': 'pod',
28 | 'id': 1
29 | };
30 | inspectNodeService.setDetailData(data);
31 | var getData = inspectNodeService.getDetailData();
32 | expect(data).toEqual(getData);
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/js/modules/services/inspectNodeService.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | /**=========================================================
18 | * Module: Graph
19 | * Visualizer for force directed graph
20 | * This is a service that shares node detals data among controllers.
21 | =========================================================*/
22 |
23 | (function() {
24 | 'use strict';
25 |
26 | var inspectNodeService = function() {
27 | var nodeDetails = null;
28 | var setDetailData = function(data) { nodeDetails = data; };
29 |
30 | var getDetailData = function() { return nodeDetails; };
31 |
32 | return {
33 | 'setDetailData': setDetailData,
34 | 'getDetailData': getDetailData
35 | };
36 | };
37 |
38 | angular.module('kubernetesApp.components.graph.services', []).factory('inspectNodeService', inspectNodeService);
39 |
40 | })();
41 |
--------------------------------------------------------------------------------
/pages/inspect.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | {{element}}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/js/modules/controllers/inspectNode.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | /**=========================================================
18 | * Module: Graph
19 | * Visualizer for force directed graph
20 | =========================================================*/
21 | (function() {
22 | 'use strict';
23 |
24 | angular.module('kubernetesApp.components.graph')
25 | .controller('InspectNodeCtrl', [
26 | '$scope',
27 | 'inspectNodeService',
28 | '$location',
29 | function($scope, inspectNodeService, $location) {
30 | var nodeDetail = inspectNodeService.getDetailData();
31 | $scope.element = nodeDetail.id;
32 | $scope.metadata = nodeDetail.metadata;
33 |
34 | $scope.backToGraph = function() {
35 | $location.path('/graph');
36 | $scope.$apply();
37 | };
38 | }
39 | ]);
40 |
41 | })();
42 |
--------------------------------------------------------------------------------
/js/modules/services/d3.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | angular.module('kubernetesApp.components.graph')
18 | .factory('d3Service', [
19 | '$document',
20 | '$q',
21 | '$rootScope',
22 | function($document, $q, $rootScope) {
23 | var d = $q.defer();
24 | function onScriptLoad() {
25 | // Load client in the browser
26 | $rootScope.$apply(function() { d.resolve(window.d3); });
27 | }
28 | // Create a script tag with d3 as the source
29 | // and call our onScriptLoad callback when it
30 | // has been loaded
31 | var scriptTag = $document[0].createElement('script');
32 | scriptTag.type = 'text/javascript';
33 | scriptTag.async = true;
34 | scriptTag.src = 'vendor/d3/d3.min.js';
35 | scriptTag.onreadystatechange = function() {
36 | if (this.readyState == 'complete') onScriptLoad();
37 | };
38 | scriptTag.onload = onScriptLoad;
39 |
40 | var s = $document[0].getElementsByTagName('body')[0];
41 | s.appendChild(scriptTag);
42 |
43 | return {
44 | d3: function() { return d.promise; }
45 | };
46 | }
47 | ]);
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Graph Component for Kubernetes WebUI
2 |
3 | This is the Graph component for the Kubernetes UI. It uses the [d3 Force Layout](https://github.com/mbostock/d3/wiki/Force-Layout) to expose the structure and organization of the cluster, creating renderings like this one:
4 |
5 | 
6 |
7 | It contains a legend that lets the user filter the types of objects displayed. Modifier keys let the user zoom the graph, and select or pin individual objects. Objects can also be inspected to display their available properties.
8 |
9 | ## Data Source
10 | By default, the data displayed by the Graph tab is collected from the Kubernetes api server and the Docker daemons, and assembled into a single JSON document exposed on a REST endpoint by the cluster-insight container available [here](https://registry.hub.docker.com/u/kubernetes/cluster-insight/) on DockerHub. Installation and usage instructions for the cotainer are provided [here](https://github.com/google/cluster-insight) on GitHub.
11 |
12 | The data are cached by the container and refreshed periodically to throttle the load on the cluster. The application can poll the container for the document continuously or on demand. When new contents are retrieved from the container, the application transforms them into the shape displayed on the canvas using a pluggable transform engine that loads transforms from the assets folder. The default transform is declarative; it interprets JSON documents loaded from the same location.
13 |
14 | Canned data is also available for use without cluster-insight. It's selectable using the 'cloud' button located above the canvas. The canned data is served from a file in the assets folder.
15 |
16 |
17 | []()
18 |
19 |
20 | []()
21 |
--------------------------------------------------------------------------------
/test/modules/controllers/inspectNode.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | 'use strict';
18 |
19 | describe("Inspect node controller", function() {
20 | var inspectNodeService = {};
21 | var scope, location, controller;
22 | var mockNodeDetail = {
23 | 'id': 1,
24 | 'metadata': 'data'
25 | };
26 | // Work around to get ngLodash correctly injected.
27 | beforeEach(function() {
28 | angular.module('testModule', ['ngLodash', 'kubernetesApp.components.graph', 'kubernetesApp.config']);
29 | });
30 |
31 | beforeEach(module('testModule'));
32 |
33 | beforeEach(inject(function(_inspectNodeService_, $controller, $location, $rootScope) {
34 | inspectNodeService = _inspectNodeService_;
35 | // Mock the node detail data returned by the service.
36 | inspectNodeService.setDetailData(mockNodeDetail);
37 | scope = $rootScope.$new();
38 | location = $location;
39 | controller = $controller('InspectNodeCtrl', {$scope: scope, $location: location});
40 | }));
41 |
42 | it("should work as intended", function() {
43 | // Test if the controller sets the correct model values.
44 | expect(scope.element).toEqual(mockNodeDetail.id);
45 | expect(scope.metadata).toEqual(mockNodeDetail.metadata);
46 |
47 | // Test if the controller changed the location correctly.
48 | scope.backToGraph();
49 | expect(location.path()).toEqual('/graph');
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/js/modules/directives/d3.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | /**=========================================================
18 | * Module: Graph
19 | * Visualizer for force directed graph.
20 | * This is a directive that uses d3 to generate an svg
21 | * element.
22 | =========================================================*/
23 |
24 | angular.module('kubernetesApp.components.graph')
25 | .directive('d3Visualization', [
26 | 'd3Service',
27 | 'd3RenderingService',
28 | function(d3Service, d3RenderingService) {
29 | return {
30 | restrict: 'E',
31 | link: function(scope, element, attrs) {
32 | scope.$watch('viewModelService.viewModel.version', function(newValue, oldValue) {
33 | if (!window.d3) {
34 | d3Service.d3().then(d3Rendering);
35 | } else {
36 | d3Rendering();
37 | }
38 | });
39 |
40 | scope.$watch('selectionIdList', function(newValue, oldValue) {
41 | if (newValue !== undefined) {
42 | // The d3Rendering.nodeSelection() method expects a set of objects, each with an id property.
43 | var nodes = new Set();
44 |
45 | newValue.forEach(function(e) { nodes.add({id: e}); });
46 |
47 | d3Rendering.nodeSelection(nodes);
48 | }
49 | });
50 |
51 | var d3Rendering = d3RenderingService.rendering().controllerScope(scope).directiveElement(element[0]);
52 | }
53 | };
54 | }
55 | ]);
56 |
--------------------------------------------------------------------------------
/less/graph.less:
--------------------------------------------------------------------------------
1 | .graph {
2 | .edgelabel {
3 | font: 12px sans-serif;
4 | paint-order: stroke;
5 | stroke: #ffffff;
6 | stroke-width: 3px;
7 | }
8 |
9 | .node text {
10 | pointer-events: none;
11 | font: 12px sans-serif;
12 | paint-order: stroke;
13 | stroke: #ffffff;
14 | stroke-width: 3px;
15 | }
16 | }
17 |
18 | .d3-context-menu {
19 | position: absolute;
20 | display: none;
21 | background-color: #f2f2f2;
22 | border-radius: 4px;
23 |
24 | font-family: Arial, sans-serif;
25 | font-size: 14px;
26 | min-width: 150px;
27 | border: 1px solid #d4d4d4;
28 |
29 | z-index:1200;
30 | }
31 |
32 | .d3-context-menu ul {
33 | list-style-type: none;
34 | margin: 4px 0px;
35 | padding: 0px;
36 | cursor: default;
37 | }
38 |
39 | .d3-context-menu ul li {
40 | padding: 4px 16px;
41 | }
42 |
43 | .d3-context-menu ul li:hover {
44 | background-color: #4677f8;
45 | color: #fefefe;
46 | }
47 |
48 | .details-table {
49 | width: 100%;
50 | border-collapse: collapse;
51 | }
52 |
53 | .details-table-content-row {
54 | width: 100%;
55 | }
56 |
57 | .details-table-content-tag {
58 | padding: 5px;
59 | white-space: pre-wrap;
60 | margin: 0px;
61 | }
62 |
63 | .details-table-content-value {
64 | padding: 5px;
65 | word-break: break-all;
66 | white-space: pre-wrap;
67 | margin: 0px;
68 | }
69 |
70 | .sidenav-card {
71 | margin: 0;
72 | }
73 |
74 | .sidenav-frame {
75 | padding: 0;
76 | }
77 |
78 | .legend-table {
79 | width: 100%;
80 | border-collapse: collapse;
81 | table-layout: fixed;
82 | margin-top: 6px;
83 | margin-bottom: 6px;
84 | }
85 |
86 | .legend-table-content-row {
87 | width: 100%;
88 | }
89 |
90 | .legend-table-icon {
91 | width: 34px;
92 | height: 34px;
93 | padding: 5px;
94 | }
95 |
96 | .legend-table-text {
97 | font-size: 12px;
98 | padding: 5px;
99 | word-break: break-all;
100 | vertical-align: center;
101 | }
102 |
103 | .bold {
104 | font-weight: 700;
105 | }
106 |
107 | .gray {
108 | color: gray;
109 | }
110 |
111 | .pin-cursor {
112 | cursor: url(../../components/graph/img/Pin.svg) 6 21, auto;
113 | }
114 |
115 | .zoom-cursor {
116 | cursor: -webkit-zoom-in;
117 | }
118 |
--------------------------------------------------------------------------------
/css/show-details-table.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Angular directive to convert JSON into human readable table. Inspired by https://github.com/marianoguerra/json.human.js.
3 | * @version v1.2.1 - 2014-12-22
4 | * @link https://github.com/yaru22/angular-json-human
5 | * @author Brian Park
6 | * @license MIT License, http://www.opensource.org/licenses/MIT
7 | */
8 | /**
9 | * DISCLAIMER: This CSS is copied from https://github.com/marianoguerra/json.human.js
10 | */
11 |
12 | .jh-root,
13 | .jh-type-object,
14 | .jh-type-array,
15 | .jh-key,
16 | .jh-value,
17 | .jh-root tr {
18 | font-size: 14px;
19 | -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
20 | -moz-box-sizing: border-box; /* Firefox, other Gecko */
21 | box-sizing: border-box; /* Opera/IE 8+ */
22 | }
23 |
24 | .jh-key,
25 | .jh-value {
26 | margin: 0;
27 | padding: 0.6em;
28 | }
29 |
30 | .jh-value {
31 | border-left: 1px solid #ddd;
32 | }
33 |
34 | .jh-type-bool,
35 | .jh-type-number {
36 | text-align: center;
37 | color: rgba(0,0,0,0.87);
38 | }
39 |
40 | .jh-type-string {
41 | color: rgba(0,0,0,0.87);
42 | }
43 |
44 | .jh-array-key {
45 | font-size: small;
46 | text-align: center;
47 | }
48 |
49 | .jh-object-key,
50 | .jh-array-key {
51 | color: #444;
52 | vertical-align: top;
53 | }
54 |
55 | .jh-type-object > tbody > tr:nth-child(odd),
56 | .jh-type-array > tbody > tr:nth-child(odd) {
57 | background-color: #f5f5f5;
58 | }
59 |
60 | .jh-type-object > tbody > tr:nth-child(even),
61 | .jh-type-array > tbody > tr:nth-child(even) {
62 | background-color: #fff;
63 | }
64 |
65 | .jh-type-object,
66 | .jh-type-array {
67 | width: 100%;
68 | border-collapse: collapse;
69 | }
70 |
71 | .jh-root {
72 | border: 1px solid #ccc;
73 | margin: 0.2em;
74 | }
75 |
76 | th.jh-key {
77 | text-align: left;
78 | }
79 |
80 | .jh-type-object > tbody > tr,
81 | .jh-type-array > tbody > tr {
82 | border: 1px solid #ddd;
83 | border-bottom: none;
84 | }
85 |
86 | .jh-type-object > tbody > tr:last-child,
87 | .jh-type-array > tbody > tr:last-child {
88 | border-bottom: 1px solid #ddd;
89 | }
90 |
91 | .jh-type-object > tbody > tr:hover,
92 | .jh-type-array > tbody > tr:hover {
93 | border: 1px solid rgb(63,81,181);
94 | }
95 |
96 | .jh-empty {
97 | color: #999;
98 | font-size: small;
99 | }
100 |
--------------------------------------------------------------------------------
/assets/legend.json:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "Container": {
4 | "style": {
5 | "size": [24, 24],
6 | "radius": 12,
7 | "icon": "components/graph/img/icons/Container.svg",
8 | "fill": "cornflowerblue",
9 | "stroke": "dimgray"
10 | },
11 | "selected": true,
12 | "available": true
13 | },
14 | "Cluster": {
15 | "style": {
16 | "size": [34, 34],
17 | "radius": 17,
18 | "icon": "components/graph/img/icons/Cluster.svg",
19 | "fill": "#D32F2F",
20 | "stroke": "dimgray"
21 | },
22 | "selected": false,
23 | "available": true
24 | },
25 | "Node": {
26 | "style": {
27 | "size": [34, 34],
28 | "radius": 17,
29 | "icon": "components/graph/img/icons/Node.svg",
30 | "fill": "#FF4D81",
31 | "stroke": "dimgray"
32 | },
33 | "selected": false,
34 | "available": true
35 | },
36 | "Process": {
37 | "style": {
38 | "size": [24, 24],
39 | "radius": 12,
40 | "icon": "components/graph/img/icons/Process.svg",
41 | "fill": "#FF9800",
42 | "stroke": "dimgray"
43 | },
44 | "selected": false,
45 | "available": true
46 | },
47 | "Service": {
48 | "style": {
49 | "size": [30, 30],
50 | "radius": 15,
51 | "icon": "components/graph/img/icons/Service.svg",
52 | "fill": "#7C4DFF",
53 | "stroke": "dimgray"
54 | },
55 | "selected": true,
56 | "available": true
57 | },
58 | "ReplicationController": {
59 | "displayName": "Replication Controller",
60 | "style": {
61 | "size": [30, 30],
62 | "radius": 15,
63 | "icon": "components/graph/img/icons/ReplicationController.svg",
64 | "fill": "#DE2AFB",
65 | "stroke": "dimgray"
66 | },
67 | "selected": true,
68 | "available": true
69 | },
70 | "Pod": {
71 | "style": {
72 | "size": [30, 30],
73 | "radius": 15,
74 | "icon": "components/graph/img/icons/Pod.svg",
75 | "fill": "#E91E63",
76 | "stroke": "dimgray"
77 | },
78 | "selected": true,
79 | "available": true
80 | },
81 | "Image": {
82 | "style": {
83 | "size": [24, 24],
84 | "radius": 12,
85 | "icon": "components/graph/img/icons/Image.svg",
86 | "fill": "#D1C4E9",
87 | "stroke": "dimgray"
88 | },
89 | "selected": false,
90 | "available": true
91 | }
92 | },
93 | "links": {
94 | "contains": {
95 | "available": true,
96 | "style": {
97 | "dash": "1, 1",
98 | "width": 1,
99 | "stroke": "gray",
100 | "distance": 10
101 | }
102 | },
103 | "runs": {
104 | "available": true,
105 | "style": {
106 | "dash": "5, 5",
107 | "width": 1,
108 | "stroke": "#FF4D81",
109 | "distance": 10
110 | }
111 | },
112 | "balances": {
113 | "available": true,
114 | "style": {
115 | "width": 1,
116 | "stroke": "#7C4DFF",
117 | "dash": "5, 5",
118 | "distance": 15
119 | }
120 | },
121 | "uses": {
122 | "available": true,
123 | "style": {
124 | "width": 1,
125 | "stroke": "#D1C4E9",
126 | "dash": "5, 5",
127 | "distance": 15
128 | }
129 | },
130 | "monitors": {
131 | "available": true,
132 | "style": {
133 | "width": 1,
134 | "stroke": "#DE2AFB",
135 | "dash": "5, 5",
136 | "distance": 15
137 | }
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/test/modules/directives/d3.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2015 Google Inc. All rights reserved.
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 | 'use strict';
18 |
19 | describe('D3 directive', function() {
20 | var $compile;
21 | var $rootScope;
22 | var viewModelService;
23 |
24 | var MOCK_SAMPLE_DATA = [{
25 | 'nodes': [
26 | {'name': 'service: guestbook', 'radius': 16, 'fill': 'olivedrab', 'id': 5},
27 | {'name': 'pod: guestbook-controller', 'radius': 20, 'fill': 'palegoldenrod', 'id': 2},
28 | ],
29 | 'links': [],
30 | 'configuration': {'settings': {'clustered': false, 'showEdgeLabels': true, 'showNodeLabels': true}}
31 | }];
32 |
33 | // Work around to get ngLodash correctly injected.
34 | beforeEach(function() { angular.module('testModule', ['ngLodash', 'kubernetesApp.components.graph']); });
35 |
36 | beforeEach(module('testModule'));
37 |
38 | beforeEach(inject(function(_$compile_, _$rootScope_, _viewModelService_) {
39 | $compile = _$compile_;
40 | $rootScope = _$rootScope_;
41 | viewModelService = _viewModelService_;
42 | }));
43 |
44 | it('should replace the element with the appropriate svg content in response to the viewModel being set', function() {
45 | // Compile some HTML containing the directive.
46 | var element = $compile('
')($rootScope);
47 |
48 | $rootScope.viewModelService = viewModelService;
49 |
50 | // Test that the element hasn't been compiled yet.
51 | expect(element.html()).toEqual('');
52 |
53 | // Request the viewModelService to update the view model with the specified data.
54 | viewModelService.setViewModel(MOCK_SAMPLE_DATA[0]);
55 |
56 | // Test that the element still hasn't been compiled yet.
57 | expect(element.html()).toEqual('');
58 |
59 | // Fire all the watches.
60 | $rootScope.$digest();
61 |
62 | // Test that the element has been compiled and contains the svg content.
63 | expect(element.html()).toContain('