Remove the "www" and "third-party ui" directories from kubernetes repository
* This code now lives in the kube-ui repository.
189
www/README.md
@@ -1,188 +1 @@
|
||||
# Working with the Kubernetes UI
|
||||
This document explains how to work with the Kubernetes UI. For information on how to access and use it, see [docs/user-guide/ui.md](../docs/user-guide/ui.md).
|
||||
|
||||
## Installing dependencies
|
||||
There are two kinds of dependencies in the UI project: tools and frameworks. The tools help
|
||||
us manage and test the application. They are not part of the application. The frameworks, on the other hand, become part of the application, as described below.
|
||||
|
||||
* We get the tools via `npm`, the [node package manager](https://www.npmjs.com/).
|
||||
* We get the frameworks via `bower`, a [client-side package manager](http://bower.io/).
|
||||
|
||||
Before you build the application for the first time, run this command from the `www/master` directory:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
It creates a new directory, `www/master/node_modules`, which contains the tool dependencies.
|
||||
|
||||
## Building and serving the app
|
||||
|
||||
### Building the app for development
|
||||
To build the application for development, run this command from the `www/master` directory:
|
||||
|
||||
```
|
||||
npm start
|
||||
```
|
||||
|
||||
It runs `bower install` to install and/or update the framework dependencies, and then `gulp`, a [JavaScript build system](http://gulpjs.com/), to generate a development version of the application.
|
||||
|
||||
Bower creates a new directory, `third_party/ui/bower_components`, which contains the framework dependencies. Each of them should be referenced in one of the `vendor.json` files below:
|
||||
|
||||
* `www/master/vendor.base.json` - 3rd party vendor javascript files required to start the app. All of the dependencies referenced by this file are compiled into `base.js` and loaded before `app.js`.
|
||||
* `www/master/vendor.json` - 3rd party vendor js or css files required to make the app work, usually by lazy loading. All of the dependencies referenced by this file are compiled into `www/app/vendor`. (Note: some framework dependencies have been hand edited and checked into source control under `www/master/shared/vendor`.)
|
||||
|
||||
The default `gulp` target builds the application for development (e.g., without uglification of js files or minification of css files), and then starts a file watcher that rebuilds the generated files every time the source files are updated. (Note: the file watcher does not support adding or deleting files. It must be stopped and restarted to pick up additions or deletions).
|
||||
|
||||
The `www/app` directory and its contents are generated by the build. All of the other files under `www` are source or project files, such as tests, scripts, documentation and package manifests. (Note: the build output checked into source control is the production version, built with uglification and minification, as described below, so expect the build output to change if you build for development.)
|
||||
|
||||
### Serving the app during development
|
||||
|
||||
For development you can serve the files locally by installing a web server as follows:
|
||||
|
||||
```
|
||||
sudo npm install -g http-server
|
||||
```
|
||||
|
||||
The server can then be launched from the `www/app` directory as follows:
|
||||
|
||||
```
|
||||
cd www/app
|
||||
http-server -a localhost -p 8001
|
||||
```
|
||||
|
||||
`http-server` is convenient, since we're already using `npm`, but any web server hosting the `www/app` directory should work.
|
||||
|
||||
Note that you'll need to tell the application where to find the api server by setting the value of the `k8sApiServer` configuration parameter in `www/master/shared/config/development.json` and then rebuilding the application. For example, for a cluster running locally at `localhost:8080`, as described [here](../docs/getting-started-guides/locally.md), you'll want to set it as follows:
|
||||
|
||||
```
|
||||
"k8sApiServer": "http://localhost:8080/api/v1"
|
||||
```
|
||||
|
||||
### Building the app for production
|
||||
To build the application for production, run this command from the `www/master` directory:
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
Like `npm start`, it runs `bower install` to install and/or update the framework dependencies, but then it runs `gulp build` to generate a production version of the application. The `build` target builds the application for production (e.g., with uglification of js files and minification of css files), and does not run a file watcher, so that it can be used in automated build environments.
|
||||
|
||||
To make the production code available to the Kubernetes api server, run this command from the top level directory:
|
||||
|
||||
```
|
||||
hack/build-ui.sh dashboard
|
||||
```
|
||||
|
||||
It runs the `go-bindata` tool to package the generated `app` directory into `pkg/ui/data/dashboard/datafile.go`. It can also be used to package other user interface content, such as the Swagger documentation. Note: go-bindata can be installed with `go get github.com/jteeuwen/go-bindata/...`.
|
||||
|
||||
Then, run `make kube-ui` in the `cluster/addons/kube-ui/image` directory to build a new `kube-ui` binary that includes the updated `datafile.go`. When the updated UI is ready for release, increment the version tag in `cluster/addons/kube-ui/image/Makefile` and run `make push` in the same directory to build & push the new kube-ui docker image.
|
||||
|
||||
### Serving the app in production
|
||||
The app is served in production by the `kube-ui` binary at:
|
||||
|
||||
```
|
||||
https://<kubernetes-master>/ui/
|
||||
```
|
||||
|
||||
which redirects to:
|
||||
|
||||
```
|
||||
https://<kubernetes-master>/api/v1/proxy/namespaces/kube-system/services/kube-ui/
|
||||
```
|
||||
|
||||
## Configuration
|
||||
### Configuration settings
|
||||
A json file can be used by `gulp` to automatically create angular constants. This is useful for setting per environment variables such as api endpoints.
|
||||
|
||||
`www/master/shared/config/development.json` and `www/master/shared/config/production.json` are used for application wide configuration in development and production, respectively.
|
||||
|
||||
* `www/master/shared/config/production.json` is kept under source control with default values for production.
|
||||
* `www/master/shared/config/development.json` is not kept under source control. Each developer can create a local version of the file by copy, paste and rename from `www/master/shared/config/development.example.json`, which is kept under source control with default values for development.
|
||||
|
||||
The configuration files for the current build environment are compiled into the intermediary `www/master/shared/config/generated-config.js`, which is then compiled into `app.js`.
|
||||
|
||||
* Component configuration added to `www/master/components/<component name>/config/<environment>.json` is combined with the application wide configuration during the build.
|
||||
|
||||
The generated angular constant is named `ENV`. The shared configuration and component configurations each generate a nested object within it. For example:
|
||||
|
||||
```
|
||||
www/master
|
||||
├── shared/config/development.json
|
||||
└── components
|
||||
├── dashboard/config/development.json
|
||||
└── my_component/config/development.json
|
||||
```
|
||||
generates the following in `www/master/shared/config/generated-config.js`:
|
||||
|
||||
```
|
||||
angular.module('kubernetesApp.config', [])
|
||||
.constant('ENV', {
|
||||
'/': <www/master/shared/config/development.json>,
|
||||
'dashboard': <www/master/components/dashboard/config/development.json>,
|
||||
'my_component': <www/master/components/my_component/config/development.json>
|
||||
});
|
||||
```
|
||||
|
||||
### Kubernetes server configuration
|
||||
**RECOMMENDED**: The Kubernetes api server does not enable CORS by default, so `kube-apiserver` must be started with `--cors-allowed-origins=http://<your
|
||||
host here>` or `--cors-allowed-origins=.*`.
|
||||
|
||||
**NOT RECOMMENDED**: If you don't want to/cannot restart the Kubernetes api server, you can start your browser with web security disabled. For example, you can [launch Chrome](http://www.chromium.org/developers/how-tos/run-chromium-with-flags) with flag `--disable-web-security`. Be careful not to visit untrusted web sites when running your browser in this mode.
|
||||
|
||||
## Building a new visualizer or component
|
||||
See [master/components/README.md](master/components/README.md).
|
||||
|
||||
## Testing
|
||||
Currently, the UI project includes both unit-testing with [Karma](http://karma-runner.github.io/0.12/index.html) and end-to-end testing with [Protractor](http://angular.github.io/protractor/#/).
|
||||
|
||||
### Unit testing with Karma
|
||||
To run the existing Karma tests:
|
||||
|
||||
* Install the Karma CLI (Note: it needs to be installed globally, so the `sudo` below may be needed. The other Karma packages, such as `karma`, `karma-jasmine`, and `karma-chrome-launcher,` should be installed automatically by the build).
|
||||
|
||||
```
|
||||
sudo npm install -g karma-cli
|
||||
```
|
||||
|
||||
* Edit the Karma configuration in `www/master/karma.config.js`, if necessary.
|
||||
* Run the tests. The console should show the test results.
|
||||
|
||||
```
|
||||
cd www/master
|
||||
karma start karma.conf.js
|
||||
```
|
||||
|
||||
To run new Karma tests for a component, put new `*.spec.js` files under the appropriate `www/master/components/**/test/modules/*` directories.
|
||||
|
||||
To test the chrome, put new `*.spec.js` files under the appropriate `www/master/test/modules/*` directories.
|
||||
|
||||
### End-to-end testing with Protractor
|
||||
To run the existing Protractor tests:
|
||||
|
||||
* Install the CLIs.
|
||||
|
||||
```
|
||||
sudo npm install -g protractor
|
||||
```
|
||||
|
||||
* Edit the test configuration in `www/master/protractor/conf.js`, if necessary.
|
||||
* Start the webdriver server.
|
||||
|
||||
```
|
||||
sudo webdriver-manager start
|
||||
```
|
||||
|
||||
* Start the application (see instructions above), running at port 8000.
|
||||
* Run the tests. The console should show the test results.
|
||||
|
||||
```
|
||||
cd www/master/protractor
|
||||
protractor conf.js
|
||||
```
|
||||
|
||||
To run new protractor tests for a component, put new `*.spec.js` files in the appropriate `www/master/components/**/protractor/*` directories.
|
||||
|
||||
To test the chrome, put new `*.spec.js` files under the `www/master/protractor/chrome` directory.
|
||||
|
||||
[]()
|
||||
The Kubernetes UI has moved to [kube-ui](https://github.com/kubernetes/kube-ui)
|
||||
|
Before Width: | Height: | Size: 373 B |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M7 10l5 5 5-5z"/>
|
||||
<path d="M0 0h24v24h-24z" fill="none"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 166 B |
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
|
||||
height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<g id="Header">
|
||||
<g>
|
||||
<rect x="-618" y="-952" fill="none" width="1400" height="3600"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Label">
|
||||
</g>
|
||||
<g id="Icon">
|
||||
<g>
|
||||
<g>
|
||||
<polygon points="7,14 12,9 17,14 "/>
|
||||
</g>
|
||||
<rect fill="none" width="24" height="24"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Grid" display="none">
|
||||
<g display="inline">
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 795 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"/></svg>
|
Before Width: | Height: | Size: 151 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/></svg>
|
Before Width: | Height: | Size: 149 B |
Before Width: | Height: | Size: 635 B |
Before Width: | Height: | Size: 1.6 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/></svg>
|
Before Width: | Height: | Size: 158 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></svg>
|
Before Width: | Height: | Size: 276 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
Before Width: | Height: | Size: 202 B |
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 10 10" style="enable-background:new 0 0 10 10;" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill:#010002;" d="M9.5,4.5h-9C0.224,4.5,0,4.724,0,5s0.224,0.5,0.5,0.5h9C9.775,5.5,10,5.276,10,5
|
||||
S9.775,4.5,9.5,4.5z"/>
|
||||
<path style="fill:#010002;" d="M0.5,2.5h9C9.775,2.5,10,2.276,10,2S9.775,1.5,9.5,1.5h-9C0.224,1.5,0,1.724,0,2
|
||||
S0.224,2.5,0.5,2.5z"/>
|
||||
<path style="fill:#010002;" d="M9.5,7.5h-9C0.224,7.5,0,7.725,0,8s0.224,0.5,0.5,0.5h9C9.775,8.5,10,8.275,10,8
|
||||
S9.775,7.5,9.5,7.5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 791 B |
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
|
||||
height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<g id="Header">
|
||||
<g>
|
||||
<rect x="-618" y="-2232" fill="none" width="1400" height="3600"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Label">
|
||||
</g>
|
||||
<g id="Icon">
|
||||
<g>
|
||||
<rect fill="none" width="24" height="24"/>
|
||||
<path d="M3,18h18v-2H3V18z M3,13h18v-2H3V13z M3,6v2h18V6H3z" style="fill:#f3f3f3;"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Grid" display="none">
|
||||
<g display="inline">
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 841 B |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 11 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><path d="M5 8l4 4 4-4z"/></svg>
|
Before Width: | Height: | Size: 114 B |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M7 10l5 5 5-5z"/>
|
||||
<path d="M0 0h24v24h-24z" fill="none"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 166 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><path d="M14.53 4.53l-1.06-1.06L9 7.94 4.53 3.47 3.47 4.53 7.94 9l-4.47 4.47 1.06 1.06L9 10.06l4.47 4.47 1.06-1.06L10.06 9z"/></svg>
|
Before Width: | Height: | Size: 215 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
Before Width: | Height: | Size: 202 B |
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"description": "The basic Kubernetes UI dashboard... ",
|
||||
"routes": [
|
||||
{
|
||||
"description": "Dashboard visualization.",
|
||||
"url": "/",
|
||||
"templateUrl": "components/dashboard/pages/home.html"
|
||||
},
|
||||
{
|
||||
"description": "Pods",
|
||||
"url": "/pods",
|
||||
"templateUrl": "components/dashboard/views/listPods.html"
|
||||
},
|
||||
{
|
||||
"description": "Pod Visualizer",
|
||||
"url": "/visualpods",
|
||||
"templateUrl": "components/dashboard/views/listPodsVisualizer.html"
|
||||
},
|
||||
{
|
||||
"description": "Services",
|
||||
"url": "/services",
|
||||
"templateUrl": "components/dashboard/views/listServices.html"
|
||||
},
|
||||
{
|
||||
"description": "Replication Controllers",
|
||||
"url": "/replicationcontrollers",
|
||||
"templateUrl": "components/dashboard/views/listReplicationControllers.html"
|
||||
},
|
||||
{
|
||||
"description": "Events",
|
||||
"url": "/events",
|
||||
"templateUrl": "components/dashboard/views/listEvents.html"
|
||||
},
|
||||
{
|
||||
"description": "Nodes",
|
||||
"url": "/nodes",
|
||||
"templateUrl": "components/dashboard/views/listMinions.html"
|
||||
},
|
||||
{
|
||||
"description": "Replication Controller",
|
||||
"url": "/replicationcontrollers/:replicationControllerId",
|
||||
"templateUrl": "components/dashboard/views/replication.html"
|
||||
},
|
||||
{
|
||||
"description": "Service",
|
||||
"url": "/services/:serviceId",
|
||||
"templateUrl": "components/dashboard/views/service.html"
|
||||
},
|
||||
{
|
||||
"description": "Node",
|
||||
"url": "/nodes/:nodeId",
|
||||
"templateUrl": "components/dashboard/views/node.html"
|
||||
},
|
||||
{
|
||||
"description": "Explore",
|
||||
"url": "/groups/:grouping*?/selector/:selector*?",
|
||||
"templateUrl": "components/dashboard/views/groups.html"
|
||||
},
|
||||
{
|
||||
"description": "Pod",
|
||||
"url": "/pods/:podId",
|
||||
"templateUrl": "components/dashboard/views/pod.html"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1 +0,0 @@
|
||||
<p></p>
|
@@ -1,26 +0,0 @@
|
||||
<div layout-fill>
|
||||
<md-toolbar md-scroll-shrink class="dashboard-subnav">
|
||||
<div class="md-toolbar-tools">
|
||||
<div layout="row" flex class="fill-height">
|
||||
<div class="md-toolbar-item md-breadcrumb"></div>
|
||||
<span ng-if="menu.currentPage.name !== menu.currentSection.name">
|
||||
<span hide-sm hide-md><a href="#{{menu.currentSection.url}}">{{menu.currentSection.name}}</a></span>
|
||||
<span class="menu-separator-icon" style="padding: 0 10px;" hide-sm hide-md>
|
||||
<img style="height: 12px;" src="assets/img/docArrow.png" alt="" aria-hidden="true">
|
||||
</span>
|
||||
</span>
|
||||
<span style="display: inline-block;">{{(menu.currentPage | humanizeDoc) || 'Kubernetes' }}</span>
|
||||
<span flex></span>
|
||||
<div class="md-toolbar-item md-tools" layout="row">
|
||||
<div layout="column" class="selectSubPages">
|
||||
<md-select ng-model="page" placeholder="Views" class="selectTitle">
|
||||
<md-optgroup label="Dashboard">
|
||||
<md-option id="{{subpage.id}}" ng-value="subpage.value" ng-repeat="subpage in subpages | filter: {category: 'dashboard' }">{{subpage.name}}</md-option>
|
||||
</md-option-group>
|
||||
</md-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
</div>
|
@@ -1,7 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard" ng-controller="DashboardCtrl" layout-fill>
|
||||
<md-content>
|
||||
<div ng-include="'components/dashboard/views/partials/cadvisor.html'">></div>
|
||||
</md-content>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,35 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="GroupCtrl" layout="column" class="body-wrapper groups">
|
||||
<md-content>
|
||||
<!-- page header -->
|
||||
<div class="header" layout="row">
|
||||
<div class="">Group by: </div>
|
||||
|
||||
<md-select placeholder="{{selectedGroupByName}}" class="select-group-by" ng-model="selectedGroupBy" ng-change="changeGroupBy()">
|
||||
<md-option ng-value="g.value" ng-repeat="g in groupByOptions">{{g.name}}</md-option>
|
||||
</md-select>
|
||||
|
||||
<div ng-if="selector" layout="row" class="selector-area">
|
||||
<div class="filter-label">Filter:</div>
|
||||
|
||||
<div class="filter-text">{{selectorName}}</div>
|
||||
<div class="filter-area" ng-if="selector && selector.length > 0">
|
||||
|
||||
<button ng-click="clearSelector(routeParams.grouping)" class="md-button cancel-button">
|
||||
|
||||
<md-icon md-svg-src="components/dashboard/img/icons/ic_close_18px.svg" class="cancel-icon" alt="Cancel"></md-icon>
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="group-item" ng-repeat="(groupName,group) in groups.items" ng-include="'components/dashboard/views/partials/groupBox.html'"></div>
|
||||
</md-content>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,7 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ListEventsCtrl" style="padding:25px;" class="list-pods">
|
||||
<md-table headers="headers" content="content" sortable="sortable" filters="search" custom-class="custom" thumbs="thumbs" count="count" reverse="true"></md-table>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,7 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ListMinionsCtrl" style="padding:25px;" class="list-pods">
|
||||
<md-table headers="headers" content="content" sortable="sortable" filters="search" custom-class="custom" thumbs="thumbs" count="count" on-select="go(data)"></md-table>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,7 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ListPodsCtrl" style="padding:25px;" class="list-pods">
|
||||
<md-table headers="headers" content="content" sortable="sortable" filters="search" custom-class="custom" thumbs="thumbs" count="count" on-select="go(data)"></md-table>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,59 +0,0 @@
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ListPodsCtrl" style="padding:25px;" class="list-pods">
|
||||
|
||||
<md-whiteframe layout-margin class="md-whiteframe-z2">
|
||||
<md-toolbar class="">
|
||||
<div class="md-toolbar-tools">
|
||||
Pods
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-content>
|
||||
|
||||
|
||||
<div class="pod-group">
|
||||
<md-grid-list md-cols="6" md-row-height="1:1.5" md-gutter="8px" ng-repeat="(podName, groupPods) in groupedPods">
|
||||
<md-grid-tile md-rowspan="1" md-colspan="2" class="gray">
|
||||
<md-grid-tile-footer>
|
||||
<div class="pod-title"><h2>{{podName}}</h2></div>
|
||||
</md-grid-tile-footer>
|
||||
</md-grid-tile>
|
||||
|
||||
<md-grid-tile class="purple" md-rowspan="1" md-colspan="1" ng-repeat="pod in groupPods" >
|
||||
<div>
|
||||
|
||||
<div>
|
||||
Containers:
|
||||
<span ng-repeat="container in pod.desiredState.manifest.containers">
|
||||
{{container.name}}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
Images:
|
||||
<span ng-repeat="container in pod.desiredState.manifest.containers">
|
||||
{{container.image}}
|
||||
</span>
|
||||
</div>
|
||||
<div>Internal IP: {{pod.currentState.podIP}}</div>
|
||||
<div>
|
||||
Labels:
|
||||
<span ng-repeat="(label, value) in pod.labels">{{label}}={{value}}<span ng-show="!$last">, </span></span>
|
||||
</div>
|
||||
<div>Status: {{pod.currentState.status}}</div>
|
||||
</div>
|
||||
<md-grid-tile-footer>
|
||||
|
||||
<div class="pod-host">{{pod.currentState.host}}</div>
|
||||
<div><a ng-href="#/dashboard/pods/{{ pod.id }}"><h3>{{ pod.id }}</h3></a></div>
|
||||
|
||||
</md-grid-tile-footer>
|
||||
</md-grid-tile>
|
||||
|
||||
</md-grid-list>
|
||||
</div>
|
||||
|
||||
|
||||
</md-content>
|
||||
</md-whiteframe>
|
||||
|
||||
</div>
|
||||
</div>
|
@@ -1,17 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ListPodsCtrl" style="padding:25px;" class="list-pods">
|
||||
<md-whiteframe layout-margin class="md-whiteframe-z2">
|
||||
<md-content>
|
||||
<div>
|
||||
<md-button class="md-primary" ng-click="serverView = false">By Name</md-button> |
|
||||
<md-button class="md-primary" ng-click="serverView = true">By Server</md-button>
|
||||
<div style="float:right;"><md-button class="md-primary" ng-href="#/dashboard/pods">View Pod Listing</md-button></div>
|
||||
</div>
|
||||
<div class="pod-group" ng-show="!serverView" ng-include="'components/dashboard/views/partials/podTilesByName.html'"></div>
|
||||
<div class="pod-group" ng-show="serverView" ng-include="'components/dashboard/views/partials/podTilesByServer.html'"></div>
|
||||
</md-content>
|
||||
</md-whiteframe>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,7 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ListReplicationControllersCtrl" style="padding:25px;" class="list-pods">
|
||||
<md-table headers="headers" content="content" sortable="sortable" filters="search" custom-class="custom" thumbs="thumbs" count="count" on-select="go(data)"></md-table>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,7 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ListServicesCtrl" style="padding:25px;" class="list-pods">
|
||||
<md-table headers="headers" content="content" sortable="sortable" filters="search" custom-class="custom" thumbs="thumbs" count="count" on-select="go(data)"></md-table>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,89 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="NodeCtrl" layout="column" class="body-wrapper node">
|
||||
<div class="detail">
|
||||
|
||||
<div class="back">
|
||||
<md-button class="md-default-theme" ng-click="doTheBack()">‹ BACK</md-button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="heading">
|
||||
<span class="label">Name:</span>
|
||||
<span>{{node.metadata.name}}</span>
|
||||
</div>
|
||||
|
||||
|
||||
<table class="align-top">
|
||||
<tbody>
|
||||
<tr ng-show="node.metadata.labels">
|
||||
<td class="name">Labels</td>
|
||||
<td class="value">
|
||||
<div ng-repeat="(label, value) in node.metadata.labels">
|
||||
{{label}}: {{value}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Created</td>
|
||||
<td class="value">
|
||||
{{node.metadata.creationTimestamp | date:'medium'}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Addresses</td>
|
||||
<td class="value">
|
||||
<div ng-repeat="a in node.status.addresses">
|
||||
{{a.address}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-show="node.status.capacity">
|
||||
<td class="name">Capacity</td>
|
||||
<td class="value">
|
||||
<table>
|
||||
<tr ng-repeat="(label, value) in node.status.capacity">
|
||||
<td>{{label}}:</td> <td>{{value}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">System Info</td>
|
||||
<td class="value">
|
||||
<table>
|
||||
<tr ng-repeat="(label, value) in node.status.nodeInfo">
|
||||
<td>{{label}}:</td> <td>{{value}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-show="node.spec.podCIDR">
|
||||
<td class="name">PodCIDR</td>
|
||||
<td class="value">
|
||||
{{node.spec.podCIDR}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-show="node.spec.externalID">
|
||||
<td class="name">ExternalID</td>
|
||||
<td class="value">
|
||||
{{node.spec.externalID}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,9 +0,0 @@
|
||||
<div class="dashboard" ng-controller="cAdvisorController">
|
||||
<div class="server-overview">
|
||||
<md-content layout="row" layout-wrap>
|
||||
<div flex-sm="100" flex-md="50" flex-lg="33" flex-gt-lg="25" class="chart_area" ng-repeat="minion in minions.items">
|
||||
<d3-minion-bar-gauge data="activeMinionDataById[minion.metadata.name]" class="concentric" graph-width="325" graph-height="325" thickness=18 />
|
||||
</div>
|
||||
</md-content>
|
||||
</div>
|
||||
</div>
|
@@ -1,20 +0,0 @@
|
||||
<div>
|
||||
<md-content>
|
||||
<div class="server-overview" layout="column">
|
||||
<!-- subheader -->
|
||||
<div class="group-heading" layout="row">
|
||||
<div class="label">{{selectedGroupByName | ucfirst}}: <span class="bold">{{ (groupName) || "blank" }}</span></div>
|
||||
</div>
|
||||
<!-- render group data -->
|
||||
<div ng-include="'components/dashboard/views/partials/groupItem.html'"></div>
|
||||
<div class="footer">
|
||||
<!-- Alternate box inside a box -->
|
||||
<div ng-if="group.kind == 'grouping'">
|
||||
{{group.kind}}
|
||||
<div ng-repeat="(groupName,group) in group.items" ng-include="'components/dashboard/views/partials/groupBox.html'"></div>
|
||||
</div>
|
||||
<md-divider></md-divider>
|
||||
</div>
|
||||
</div>
|
||||
</md-content>
|
||||
</div>
|
@@ -1,47 +0,0 @@
|
||||
<div layout="row" ng-if="group.kind != 'grouping'">
|
||||
<div>
|
||||
<!-- Default box display -->
|
||||
<div layout="row" class="group-item" ng-repeat="(groupType, data) in group | groupBy: 'metadata.labels.type'">
|
||||
<!-- left image -->
|
||||
<div class="icon-area">
|
||||
<div class="group-icon" style="background-color: {{getGroupColor(groupType)}}"></div>
|
||||
</div>
|
||||
<!-- right area -->
|
||||
<div class="group-main-area" layout="column">
|
||||
<!-- type -->
|
||||
<div class="subtype">
|
||||
{{groupType | ucfirst}}s
|
||||
</div>
|
||||
<!-- links -->
|
||||
<div layout="row" layout-wrap>
|
||||
<div layout="row" ng-repeat="item in data">
|
||||
<!-- title -->
|
||||
<div ng-switch on='item.metadata.labels["type"]'>
|
||||
<div class="group-name">
|
||||
<a ng-switch-when='pod' ng-href="#/dashboard/pods/{{ item.metadata.name }}">{{ item.metadata.name }}</a>
|
||||
<a ng-switch-when='service' ng-href="#/dashboard/services/{{ item.metadata.name }}">{{ item.metadata.name }}</a>
|
||||
<a ng-switch-when='replicationController' ng-href="#/dashboard/replicationcontrollers/{{ item.metadata.name }}">{{ item.metadata.name }}</a>
|
||||
<div ng-switch-default>{{item.metadata.name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="selectFilter">
|
||||
<md-select ng-model="selectedFilter" ng-change="changeFilterBy(selectedFilter)">
|
||||
<md-optgroup label="FILTER">
|
||||
<md-option ng-value="'{{key | uriComponentEncode}}={{value | uriComponentEncode}}'" ng-repeat="(key, value) in item.metadata.labels">{{key}}: {{value}}</md-option>
|
||||
</md-option-group>
|
||||
</md-optgroup>
|
||||
</md-select>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- This is the official button design, but requires a custom dialog. Fix up after the demo. -->
|
||||
<!-- <md-button ng-click="" class="filter-button" style="padding:0">
|
||||
<md-icon md-svg-src="components/dashboard/img/icons/ic_arrow_drop_down_18px.svg" class="filter-icon" aria-label="" alt="Filter"></md-icon>
|
||||
</md-button> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -1,34 +0,0 @@
|
||||
|
||||
<md-grid-list class="list-color-{{$index + 1}}" md-cols="6" md-row-height="1:1" md-gutter="8px" ng-repeat="(podName, groupPods) in podsByName">
|
||||
<md-grid-tile md-rowspan="2" md-colspan="2" class="colored">
|
||||
<md-grid-tile-footer>
|
||||
<div class="pod-title"><h2>{{podName}} overview</h2></div>
|
||||
</md-grid-tile-footer>
|
||||
</md-grid-tile>
|
||||
|
||||
<md-grid-tile class="colored {{podStatusClass(pod)}}" md-rowspan="1" md-colspan="1" ng-repeat="pod in groupPods" >
|
||||
<md-grid-tile-header class="clear-bg">
|
||||
|
||||
<div layout="row">
|
||||
<div class="labels"><span ng-repeat="(label, value) in otherLabels(pod.labels)">{{label}}: {{value}}<span ng-show="!$last">, </span></span></div>
|
||||
|
||||
<div flex="20" class="restarts" ng-show="getPodRestarts(pod) > 0">
|
||||
<md-button class="md-fab restart-button">
|
||||
{{getPodRestarts(pod)}}
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</md-grid-tile-header>
|
||||
<div class="inner-box">
|
||||
|
||||
<div ng-show="podStatusClass(pod)">Status: {{pod.currentState.status}}</div>
|
||||
</div>
|
||||
<md-grid-tile-footer>
|
||||
|
||||
<div class="pod-host">{{pod.currentState.host}}</div>
|
||||
<div><a ng-href="#/dashboard/pods/{{ pod.id }}"><h3>{{ pod.id }}</h3></a></div>
|
||||
|
||||
</md-grid-tile-footer>
|
||||
</md-grid-tile>
|
||||
</md-grid-list>
|
@@ -1,34 +0,0 @@
|
||||
<md-grid-list class="" md-cols="6" md-row-height="1:1" md-gutter="8px" ng-repeat="(serverIp, groupPods) in podsByServer">
|
||||
<md-grid-tile md-rowspan="2" md-colspan="2" class="gray">
|
||||
<md-grid-tile-footer>
|
||||
<div class="pod-title"><h2>{{serverIp}} overview</h2></div>
|
||||
</md-grid-tile-footer>
|
||||
</md-grid-tile>
|
||||
|
||||
<md-grid-tile class="color-{{podIndexFromName(pod)}} {{podStatusClass(pod)}}" md-rowspan="1" md-colspan="1" ng-repeat="pod in groupPods" >
|
||||
<md-grid-tile-header class="clear-bg">
|
||||
|
||||
<div layout="row">
|
||||
<div class="labels"><span ng-repeat="(label, value) in otherLabels(pod.labels)">{{label}}: {{value}}<span ng-show="!$last">, </span></span></div>
|
||||
|
||||
<div flex="20" class="restarts" ng-show="getPodRestarts(pod) > 0">
|
||||
<md-button class="md-fab restart-button">
|
||||
{{getPodRestarts(pod)}}
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</md-grid-tile-header>
|
||||
<div class="inner-box">
|
||||
|
||||
<div ng-show="podStatusClass(pod)">Status: {{pod.currentState.status}}</div>
|
||||
</div>
|
||||
<md-grid-tile-footer>
|
||||
|
||||
<div class="pod-host">{{pod.labels.name}}</div>
|
||||
<div><a ng-href="#/dashboard/pods/{{ pod.id }}"><h3>{{ pod.id }}</h3></a></div>
|
||||
|
||||
</md-grid-tile-footer>
|
||||
</md-grid-tile>
|
||||
|
||||
</md-grid-list>
|
@@ -1,114 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="PodCtrl" layout="column" class="body-wrapper pod">
|
||||
<div class="detail">
|
||||
|
||||
<div class="back">
|
||||
<md-button class="md-default-theme" ng-click="doTheBack()">‹ BACK</md-button>
|
||||
</div>
|
||||
|
||||
<div class="heading">
|
||||
<span class="label">Name:</span>
|
||||
<span>{{pod.metadata.name}}</span>
|
||||
</div>
|
||||
|
||||
|
||||
<table class="align-top">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="name">Status</td>
|
||||
<td class="value">
|
||||
{{pod.status.phase}} on <a ng-href="#/dashboard/groups/host/selector/host={{pod.spec.nodeName}}">{{pod.spec.nodeName}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Created</td>
|
||||
<td class="value">
|
||||
{{pod.metadata.creationTimestamp | date:'medium'}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Host Networking</td>
|
||||
<td class="value">
|
||||
{{pod.spec.nodeName}}/{{pod.status.hostIP}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Pod Networking</td>
|
||||
<td class="value">
|
||||
{{pod.status.podIP}}
|
||||
<span ng-repeat="container in pod.spec.containers">
|
||||
<span ng-repeat="port in container.ports">
|
||||
<span ng-show="port.containerPort">
|
||||
{{port.name}}: {{port.containerPort}}{{$last ? '' : ', '}}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Labels</td>
|
||||
<td class="value">
|
||||
<div ng-repeat="(label, value) in pod.metadata.labels">
|
||||
{{label}}: {{value}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Containers</td>
|
||||
<td class="value">
|
||||
|
||||
<table class="containerTable">
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>Image</td>
|
||||
<td>Ready</td>
|
||||
<td>Restarts</td>
|
||||
<td>State</td>
|
||||
</tr>
|
||||
<tr ng-repeat="container in pod.status.containerStatuses">
|
||||
<td>{{container.name}}</td>
|
||||
<td>{{container.image}}</td>
|
||||
<td>{{container.ready}}</td>
|
||||
<td>{{container.restartCount}}</td>
|
||||
<td>
|
||||
<div ng-show="container.state.running">
|
||||
<div class="run-state">Running</div>
|
||||
<div class="run-messages">Started: {{container.state.running.startedAt | date:'medium'}}</div>
|
||||
</div>
|
||||
<div ng-show="container.state.waiting">
|
||||
<div class="run-state">Waiting</div>
|
||||
<div class="run-messages" ng-show="container.state.waiting.reason">Reason: {{container.state.waiting.reason}}</div>
|
||||
</div>
|
||||
<div ng-show="container.state.termination">
|
||||
<div class="run-state">Terminated</div>
|
||||
<div class="run-messages" ng-show="container.state.termination.reason">Reason: {{container.state.termination.reason}}</div>
|
||||
<div class="run-messages" ng-show="container.state.termination.message">Message: {{container.state.termination.message}}</div>
|
||||
<div class="run-messages">Exit Code: {{container.state.termination.exitCode}}</div>
|
||||
<div class="run-messages" ng-show="container.state.termination.signal">Signal: {{container.state.termination.signal}}</div>
|
||||
<div class="run-messages">Started: {{container.state.termination.startedAt | date:'medium'}}</div>
|
||||
<div class="run-messages">Finished: {{container.state.termination.finishedAt | date:'medium'}}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,100 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ReplicationControllerCtrl" layout="column" class="body-wrapper">
|
||||
|
||||
<div class="detail">
|
||||
|
||||
<div class="back">
|
||||
<md-button class="md-default-theme" ng-click="doTheBack()">‹ BACK</md-button>
|
||||
</div>
|
||||
|
||||
<div class="heading">
|
||||
<span class="label">Replication Controller: </span>
|
||||
<span>{{replicationController.metadata.name}}</span>
|
||||
</div>
|
||||
|
||||
|
||||
<table class="align-top">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="name">Created</td>
|
||||
<td class="value">
|
||||
{{replicationController.metadata.creationTimestamp | date:'medium'}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Desired Replicas</td>
|
||||
<td class="value">
|
||||
{{replicationController.spec.replicas}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Current Replicas</td>
|
||||
<td class="value">
|
||||
{{replicationController.status.replicas}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-show="replicationController.spec.selector">
|
||||
<td class="name">Selector</td>
|
||||
<td class="value">
|
||||
<span ng-repeat="(label, value) in replicationController.spec.selector">
|
||||
{{label}}={{value}}{{$last ? '' : ', '}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Labels</td>
|
||||
<td class="value">
|
||||
<div ng-repeat="(label, value) in replicationController.metadata.labels">
|
||||
{{label}}: {{value}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Related Pods</td>
|
||||
<td class="value">
|
||||
<div ng-show="replicationController.spec.selector && Object.keys(replicationController.spec.selector).length > 1">
|
||||
<a ng-href="#/dashboard/groups/type/selector/{{getSelectorUrlFragment(replicationController.spec.selector)}},type=pod">{{getSelectorUrlFragment(replicationController.spec.selector)}}</a>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="(label, value) in replicationController.spec.selector">
|
||||
<a ng-href="#/dashboard/groups/type/selector/{{label}}={{value}},type=pod">{{label}}: {{value}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td class="name">Related Services</td>
|
||||
<td class="value">
|
||||
<div ng-show="replicationController.spec.selector && Object.keys(replicationController.spec.selector).length > 1">
|
||||
|
||||
<a ng-href="#/dashboard/groups/type/selector/{{getSelectorUrlFragment(replicationController.spec.selector)}},type=pod">{{getSelectorUrlFragment(replicationController.spec.selector)}}</a>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="(label, value) in replicationController.spec.selector">
|
||||
<a ng-href="#/dashboard/groups/type/selector/{{label}}={{value}},type=service">{{label}}={{value}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,120 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard">
|
||||
<div ng-controller="ServiceCtrl" layout="column" class="body-wrapper service">
|
||||
|
||||
<div class="detail">
|
||||
|
||||
<div class="back">
|
||||
<md-button class="md-default-theme" ng-click="doTheBack()">‹ BACK</md-button>
|
||||
</div>
|
||||
|
||||
<div class="heading">
|
||||
<span class="label">Service: </span>
|
||||
<span>{{service.metadata.name}}</span>
|
||||
</div>
|
||||
|
||||
|
||||
<table class="align-top">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="name">Created</td>
|
||||
<td class="value">
|
||||
{{service.metadata.creationTimestamp | date:'medium'}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Ports</td>
|
||||
<td class="value">
|
||||
<div ng-repeat="port in service.spec.ports">
|
||||
<span ng-show="port.name">
|
||||
{{port.name}}:
|
||||
</span>
|
||||
{{port.port}}/{{port.protocol}}
|
||||
|
||||
<div ng-show="port.nodePort && port.nodePort != 0">
|
||||
Node Port: {{port.nodePort}}/{{port.protocol}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td class="name">IP</td>
|
||||
<td class="value">
|
||||
{{service.spec.clusterIP}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-show="service.status.loadBalancer.ingress">
|
||||
<td class="name">LoadBalancer Ingress</td>
|
||||
<td class="value">
|
||||
<span ng-repeat="lb in service.status.loadBalancer.ingress">
|
||||
{{lb.ip || lb.hostname}}{{$last ? '' : ', '}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Session Affinity</td>
|
||||
<td class="value">
|
||||
{{service.spec.sessionAffinity}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Labels</td>
|
||||
<td class="value">
|
||||
<div ng-repeat="(label, value) in service.metadata.labels">
|
||||
{{label}}: {{value}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-show="service.spec.selector">
|
||||
<td class="name">Selector</td>
|
||||
<td class="value">
|
||||
<span ng-repeat="(label, value) in service.spec.selector">
|
||||
{{label}}={{value}}{{$last ? '' : ', '}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Related Pods</td>
|
||||
<td class="value">
|
||||
<div ng-show="service.spec.selector && Object.keys(service.spec.selector).length > 1">
|
||||
<a ng-href="#/dashboard/groups/type/selector/{{getSelectorUrlFragment(service.spec.selector)}},type=pod">{{getSelectorUrlFragment(service.spec.selector)}}</a>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="(label, value) in service.spec.selector">
|
||||
<a ng-href="#/dashboard/groups/type/selector/{{label}}={{value}},type=pod">{{label}}={{value}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name">Related Replication Controllers</td>
|
||||
<td class="value">
|
||||
<div ng-show="service.spec.selector && Object.keys(service.spec.selector).length > 1">
|
||||
<a ng-href="#/dashboard/groups/type/selector/{{getSelectorUrlFragment(service.spec.selector)}},type=replicationController">{{getSelectorUrlFragment(service.spec.selector)}}</a>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="(label, value) in service.spec.selector">
|
||||
<a ng-href="#/dashboard/groups/type/selector/{{label}}={{value}},type=replicationController">{{label}}={{value}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|
@@ -1,58 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" ng-app="kubernetesApp">
|
||||
|
||||
<head>
|
||||
<title>Kubernetes UI</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<link rel="stylesheet" href="vendor/angular-material/angular-material.css">
|
||||
<link rel="stylesheet" href="assets/css/app.css">
|
||||
<link rel="shortcut icon" href="assets/img/icons/favicon.png" type="image/vnd.microsoft.icon" />
|
||||
</head>
|
||||
|
||||
<body layout="row" ng-controller="PageCtrl">
|
||||
<md-sidenav layout="column" md-is-locked-open="shouldLockOpen()" style="overflow: hidden; display: flex;" class="site-sidenav md-sidenav-left md-whiteframe-z2" md-component-id="left" md-closed>
|
||||
<md-toolbar>
|
||||
<h1 class="md-toolbar-tools">
|
||||
<a ng-href="#/dashboard" layout="row" flex>
|
||||
<span class="kubernetes-ui-logo"></span>
|
||||
<div style="line-height:40px; text-indent: 15px;">Kubernetes</div>
|
||||
</a>
|
||||
</h1>
|
||||
</md-toolbar>
|
||||
<md-content flex>
|
||||
<div kubernetes-ui-menu role="kubernetes-ui-menu"></div>
|
||||
<div compile="sidenavLeft"></div>
|
||||
</md-content>
|
||||
</md-sidenav>
|
||||
<div layout="column" layout-fill tabIndex="-1" role="main" flex>
|
||||
<md-toolbar>
|
||||
<div class="md-toolbar-tools">
|
||||
<h1 class="md-toolbar-tools">
|
||||
<a ng-href="#/dashboard" layout="row" flex>
|
||||
<span class="kubernetes-ui-logo"></span>
|
||||
<div style="line-height:40px; text-indent: 15px;">Kubernetes</div>
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-content md-scroll-y flex>
|
||||
<md-whiteframe layout layout-align="center center">
|
||||
<div ng-controller="TabCtrl" class="tabsDefaultTabs">
|
||||
<md-tabs md-selected="0">
|
||||
<md-tab ng-repeat="tab in tabs" md-on-select="switchTab($index)" label="{{tab.title}}">
|
||||
<div class="demo-tab tab{{$index%4}}" layout="column" layout-fill></div>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
<div ng-view layout="column" layout-fill role="main"></div>
|
||||
</div>
|
||||
</md-whiteframe>
|
||||
</md-content>
|
||||
</div>
|
||||
<script src="assets/js/base.js"></script>
|
||||
<script src="assets/js/app.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
@@ -1 +0,0 @@
|
||||
.jh-key,.jh-root,.jh-root tr,.jh-type-array,.jh-type-object,.jh-value{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.jh-key,.jh-value{margin:0;padding:.2em}.jh-value{border-left:1px solid #ddd}.jh-type-bool,.jh-type-number{font-weight:700;text-align:center;color:#5286BC}.jh-type-string{font-style:italic;color:#839B00}.jh-array-key{font-style:italic;font-size:small;text-align:center}.jh-array-key,.jh-object-key{color:#444;vertical-align:top}.jh-type-array>tbody>tr:nth-child(odd),.jh-type-object>tbody>tr:nth-child(odd){background-color:#f5f5f5}.jh-type-array>tbody>tr:nth-child(even),.jh-type-object>tbody>tr:nth-child(even){background-color:#fff}.jh-type-array,.jh-type-object{width:100%;border-collapse:collapse}.jh-root{border:1px solid #ccc;margin:.2em}th.jh-key{text-align:left}.jh-type-array>tbody>tr,.jh-type-object>tbody>tr{border:1px solid #ddd;border-bottom:none}.jh-type-array>tbody>tr:last-child,.jh-type-object>tbody>tr:last-child{border-bottom:1px solid #ddd}.jh-type-array>tbody>tr:hover,.jh-type-object>tbody>tr:hover{border:1px solid #F99927}.jh-empty{font-style:italic;color:#999;font-size:small}
|
5
www/app/vendor/d3/d3.min.js
vendored
@@ -1 +0,0 @@
|
||||
<span>The page you're looking for could not be found.</span>
|
@@ -1,14 +0,0 @@
|
||||
<ul class="kubernetes-ui-menu">
|
||||
<li ng-repeat="section in menu.sections" class="parent-list-item" ng-class="{'parentActive' : isSectionSelected(section)}">
|
||||
<h2 class="menu-heading" ng-if="section.type === 'heading'" id="heading_{{ section.name | nospace }}">
|
||||
{{section.name}}
|
||||
</h2>
|
||||
<menu-link section="section" ng-if="section.type === 'link'"></menu-link>
|
||||
<menu-toggle section="section" ng-if="section.type === 'toggle'"></menu-toggle>
|
||||
<ul ng-if="section.children" class="menu-nested-list">
|
||||
<li ng-repeat="child in section.children" ng-class="{'childActive' : isSectionSelected(child)}">
|
||||
<menu-toggle section="child"></menu-toggle>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
@@ -1,47 +0,0 @@
|
||||
<table class="md-table">
|
||||
<thead>
|
||||
<tr class="md-table-headers-row">
|
||||
<th class="md-table-header" ng-repeat="h in headers">
|
||||
<a href ng-if="handleSort(h.field)" ng-click="reverse=!reverse;order(h.field,reverse)">{{h.name}} <span class="md-table-caret" ng-show="reverse && h.field == predicate"><img src="assets/img/ic_arrow_drop_down_24px.svg"></span><span class="md-table-caret" ng-show="!reverse && h.field == predicate"><img src="assets/img/ic_arrow_drop_up_24px.svg"></span></a>
|
||||
<span ng-if="!handleSort(h.field)">{{h.name}}</span>
|
||||
</th>
|
||||
<th class="md-table-header" ng-show="showMore()"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="md-table-content-row" ng-repeat="c in content | filter:filters | startFrom:currentPage*count | limitTo: count">
|
||||
<td ng-repeat="h in headers" ng-if="h.field == thumbs" class="md-table-thumbs">
|
||||
<div ng-if="h.field == thumbs" style="background-image:url({{c.thumb}})"></div>
|
||||
</td>
|
||||
<td class="md-table-content" ng-click="doSelect({data:c})" ng-repeat="h in headers" ng-class="customClass[h.field]" ng-if="h.field != thumbs">
|
||||
{{c[h.field]}}
|
||||
</td>
|
||||
<td class="md-table-td-more" ng-show="showMore()">
|
||||
<md-button aria-label="More" ng-click="moreClick(c, $event)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
|
||||
</svg>
|
||||
</md-button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="md-table-footer" layout="row">
|
||||
<span class="md-table-count-info">Rows count per page : <a href ng-click="goToPage(0); count=1">1</a>, <a href ng-click="goToPage(0); count=10">10</a>, <a href ng-click="goToPage(0); count=25">25</a>, <a href ng-click="goToPage(0); count=50">50</a>, <a href ng-click="goToPage(0); count=100">100</a> (current
|
||||
is
|
||||
<strong>{{count}}</strong>)</span>
|
||||
<span flex></span>
|
||||
<span ng-show="nbOfPages() > 1">
|
||||
<md-button aria-label="Back" class="md-table-footer-item" ng-disabled="currentPage==0" ng-click="currentPage=currentPage-1">
|
||||
<img src="assets/img/ic_keyboard_arrow_left_24px.svg">
|
||||
</md-button>
|
||||
<a href ng-repeat="i in getNumber(nbOfPages()) track by $index">
|
||||
<md-button aria-label="Next" class="md-primary md-table-footer-item" ng-click="goToPage($index)">
|
||||
<span ng-class="{ 'md-table-active-page': currentPage==$index}">{{$index+1}}</span>
|
||||
</md-button>
|
||||
</a>
|
||||
<md-button aria-label="Jump" class="md-table-footer-item" ng-disabled="currentPage==nbOfPages()-1" ng-click="currentPage=currentPage+1">
|
||||
<img src="assets/img/ic_keyboard_arrow_right_24px.svg">
|
||||
</md-button>
|
||||
</span>
|
||||
</div>
|
@@ -1,10 +0,0 @@
|
||||
<md-button class="md-button-toggle" ng-click="toggle()" aria-controls="kubernetes-ui-menu-{{section.name | nospace}}" flex layout="row" aria-expanded="{{isOpen()}}">
|
||||
{{section.name}}
|
||||
<span aria-hidden="true" class="md-toggle-icon" ng-class="{'toggled' : isOpen()}"></span>
|
||||
<span class="visually-hidden">Toggle {{isOpen()? 'expanded' : 'collapsed'}}</span>
|
||||
</md-button>
|
||||
<ul ng-show="isOpen()" id="kubernetes-ui-menu-{{section.name | nospace}}" class="menu-toggle-list">
|
||||
<li ng-repeat="page in section.pages">
|
||||
<menu-link section="page"></menu-link>
|
||||
</li>
|
||||
</ul>
|
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"directory": "../../third_party/ui/bower_components"
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
### Application source and project files
|
||||
|
||||
This directory contains the source and project files for the application, including:
|
||||
|
||||
* `bower.json`, which declares the framework dependencies downloaded by bower,
|
||||
* `gulpfile.js`, which defines the build tasks run by `npm start` and `npm run build`,
|
||||
* `karma.conf.js`, the default configuration file for top level karma tests.
|
||||
* `package.json`, which declares the tool dependences downloaded by `npm install`.
|
||||
* `vendor.json` and `vendor.base.json`, which declare dependencies compiled into `app.js` and `base.js`, respectively.
|
||||
|
||||
You will find the following directories inside:
|
||||
|
||||
* `components/` This directory contains components that appear as tabs in the application. See [master/components/README.md](master/components/README.md).
|
||||
* `less/` This directory contains the LESS files for the core styles and material styles.
|
||||
* `js/` Here you will find JavaScript files compiled into `app.js`.
|
||||
* `protractor/` This directory contains the default configuration file `conf.js` and the `*.spec.js` files for the top level protractor tests.
|
||||
* `shared/` This directory contains assets shared by two or more components.
|
||||
* `test/` This directory contains the `*.spec.js` files for the top level karma tests. The default configuration file is `master/karma.conf.js`.
|
||||
|
||||
[]()
|
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "kubernetes-ui",
|
||||
"description": "UI for Kubernetes",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/kubernetes-ui/kubernetes-ui",
|
||||
"license": "Apache",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"jquery": "~2.1.3",
|
||||
"angular": "1.3.x",
|
||||
"angular-route": "1.3.x",
|
||||
"angular-css": "1.0.x",
|
||||
"angular-mocks": "1.3.x",
|
||||
"angular-animate": "1.3.x",
|
||||
"angular-aria": "1.3.x",
|
||||
"angular-material": "0.8.1",
|
||||
"angularjs-jasmine-matchers": "0.2",
|
||||
"hammerjs": "~2.0.2",
|
||||
"angular-cookies": "1.3.x",
|
||||
"modernizr": "2.8.3",
|
||||
"ng-lodash": "~0.2.0",
|
||||
"string-format-js": "~0.1.2",
|
||||
"sprintf": "~1.0.2",
|
||||
"jsonpath": "#3f6e79e",
|
||||
"d3": "~3.5.5",
|
||||
"d3-context-menu": "",
|
||||
"angular-json-human": "~1.2.1",
|
||||
"angular-filter": "~0.5.1"
|
||||
}
|
||||
}
|
@@ -1,130 +0,0 @@
|
||||
Components
|
||||
==========
|
||||
|
||||
A tab in the Kubernetes UI with its set of visualizations is referred to as a *component*. Components are separated from the chrome and services to simplify the development of new visualizations. This document describes how to create and modify components.
|
||||
|
||||
Each component has its own directory in `www/master/components`. The component directory contains a manifest file and the files comprising the component, such as HTML pages and views, Angular providers, CSS and Less files, and other assets. Here is the recommended structure for a component directory:
|
||||
|
||||
```
|
||||
foo_component
|
||||
├── config
|
||||
├── css
|
||||
├── img
|
||||
├── js
|
||||
│ └── modules
|
||||
│ ├── controllers
|
||||
│ ├── directives
|
||||
│ └── services
|
||||
├── less
|
||||
├── pages
|
||||
├── protractor
|
||||
├── test
|
||||
├── views
|
||||
│ └── partials
|
||||
└── manifest.json
|
||||
```
|
||||
|
||||
###Manifest file
|
||||
|
||||
The JSON-formatted manifest file, named `manifest.json`, resides at the root of the directory. Using the component directory name and the contents of the manifest, the Kubernetes UI automatically adds a tab to the chrome, a dependency on the component's AngularJS module in the main AngularJS app, and Angular routes for the component.
|
||||
|
||||
For example, consider the following manifest file at `master/components/foo_component/manifest.json`:
|
||||
|
||||
```
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
"url": "/",
|
||||
"templateUrl": "/components/foo_component/pages/home.html"
|
||||
},
|
||||
{
|
||||
"url": "/kittens",
|
||||
"templateUrl": "/components/foo_component/pages/kittens.html",
|
||||
"css": "/components/foo_component/css/kittens.css"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
From the name of the component directory, the Kubernetes UI:
|
||||
|
||||
* creates a tab called "Foo Component",
|
||||
* adds Angular module `kubernetesApp.components.fooComponent` to the dependencies of `kubernetesApp`, and
|
||||
* defines Angular routes `/foo_component/` and `/foo_component/kittens`.
|
||||
|
||||
Every tab links to `/` relative to its component, so it is important to always define a `/` route.
|
||||
|
||||
###Source files
|
||||
Many of the files located in `master/components/<component>` are copied to `app/components/<component>/` on each gulp build. This includes (but is not limited to) HTML pages and views, CSS files and images.
|
||||
|
||||
Exceptions include the `config` and `less` directories, and all of the `.js` files. The following sections explain how the exceptions are built into the UI.
|
||||
|
||||
####JavaScript
|
||||
All JavaScript files located in the `master/components/<component>/js` are concatenated together with the rest of the UI's JavaScript and written to `app/assets/js/app.js`. In the production build, they are also uglified.
|
||||
|
||||
####Configuration
|
||||
|
||||
Similar to the [application wide configuration](../../README.md#configuration), components can define environment specific configuration. The gulp task creates the constant `ENV` under the `kubernetesApp.config` module, which is an object with a property for the root UI and each component.
|
||||
|
||||
For example, a configuration for the `development` environment specific to `foo_component` would be located at `master/components/foo_component/config/development.json`. Such a component would access its `development.json` configuration verbatim at `ENV.foo_component`:
|
||||
|
||||
```
|
||||
angular.module('kubernetesApp.components.fooComponent', ['kubernetesApp.config'])
|
||||
.provider('foo', ...)
|
||||
.config(['fooProvider', 'ENV', function(fooProvider, ENV) {
|
||||
// Configure fooProvider using ENV['foo_component'].
|
||||
});
|
||||
```
|
||||
|
||||
####Less
|
||||
|
||||
Like JavaScript, the component's Less files are built into one monolithic CSS file. All top-level Less files located at `master/components/<component>/less/*.less` are imported into the main UI's Less file. The result is then copied to `app/assets/css/app.css`. In the production build, it is also minified.
|
||||
|
||||
Sub-directories of this path are watched for changes, but not directly imported. This is useful for defining common colors, mixins and other functions or variables used by the top-level Less files.
|
||||
|
||||
###Appendix
|
||||
|
||||
####Manifest schema
|
||||
|
||||
```
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Very brief summary of the component. Use a README.md file for detailed descriptions."
|
||||
},
|
||||
"routes": {
|
||||
"type": "array",
|
||||
"description": "Angular routes for the component.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Short description of the route."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "Route location relative to '/<component>'."
|
||||
},
|
||||
"templateUrl": {
|
||||
"type": "string",
|
||||
"description": "Absolute location of the HTML template."
|
||||
},
|
||||
"css": {
|
||||
"type": "string",
|
||||
"description": "Absolute location of CSS to use with this route."
|
||||
}
|
||||
},
|
||||
"required": ["url", "templateUrl"]
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": ["routes"]
|
||||
}
|
||||
```
|
||||
|
||||
[]()
|
@@ -1,4 +0,0 @@
|
||||
Dashboard Component for Kubernetes WebUI
|
||||
|
||||
|
||||
[]()
|
@@ -1 +0,0 @@
|
||||
{}
|
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><path d="M5 8l4 4 4-4z"/></svg>
|
Before Width: | Height: | Size: 114 B |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M7 10l5 5 5-5z"/>
|
||||
<path d="M0 0h24v24h-24z" fill="none"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 166 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><path d="M14.53 4.53l-1.06-1.06L9 7.94 4.53 3.47 3.47 4.53 7.94 9l-4.47 4.47 1.06 1.06L9 10.06l4.47 4.47 1.06-1.06L10.06 9z"/></svg>
|
Before Width: | Height: | Size: 215 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
Before Width: | Height: | Size: 202 B |
@@ -1,186 +0,0 @@
|
||||
|
||||
|
||||
app.controller('cAdvisorController', [
|
||||
'$scope',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'lodash',
|
||||
'cAdvisorService',
|
||||
'$q',
|
||||
'$interval',
|
||||
function($scope, $routeParams, k8sApi, lodash, cAdvisorService, $q, $interval) {
|
||||
$scope.k8sApi = k8sApi;
|
||||
|
||||
$scope.activeMinionDataById = {};
|
||||
$scope.maxDataByById = {};
|
||||
|
||||
$scope.getData = function() {
|
||||
$scope.loading = true;
|
||||
|
||||
k8sApi.getMinions().success(angular.bind(this, function(res) {
|
||||
$scope.minions = res;
|
||||
// console.log(res);
|
||||
var promises = lodash.map(res.items, function(m) { return cAdvisorService.getDataForMinion(m.metadata.name); });
|
||||
|
||||
$q.all(promises).then(
|
||||
function(dataArray) {
|
||||
lodash.each(dataArray, function(data, i) {
|
||||
var m = res.items[i];
|
||||
|
||||
var maxData = maxMemCpuInfo(m.metadata.name, data.memoryData, data.cpuData, data.filesystemData);
|
||||
|
||||
// console.log("maxData", maxData);
|
||||
var hostname = "";
|
||||
if(m.status.addresses)
|
||||
hostname = m.status.addresses[0].address;
|
||||
|
||||
$scope.activeMinionDataById[m.metadata.name] =
|
||||
transformMemCpuInfo(data.memoryData, data.cpuData, data.filesystemData, maxData, hostname);
|
||||
});
|
||||
|
||||
},
|
||||
function(errorData) {
|
||||
// console.log("Error: " + errorData);
|
||||
$scope.loading = false;
|
||||
});
|
||||
|
||||
$scope.loading = false;
|
||||
})).error(angular.bind(this, this.handleError));
|
||||
};
|
||||
|
||||
function handleError(data, status, headers, config) {
|
||||
// console.log("Error (" + status + "): " + data);
|
||||
$scope.loading = false;
|
||||
};
|
||||
|
||||
// d3
|
||||
function getColorForIndex(i, percentage) {
|
||||
// var colors = ['red', 'blue', 'yellow', 'pink', 'purple', 'green', 'orange'];
|
||||
// return colors[i];
|
||||
var c = "color-" + (i + 1);
|
||||
if (percentage && percentage >= 90)
|
||||
c = c + ' color-critical';
|
||||
else if (percentage && percentage >= 80)
|
||||
c = c + ' color-warning';
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
function getMaxColorForIndex(i, percentage) {
|
||||
// var colors = ['red', 'blue', 'yellow', 'pink', 'purple', 'green', 'orange'];
|
||||
// return colors[i];
|
||||
var c = "color-max-" + (i + 1);
|
||||
if (percentage && percentage >= 90)
|
||||
c = c + ' color-max-critical';
|
||||
else if (percentage && percentage >= 80)
|
||||
c = c + ' color-max-warning';
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
function maxMemCpuInfo(mId, mem, cpu, fsDataArray) {
|
||||
if ($scope.maxDataByById[mId] === undefined) $scope.maxDataByById[mId] = {};
|
||||
|
||||
var currentMem = mem.current;
|
||||
var currentCpu = cpu;
|
||||
|
||||
var items = [];
|
||||
|
||||
if ($scope.maxDataByById[mId]['cpu'] === undefined ||
|
||||
$scope.maxDataByById[mId]['cpu'] < currentCpu.cpuPercentUsage) {
|
||||
// console.log("New max cpu " + mId, $scope.maxDataByById[mId].cpu, currentCpu.cpuPercentUsage);
|
||||
$scope.maxDataByById[mId]['cpu'] = currentCpu.cpuPercentUsage;
|
||||
}
|
||||
items.push({
|
||||
maxValue: $scope.maxDataByById[mId]['cpu'],
|
||||
maxTickClassNames: getColorForIndex(0, $scope.maxDataByById[mId]['cpu']),
|
||||
maxClassNames: getMaxColorForIndex(0, $scope.maxDataByById[mId]['cpu'])
|
||||
});
|
||||
|
||||
var memPercentage = Math.floor((currentMem.memoryUsage * 100.0) / currentMem.memoryLimit);
|
||||
if ($scope.maxDataByById[mId]['mem'] === undefined || $scope.maxDataByById[mId]['mem'] < memPercentage)
|
||||
$scope.maxDataByById[mId]['mem'] = memPercentage;
|
||||
items.push({
|
||||
maxValue: $scope.maxDataByById[mId]['mem'],
|
||||
maxTickClassNames: getColorForIndex(1, $scope.maxDataByById[mId]['mem']),
|
||||
maxClassNames: getMaxColorForIndex(1, $scope.maxDataByById[mId]['mem'])
|
||||
});
|
||||
|
||||
for (var i = 0; i < fsDataArray.length; i++) {
|
||||
var f = fsDataArray[i];
|
||||
var fid = 'FS #' + f.filesystemNumber;
|
||||
if ($scope.maxDataByById[mId][fid] === undefined || $scope.maxDataByById[mId][fid] < f.totalUsage)
|
||||
$scope.maxDataByById[mId][fid] = f.totalUsage;
|
||||
items.push({
|
||||
maxValue: $scope.maxDataByById[mId][fid],
|
||||
maxTickClassNames: getColorForIndex(2 + i, $scope.maxDataByById[mId][fid]),
|
||||
maxClassNames: getMaxColorForIndex(2 + i, $scope.maxDataByById[mId][fid])
|
||||
});
|
||||
}
|
||||
|
||||
// console.log("Max Data is now " + mId, $scope.maxDataByById[mId]);
|
||||
return items;
|
||||
}
|
||||
|
||||
function transformMemCpuInfo(mem, cpu, fsDataArray, maxData, hostName) {
|
||||
var currentMem = mem.current;
|
||||
var currentCpu = cpu;
|
||||
|
||||
var items = [];
|
||||
|
||||
items.push({
|
||||
label: 'CPU',
|
||||
stats: currentCpu.cpuPercentUsage + '%',
|
||||
value: currentCpu.cpuPercentUsage,
|
||||
classNames: getColorForIndex(0, currentCpu.cpuPercentUsage),
|
||||
maxData: maxData[0],
|
||||
hostName: hostName
|
||||
});
|
||||
|
||||
var memPercentage = Math.floor((currentMem.memoryUsage * 100.0) / currentMem.memoryLimit);
|
||||
items.push({
|
||||
label: 'Memory',
|
||||
stats: currentMem.memoryUsageDescription + ' / ' + currentMem.memoryLimitDescription,
|
||||
value: memPercentage,
|
||||
classNames: getColorForIndex(1, memPercentage),
|
||||
maxData: maxData[1],
|
||||
hostName: hostName
|
||||
});
|
||||
|
||||
for (var i = 0; i < fsDataArray.length; i++) {
|
||||
var f = fsDataArray[i];
|
||||
|
||||
items.push({
|
||||
label: 'Filesystem #' + f.filesystemNumber,
|
||||
stats: f.usageDescription + ' / ' + f.capacityDescription,
|
||||
value: f.totalUsage,
|
||||
classNames: getColorForIndex(2 + i, f.totalUsage),
|
||||
maxData: maxData[2 + i],
|
||||
hostName: hostName
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
var a = [];
|
||||
var segments = {
|
||||
segments: items
|
||||
};
|
||||
a.push(segments);
|
||||
return a;
|
||||
};
|
||||
|
||||
// end d3
|
||||
var promise = $interval($scope.getData, 3000);
|
||||
|
||||
// Cancel interval on page changes
|
||||
$scope.$on('$destroy', function() {
|
||||
if (angular.isDefined(promise)) {
|
||||
$interval.cancel(promise);
|
||||
promise = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.getData();
|
||||
|
||||
}
|
||||
]);
|
@@ -1,6 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Dashboard
|
||||
* Visualizer for clusters
|
||||
=========================================================*/
|
||||
|
||||
app.controller('DashboardCtrl', ['$scope', function($scope) {}]);
|
@@ -1,237 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Group
|
||||
* Visualizer for groups
|
||||
=========================================================*/
|
||||
|
||||
app.controller('GroupCtrl', [
|
||||
'$scope',
|
||||
'$route',
|
||||
'$interval',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'$rootScope',
|
||||
'$location',
|
||||
'lodash',
|
||||
function($scope, $route, $interval, $routeParams, k8sApi, $rootScope, $location, _) {
|
||||
'use strict';
|
||||
$scope.doTheBack = function() { window.history.back(); };
|
||||
|
||||
$scope.capitalize = function(s) { return _.capitalize(s); };
|
||||
|
||||
$rootScope.doTheBack = $scope.doTheBack;
|
||||
|
||||
$scope.resetGroupLayout = function(group) { delete group.settings; };
|
||||
|
||||
$scope.handlePath = function(path) {
|
||||
var parts = path.split("/");
|
||||
// split leaves an empty string at the beginning.
|
||||
parts = parts.slice(1);
|
||||
|
||||
if (parts.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.handleGroups(parts.slice(1));
|
||||
};
|
||||
|
||||
$scope.getState = function(obj) { return Object.keys(obj)[0]; };
|
||||
|
||||
$scope.clearSelector = function(grouping) { $location.path("/dashboard/groups/" + grouping + "/selector/"); };
|
||||
|
||||
$scope.changeGroupBy = function() {
|
||||
var grouping = encodeURIComponent($scope.selectedGroupBy);
|
||||
|
||||
var s = _.clone($location.search());
|
||||
if ($scope.routeParams.grouping != grouping)
|
||||
$location.path("/dashboard/groups/" + grouping + "/selector/").search(s);
|
||||
};
|
||||
|
||||
$scope.createBarrier = function(count, callback) {
|
||||
var barrier = count;
|
||||
var barrierFunction = angular.bind(this, function(data) {
|
||||
// JavaScript is single threaded so this is safe.
|
||||
barrier--;
|
||||
if (barrier === 0) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
return barrierFunction;
|
||||
};
|
||||
|
||||
$scope.handleGroups = function(parts, selector) {
|
||||
$scope.groupBy = parts;
|
||||
$scope.loading = true;
|
||||
$scope.selector = selector;
|
||||
$scope.selectorName = decodeURIComponent(selector);
|
||||
var args = [];
|
||||
var type = "";
|
||||
var selectedHost = "";
|
||||
if (selector && selector.length > 0) {
|
||||
$scope.selectorPieces = selector.split(",");
|
||||
var labels = [];
|
||||
var fields = [];
|
||||
for (var i = 0; i < $scope.selectorPieces.length; i++) {
|
||||
var piece = decodeURIComponent($scope.selectorPieces[i]);
|
||||
if (piece[0] == '$') {
|
||||
fields.push(piece.slice(2));
|
||||
} else {
|
||||
if (piece.indexOf("type=") === 0) {
|
||||
var labelParts = piece.split("=");
|
||||
if (labelParts.length > 1) {
|
||||
type = labelParts[1];
|
||||
}
|
||||
}
|
||||
else if (piece.indexOf("host=") === 0){
|
||||
var labelParts = piece.split("=");
|
||||
if (labelParts.length > 1) {
|
||||
selectedHost = labelParts[1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
labels.push(piece);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (labels.length > 0) {
|
||||
args.push("labelSelector=" + encodeURI(labels.join(",")));
|
||||
}
|
||||
if (fields.length > 0) {
|
||||
args.push("fields=" + encodeURI(fields.join(",")));
|
||||
}
|
||||
}
|
||||
var query = "?" + args.join("&");
|
||||
var list = [];
|
||||
var count = type.length > 0 ? 1 : 3;
|
||||
|
||||
$scope.selectedGroupByName = decodeURIComponent($routeParams.grouping)
|
||||
|
||||
var barrier = $scope.createBarrier(count, function() {
|
||||
$scope.groups = $scope.groupData(list, 0);
|
||||
$scope.loading = false;
|
||||
$scope.groupByOptions = buildGroupByOptions();
|
||||
$scope.selectedGroupBy = $routeParams.grouping;
|
||||
});
|
||||
|
||||
if (type === "" || type == "pod") {
|
||||
k8sApi.getPods(query).success(function(data) {
|
||||
$scope.addLabel("type", "pod", data.items);
|
||||
for (var i = 0; data.items && i < data.items.length; ++i) {
|
||||
data.items[i].metadata.labels.host = data.items[i].spec.nodeName;
|
||||
if(selectedHost.length == 0 || selectedHost == data.items[i].metadata.labels.host)
|
||||
list.push(data.items[i]);
|
||||
}
|
||||
barrier();
|
||||
}).error($scope.handleError);
|
||||
}
|
||||
if (type === "" || type == "service") {
|
||||
k8sApi.getServices(query).success(function(data) {
|
||||
$scope.addLabel("type", "service", data.items);
|
||||
for (var i = 0; data.items && i < data.items.length; ++i) {
|
||||
list.push(data.items[i]);
|
||||
}
|
||||
barrier();
|
||||
}).error($scope.handleError);
|
||||
}
|
||||
if (type === "" || type == "replicationController") {
|
||||
k8sApi.getReplicationControllers(query).success(angular.bind(this, function(data) {
|
||||
$scope.addLabel("type", "replicationController", data.items);
|
||||
for (var i = 0; data.items && i < data.items.length; ++i) {
|
||||
list.push(data.items[i]);
|
||||
}
|
||||
barrier();
|
||||
})).error($scope.handleError);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addLabel = function(key, value, items) {
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (!items[i].metadata.labels) {
|
||||
items[i].metadata.labels = {};
|
||||
}
|
||||
items[i].metadata.labels[key] = value;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.groupData = function(items, index) {
|
||||
var result = {
|
||||
"items": {},
|
||||
"kind": "grouping"
|
||||
};
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
key = items[i].metadata.labels[decodeURIComponent($scope.groupBy[index])];
|
||||
if (!key) {
|
||||
key = "";
|
||||
}
|
||||
var list = result.items[key];
|
||||
if (!list) {
|
||||
list = [];
|
||||
result.items[key] = list;
|
||||
}
|
||||
list.push(items[i]);
|
||||
}
|
||||
|
||||
if (index + 1 < $scope.groupBy.length) {
|
||||
for (var key in result.items) {
|
||||
result.items[key] = $scope.groupData(result.items[key], index + 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
$scope.getGroupColor = function(type) {
|
||||
if (type === 'pod') {
|
||||
return '#6193F0';
|
||||
} else if (type === 'replicationController') {
|
||||
return '#E008FE';
|
||||
} else if (type === 'service') {
|
||||
return '#7C43FF';
|
||||
}
|
||||
};
|
||||
|
||||
var groups = $routeParams.grouping;
|
||||
if (!groups) {
|
||||
groups = '';
|
||||
}
|
||||
|
||||
$scope.routeParams = $routeParams;
|
||||
$scope.route = $route;
|
||||
|
||||
$scope.handleGroups(groups.split('/'), $routeParams.selector);
|
||||
|
||||
$scope.handleError = function(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
$scope_.loading = false;
|
||||
};
|
||||
|
||||
function getDefaultGroupByOptions() { return [{name: 'Type', value: 'type'}, {name: 'Name', value: 'name'}]; }
|
||||
|
||||
function buildGroupByOptions() {
|
||||
var g = $scope.groups;
|
||||
var options = getDefaultGroupByOptions();
|
||||
var newOptions = _.map(g.items, function(vals) { return _.map(vals, function(v) { return _.keys(v.metadata.labels); }); });
|
||||
newOptions =
|
||||
_.reject(_.uniq(_.flattenDeep(newOptions)), function(o) { return o == 'name' || o == 'type' || o == ""; });
|
||||
newOptions = _.map(newOptions, function(o) {
|
||||
return {
|
||||
name: o,
|
||||
value: o
|
||||
};
|
||||
});
|
||||
|
||||
options = options.concat(newOptions);
|
||||
return options;
|
||||
}
|
||||
|
||||
$scope.changeFilterBy = function(selector) {
|
||||
var grouping = $scope.selectedGroupBy;
|
||||
|
||||
var s = _.clone($location.search());
|
||||
if ($scope.routeParams.selector != selector)
|
||||
$location.path("/dashboard/groups/" + $scope.routeParams.grouping + "/selector/" + selector).search(s);
|
||||
};
|
||||
}
|
||||
]);
|
@@ -1,27 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Header
|
||||
* Visualizer for clusters
|
||||
=========================================================*/
|
||||
|
||||
angular.module('kubernetesApp.components.dashboard', [])
|
||||
.controller('HeaderCtrl', [
|
||||
'$scope',
|
||||
'$location',
|
||||
function($scope, $location) {
|
||||
'use strict';
|
||||
$scope.$watch('Pages', function(newValue, oldValue) {
|
||||
if (typeof newValue !== 'undefined') {
|
||||
$location.path(newValue);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.subPages = [
|
||||
{category: 'dashboard', name: 'Explore', value: '/dashboard/groups/type/selector/'},
|
||||
{category: 'dashboard', name: 'Pods', value: '/dashboard/pods'},
|
||||
{category: 'dashboard', name: 'Nodes', value: '/dashboard/nodes'},
|
||||
{category: 'dashboard', name: 'Replication Controllers', value: '/dashboard/replicationcontrollers'},
|
||||
{category: 'dashboard', name: 'Services', value: '/dashboard/services'},
|
||||
{category: 'dashboard', name: 'Events', value: '/dashboard/events'}
|
||||
];
|
||||
}
|
||||
]);
|
@@ -1,90 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: List Events
|
||||
* Visualizer list events
|
||||
=========================================================*/
|
||||
|
||||
app.controller('ListEventsCtrl', [
|
||||
'$scope',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'$location',
|
||||
'$filter',
|
||||
function($scope, $routeParams, k8sApi, $location, $filter) {
|
||||
'use strict';
|
||||
$scope.getData = getData;
|
||||
$scope.loading = true;
|
||||
$scope.k8sApi = k8sApi;
|
||||
$scope.pods = null;
|
||||
$scope.groupedPods = null;
|
||||
$scope.serverView = false;
|
||||
|
||||
$scope.headers = [
|
||||
{name: 'Last Seen', field: 'lastSeen'},
|
||||
{name: 'First Seen', field: 'firstSeen'},
|
||||
{name: 'Count', field: 'count'},
|
||||
{name: 'Name', field: 'name'},
|
||||
{name: 'Kind', field: 'kind'},
|
||||
{name: 'SubObject', field: 'subObject'},
|
||||
{name: 'Reason', field: 'reason'},
|
||||
{name: 'Source', field: 'source'},
|
||||
{name: 'Message', field: 'message'}
|
||||
];
|
||||
|
||||
|
||||
$scope.sortable = ['lastSeen', 'firstSeen', 'count', 'name', 'kind', 'subObject', 'reason', 'source', 'message'];
|
||||
$scope.count = 50;
|
||||
function handleError(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
$scope.loading = false;
|
||||
}
|
||||
|
||||
$scope.content = [];
|
||||
|
||||
function getData() {
|
||||
$scope.loading = true;
|
||||
k8sApi.getEvents().success(function(data) {
|
||||
$scope.loading = false;
|
||||
|
||||
var _fixComma = function(str) {
|
||||
if (str.substring(0, 1) == ',') {
|
||||
return str.substring(1);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
data.items.forEach(function(event) {
|
||||
var _sources = '';
|
||||
if (event.source) {
|
||||
_sources = event.source.component + ' ' + event.source.host;
|
||||
}
|
||||
|
||||
|
||||
$scope.content.push({
|
||||
firstSeen: $filter('date')(event.firstTimestamp, 'medium'),
|
||||
lastSeen: $filter('date')(event.lastTimestamp, 'medium'),
|
||||
count: event.count,
|
||||
name: event.involvedObject.name,
|
||||
kind: event.involvedObject.kind,
|
||||
subObject: event.involvedObject.fieldPath,
|
||||
reason: event.reason,
|
||||
source: _sources,
|
||||
message: event.message
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
$scope.content = _.sortBy($scope.content, function(e){
|
||||
return e.lastSeen;
|
||||
}).reverse();
|
||||
|
||||
|
||||
}).error($scope.handleError);
|
||||
}
|
||||
|
||||
getData();
|
||||
|
||||
}
|
||||
]);
|
@@ -1,72 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Minions
|
||||
* Visualizer for minions
|
||||
=========================================================*/
|
||||
|
||||
app.controller('ListMinionsCtrl', [
|
||||
'$scope',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'$location',
|
||||
function($scope, $routeParams, k8sApi, $location) {
|
||||
'use strict';
|
||||
$scope.getData = getData;
|
||||
$scope.loading = true;
|
||||
$scope.k8sApi = k8sApi;
|
||||
$scope.pods = null;
|
||||
$scope.groupedPods = null;
|
||||
$scope.serverView = false;
|
||||
|
||||
$scope.headers = [{name: 'Name', field: 'name'}, {name: 'Addresses', field: 'addresses'}, {name: 'Status', field: 'status'}];
|
||||
|
||||
$scope.custom = {
|
||||
name: '',
|
||||
status: 'grey',
|
||||
ip: 'grey'
|
||||
};
|
||||
$scope.sortable = ['name', 'status', 'addresses'];
|
||||
$scope.thumbs = 'thumb';
|
||||
$scope.count = 50;
|
||||
|
||||
$scope.go = function(d) { $location.path('/dashboard/nodes/' + d.name); };
|
||||
|
||||
|
||||
function handleError(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
$scope.loading = false;
|
||||
}
|
||||
|
||||
$scope.content = [];
|
||||
|
||||
function getData() {
|
||||
$scope.loading = true;
|
||||
k8sApi.getMinions().success(function(data) {
|
||||
$scope.loading = false;
|
||||
|
||||
var _fixComma = function(str) {
|
||||
if (str.substring(0, 1) == ',') {
|
||||
return str.substring(1);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
data.items.forEach(function(minion) {
|
||||
var _statusType = '';
|
||||
|
||||
if (minion.status.conditions) {
|
||||
Object.keys(minion.status.conditions)
|
||||
.forEach(function(key) { _statusType += minion.status.conditions[key].type; });
|
||||
}
|
||||
|
||||
|
||||
$scope.content.push({name: minion.metadata.name, addresses: _.map(minion.status.addresses, function(a) { return a.address }).join(', '), status: _statusType});
|
||||
});
|
||||
|
||||
}).error($scope.handleError);
|
||||
}
|
||||
|
||||
getData();
|
||||
|
||||
}
|
||||
]);
|
@@ -1,123 +0,0 @@
|
||||
|
||||
|
||||
app.controller('ListPodsCtrl', [
|
||||
'$scope',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'lodash',
|
||||
'$location',
|
||||
function($scope, $routeParams, k8sApi, lodash, $location) {
|
||||
var _ = lodash;
|
||||
$scope.getData = getData;
|
||||
$scope.loading = true;
|
||||
$scope.k8sApi = k8sApi;
|
||||
$scope.pods = null;
|
||||
$scope.groupedPods = null;
|
||||
$scope.serverView = false;
|
||||
|
||||
$scope.headers = [
|
||||
{name: 'Pod', field: 'pod'},
|
||||
{name: 'IP', field: 'ip'},
|
||||
{name: 'Status', field: 'status'},
|
||||
{name: 'Containers', field: 'containers'},
|
||||
{name: 'Images', field: 'images'},
|
||||
{name: 'Host', field: 'host'},
|
||||
{name: 'Labels', field: 'labels'}
|
||||
];
|
||||
|
||||
$scope.custom = {
|
||||
pod: '',
|
||||
ip: 'grey',
|
||||
containers: 'grey',
|
||||
images: 'grey',
|
||||
host: 'grey',
|
||||
labels: 'grey',
|
||||
status: 'grey'
|
||||
};
|
||||
$scope.sortable = ['pod', 'ip', 'status','containers','images','host','labels'];
|
||||
$scope.count = 50;
|
||||
|
||||
$scope.go = function(data) { $location.path('/dashboard/pods/' + data.pod); };
|
||||
|
||||
var orderedPodNames = [];
|
||||
|
||||
function handleError(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
$scope.loading = false;
|
||||
};
|
||||
|
||||
function getPodName(pod) { return _.has(pod.metadata.labels, 'name') ? pod.metadata.labels.name : pod.metadata.name; }
|
||||
|
||||
$scope.content = [];
|
||||
|
||||
function getData() {
|
||||
$scope.loading = true;
|
||||
k8sApi.getPods().success(angular.bind(this, function(data) {
|
||||
$scope.loading = false;
|
||||
|
||||
var _fixComma = function(str) {
|
||||
if (str.substring(0, 1) == ',') {
|
||||
return str.substring(1);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
data.items.forEach(function(pod) {
|
||||
var _containers = '', _images = '', _labels = '', _uses = '';
|
||||
|
||||
if (pod.spec) {
|
||||
Object.keys(pod.spec.containers)
|
||||
.forEach(function(key) {
|
||||
_containers += ', ' + pod.spec.containers[key].name;
|
||||
_images += ', ' + pod.spec.containers[key].image;
|
||||
});
|
||||
}
|
||||
|
||||
if (pod.metadata.labels) {
|
||||
_labels = _.map(pod.metadata.labels, function(v, k) { return k + ': ' + v }).join(', ');
|
||||
}
|
||||
|
||||
$scope.content.push({
|
||||
pod: pod.metadata.name,
|
||||
ip: pod.status.podIP,
|
||||
containers: _fixComma(_containers),
|
||||
images: _fixComma(_images),
|
||||
host: pod.spec.nodeName,
|
||||
labels: _labels,
|
||||
status: pod.status.phase
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})).error(angular.bind(this, handleError));
|
||||
};
|
||||
|
||||
$scope.getPodRestarts = function(pod) {
|
||||
var r = null;
|
||||
var container = _.first(pod.spec.containers);
|
||||
if (container) r = pod.status.containerStatuses[container.name].restartCount;
|
||||
return r;
|
||||
};
|
||||
|
||||
$scope.otherLabels = function(labels) { return _.omit(labels, 'name') };
|
||||
|
||||
$scope.podStatusClass = function(pod) {
|
||||
|
||||
var s = pod.status.phase.toLowerCase();
|
||||
|
||||
if (s == 'running' || s == 'succeeded')
|
||||
return null;
|
||||
else
|
||||
return "status-" + s;
|
||||
};
|
||||
|
||||
$scope.podIndexFromName = function(pod) {
|
||||
var name = getPodName(pod);
|
||||
return _.indexOf(orderedPodNames, name) + 1;
|
||||
};
|
||||
|
||||
getData();
|
||||
|
||||
}
|
||||
]);
|
@@ -1,95 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Replication Controllers
|
||||
* Visualizer for replication controllers
|
||||
=========================================================*/
|
||||
|
||||
app.controller('ListReplicationControllersCtrl', [
|
||||
'$scope',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'$location',
|
||||
function($scope, $routeParams, k8sApi, $location) {
|
||||
'use strict';
|
||||
$scope.getData = getData;
|
||||
$scope.loading = true;
|
||||
$scope.k8sApi = k8sApi;
|
||||
$scope.pods = null;
|
||||
$scope.groupedPods = null;
|
||||
$scope.serverView = false;
|
||||
|
||||
$scope.headers = [
|
||||
{name: 'Controller', field: 'controller'},
|
||||
{name: 'Containers', field: 'containers'},
|
||||
{name: 'Images', field: 'images'},
|
||||
{name: 'Selector', field: 'selector'},
|
||||
{name: 'Replicas', field: 'replicas'}
|
||||
];
|
||||
|
||||
$scope.custom = {
|
||||
controller: '',
|
||||
containers: 'grey',
|
||||
images: 'grey',
|
||||
selector: 'grey',
|
||||
replicas: 'grey'
|
||||
};
|
||||
$scope.sortable = ['controller', 'containers', 'images', 'selector', 'replicas'];
|
||||
$scope.thumbs = 'thumb';
|
||||
$scope.count = 50;
|
||||
|
||||
$scope.go = function(data) { $location.path('/dashboard/replicationcontrollers/' + data.controller); };
|
||||
|
||||
function handleError(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
$scope.loading = false;
|
||||
}
|
||||
|
||||
$scope.content = [];
|
||||
|
||||
function getData() {
|
||||
$scope.loading = true;
|
||||
k8sApi.getReplicationControllers().success(function(data) {
|
||||
$scope.loading = false;
|
||||
|
||||
var _fixComma = function(str) {
|
||||
if (str.substring(0, 1) == ',') {
|
||||
return str.substring(1);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
data.items.forEach(function(replicationController) {
|
||||
|
||||
var _name = '', _image = '';
|
||||
|
||||
if (replicationController.spec.template.spec.containers) {
|
||||
Object.keys(replicationController.spec.template.spec.containers)
|
||||
.forEach(function(key) {
|
||||
_name += replicationController.spec.template.spec.containers[key].name;
|
||||
_image += replicationController.spec.template.spec.containers[key].image;
|
||||
});
|
||||
}
|
||||
|
||||
var _selectors = '';
|
||||
|
||||
if (replicationController.spec.selector) {
|
||||
_selectors = _.map(replicationController.spec.selector, function(v, k) { return k + '=' + v }).join(', ');
|
||||
}
|
||||
|
||||
$scope.content.push({
|
||||
controller: replicationController.metadata.name,
|
||||
containers: _name,
|
||||
images: _image,
|
||||
selector: _selectors,
|
||||
replicas: replicationController.status.replicas
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}).error($scope.handleError);
|
||||
}
|
||||
|
||||
getData();
|
||||
|
||||
}
|
||||
]);
|
@@ -1,108 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Services
|
||||
* Visualizer for services
|
||||
=========================================================*/
|
||||
|
||||
app.controller('ListServicesCtrl', [
|
||||
'$scope',
|
||||
'$interval',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'$rootScope',
|
||||
'$location',
|
||||
function($scope, $interval, $routeParams, k8sApi, $rootScope, $location) {
|
||||
'use strict';
|
||||
$scope.doTheBack = function() { window.history.back(); };
|
||||
|
||||
$scope.headers = [
|
||||
{name: 'Name', field: 'name'},
|
||||
{name: 'Labels', field: 'labels'},
|
||||
{name: 'Selector', field: 'selector'},
|
||||
{name: 'IP', field: 'ip'},
|
||||
{name: 'Ports', field: 'port'}
|
||||
];
|
||||
|
||||
$scope.custom = {
|
||||
name: '',
|
||||
ip: 'grey',
|
||||
selector: 'grey',
|
||||
port: 'grey',
|
||||
labels: 'grey'
|
||||
};
|
||||
$scope.sortable = ['name', 'ip', 'port', 'labels', 'selector'];
|
||||
$scope.count = 50;
|
||||
|
||||
$scope.go = function(data) { $location.path('/dashboard/services/' + data.name); };
|
||||
|
||||
$scope.content = [];
|
||||
|
||||
$rootScope.doTheBack = $scope.doTheBack;
|
||||
|
||||
$scope.handleError = function(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
$scope_.loading = false;
|
||||
};
|
||||
|
||||
$scope.getData = function() {
|
||||
$scope.loading = true;
|
||||
k8sApi.getServices().success(angular.bind(this, function(data) {
|
||||
$scope.services = data;
|
||||
$scope.loading = false;
|
||||
|
||||
var _fixComma = function(str) {
|
||||
if (str.substring(0, 1) == ',') {
|
||||
return str.substring(1);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
var addLabel = function(str, label) {
|
||||
if (str) {
|
||||
str = label + str;
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
if (data.items.constructor === Array) {
|
||||
data.items.forEach(function(service) {
|
||||
|
||||
var _labels = '';
|
||||
|
||||
if (service.metadata.labels) {
|
||||
_labels = _.map(service.metadata.labels, function(v, k) { return k + ': ' + v }).join(', ');
|
||||
}
|
||||
|
||||
var _selectors = '';
|
||||
|
||||
if (service.spec.selector) {
|
||||
_selectors = _.map(service.spec.selector, function(v, k) { return k + '=' + v }).join(', ');
|
||||
}
|
||||
|
||||
var _ports = '';
|
||||
|
||||
if (service.spec.ports) {
|
||||
_ports = _.map(service.spec.ports, function(p) {
|
||||
var n = '';
|
||||
if(p.name)
|
||||
n = p.name + ': ';
|
||||
n = n + p.port;
|
||||
return n;
|
||||
}).join(', ');
|
||||
}
|
||||
|
||||
$scope.content.push({
|
||||
name: service.metadata.name,
|
||||
ip: service.spec.clusterIP,
|
||||
port: _ports,
|
||||
selector: _selectors,
|
||||
labels: _labels
|
||||
});
|
||||
});
|
||||
}
|
||||
})).error($scope.handleError);
|
||||
};
|
||||
|
||||
$scope.getData();
|
||||
}
|
||||
]);
|
@@ -1,33 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Nodes
|
||||
* Visualizer for nodes
|
||||
=========================================================*/
|
||||
|
||||
app.controller('NodeCtrl', [
|
||||
'$scope',
|
||||
'$interval',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'$rootScope',
|
||||
function($scope, $interval, $routeParams, k8sApi, $rootScope) {
|
||||
'use strict';
|
||||
$scope.doTheBack = function() { window.history.back(); };
|
||||
|
||||
$rootScope.doTheBack = $scope.doTheBack;
|
||||
|
||||
$scope.handleError = function(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
$scope_.loading = false;
|
||||
};
|
||||
|
||||
$scope.handleNode = function(nodeId) {
|
||||
$scope.loading = true;
|
||||
k8sApi.getNodes(nodeId).success(angular.bind(this, function(data) {
|
||||
$scope.node = data;
|
||||
$scope.loading = false;
|
||||
})).error($scope.handleError);
|
||||
};
|
||||
|
||||
$scope.handleNode($routeParams.nodeId);
|
||||
}
|
||||
]);
|
@@ -1,33 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Pods
|
||||
* Visualizer for pods
|
||||
=========================================================*/
|
||||
|
||||
app.controller('PodCtrl', [
|
||||
'$scope',
|
||||
'$interval',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'$rootScope',
|
||||
function($scope, $interval, $routeParams, k8sApi, $rootScope) {
|
||||
'use strict';
|
||||
$scope.doTheBack = function() { window.history.back(); };
|
||||
|
||||
$rootScope.doTheBack = $scope.doTheBack;
|
||||
|
||||
$scope.handleError = function(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
$scope_.loading = false;
|
||||
};
|
||||
|
||||
$scope.handlePod = function(podId) {
|
||||
$scope.loading = true;
|
||||
k8sApi.getPods(podId).success(angular.bind(this, function(data) {
|
||||
$scope.pod = data;
|
||||
$scope.loading = false;
|
||||
})).error($scope.handleError);
|
||||
};
|
||||
|
||||
$scope.handlePod($routeParams.podId);
|
||||
}
|
||||
]);
|
@@ -1,36 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Replication
|
||||
* Visualizer for replication controllers
|
||||
=========================================================*/
|
||||
|
||||
function ReplicationController() {
|
||||
}
|
||||
|
||||
ReplicationController.prototype.getData = function(dataId) {
|
||||
this.scope.loading = true;
|
||||
this.k8sApi.getReplicationControllers(dataId).success(angular.bind(this, function(data) {
|
||||
this.scope.replicationController = data;
|
||||
this.scope.loading = false;
|
||||
})).error(angular.bind(this, this.handleError));
|
||||
};
|
||||
|
||||
ReplicationController.prototype.handleError = function(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
this.scope.loading = false;
|
||||
};
|
||||
|
||||
app.controller('ReplicationControllerCtrl', [
|
||||
'$scope',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
function($scope, $routeParams, k8sApi) {
|
||||
$scope.controller = new ReplicationController();
|
||||
$scope.controller.k8sApi = k8sApi;
|
||||
$scope.controller.scope = $scope;
|
||||
$scope.controller.getData($routeParams.replicationControllerId);
|
||||
|
||||
$scope.doTheBack = function() { window.history.back(); };
|
||||
$scope.getSelectorUrlFragment = function(sel){ return _.map(sel, function(v, k) { return k + '=' + v }).join(','); };
|
||||
|
||||
}
|
||||
]);
|
@@ -1,38 +0,0 @@
|
||||
/**=========================================================
|
||||
* Module: Services
|
||||
* Visualizer for services
|
||||
=========================================================*/
|
||||
|
||||
function ServiceController() {
|
||||
}
|
||||
|
||||
ServiceController.prototype.getData = function(dataId) {
|
||||
this.scope.loading = true;
|
||||
this.k8sApi.getServices(dataId).success(angular.bind(this, function(data) {
|
||||
this.scope.service = data;
|
||||
this.scope.loading = false;
|
||||
})).error(angular.bind(this, this.handleError));
|
||||
};
|
||||
|
||||
ServiceController.prototype.handleError = function(data, status, headers, config) {
|
||||
console.log("Error (" + status + "): " + data);
|
||||
this.scope.loading = false;
|
||||
};
|
||||
|
||||
app.controller('ServiceCtrl', [
|
||||
'$scope',
|
||||
'$routeParams',
|
||||
'k8sApi',
|
||||
'$location',
|
||||
function($scope, $routeParams, k8sApi, $location) {
|
||||
$scope.controller = new ServiceController();
|
||||
$scope.controller.k8sApi = k8sApi;
|
||||
$scope.controller.scope = $scope;
|
||||
$scope.controller.getData($routeParams.serviceId);
|
||||
|
||||
$scope.doTheBack = function() { window.history.back(); };
|
||||
$scope.go = function(d) { $location.path('/dashboard/services/' + d.metadata.name); }
|
||||
$scope.getSelectorUrlFragment = function(sel){ return _.map(sel, function(v, k) { return k + '=' + v }).join(','); };
|
||||
|
||||
}
|
||||
]);
|
@@ -1,345 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('kubernetesApp.components.dashboard')
|
||||
.directive('d3MinionBarGauge', [
|
||||
'd3DashboardService',
|
||||
function(d3DashboardService) {
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
data: '=',
|
||||
thickness: '@',
|
||||
graphWidth: '@',
|
||||
graphHeight: '@'
|
||||
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
var draw = function(d3) {
|
||||
var svg = d3.select("svg.chart");
|
||||
var legendSvg = d3.select("svg.legend");
|
||||
window.onresize = function() { return scope.$apply(); };
|
||||
|
||||
scope.$watch(function() { return angular.element(window)[0].innerWidth; },
|
||||
function() { return scope.render(scope.data); });
|
||||
|
||||
scope.$watch('data', function(newVals, oldVals) {
|
||||
return initOrUpdate(newVals, oldVals);
|
||||
|
||||
}, true);
|
||||
|
||||
function initOrUpdate(newVals, oldVals) {
|
||||
if (oldVals === null || oldVals === undefined) {
|
||||
return scope.render(newVals);
|
||||
} else {
|
||||
return update(oldVals, newVals);
|
||||
}
|
||||
}
|
||||
|
||||
var textOffset = 10;
|
||||
var el = null;
|
||||
var radius = 100;
|
||||
var oldData = [];
|
||||
|
||||
function init(options) {
|
||||
var clone = options.data;
|
||||
var preparedData = setData(clone);
|
||||
setup(preparedData, options.width, options.height);
|
||||
}
|
||||
|
||||
function setup(data, w, h) {
|
||||
svg = d3.select(element[0]).append("svg").attr("width", "100%");
|
||||
|
||||
legendSvg = d3.select(element[0]).append("svg").attr("width", "100%");
|
||||
|
||||
var chart = svg.attr("class", "chart")
|
||||
.attr("width", w)
|
||||
.attr("height", h - 25)
|
||||
.append("svg:g")
|
||||
.attr("class", "concentricchart")
|
||||
.attr("transform", "translate(" + ((w / 2)) + "," + h / 4 + ")");
|
||||
|
||||
var legend = legendSvg.attr("class", "legend").attr("width", w);
|
||||
|
||||
radius = Math.min(w, h) / 2;
|
||||
|
||||
var hostName = legendSvg.append("text")
|
||||
.attr("class", "hostName")
|
||||
.attr("transform", "translate(" + ((w - 120) / 2) + "," + 15 + ")");
|
||||
|
||||
var label_legend_area = legendSvg.append("svg:g")
|
||||
.attr("class", "label_legend_area")
|
||||
.attr("transform", "translate(" + ((w - 215) / 2) + "," + 35 + ")");
|
||||
|
||||
var legend_group = label_legend_area.append("svg:g").attr("class", "legend_group");
|
||||
|
||||
var label_group = label_legend_area.append("svg:g")
|
||||
.attr("class", "label_group")
|
||||
.attr("transform", "translate(" + 25 + "," + 11 + ")");
|
||||
|
||||
var stats_group = label_legend_area.append("svg:g")
|
||||
.attr("class", "stats_group")
|
||||
.attr("transform", "translate(" + 115 + "," + 11 + ")");
|
||||
|
||||
var path_group = chart.append("svg:g")
|
||||
.attr("class", "path_group")
|
||||
.attr("transform", "translate(0," + (h / 4) + ")");
|
||||
var value_group = chart.append("svg:g")
|
||||
.attr("class", "value_group")
|
||||
.attr("transform", "translate(" + -(w * 0.205) + "," + -(h * 0.10) + ")");
|
||||
generateArcs(chart, data);
|
||||
}
|
||||
|
||||
function update(_oldData, _newData) {
|
||||
if (_newData === undefined || _newData === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var clone = jQuery.extend(true, {}, _newData);
|
||||
var cloneOld = jQuery.extend(true, {}, _oldData);
|
||||
var preparedData = setData(clone);
|
||||
oldData = setData(cloneOld);
|
||||
animate(preparedData);
|
||||
}
|
||||
|
||||
function animate(data) { generateArcs(null, data); }
|
||||
|
||||
function setData(data) {
|
||||
var diameter = 2 * Math.PI * radius;
|
||||
var localData = [];
|
||||
|
||||
$.each(data[0].segments, function(ri, value) {
|
||||
|
||||
function calcAngles(v) {
|
||||
var segmentValueSum = 200;
|
||||
if (v > segmentValueSum) {
|
||||
v = segmentValueSum;
|
||||
}
|
||||
|
||||
var segmentValue = v;
|
||||
var fraction = segmentValue / segmentValueSum;
|
||||
var arcBatchLength = fraction * 4 * Math.PI;
|
||||
var arcPartition = arcBatchLength;
|
||||
var startAngle = Math.PI * 2;
|
||||
var endAngle = startAngle + arcPartition;
|
||||
|
||||
return {
|
||||
startAngle: startAngle,
|
||||
endAngle: endAngle
|
||||
};
|
||||
}
|
||||
|
||||
var valueData = calcAngles(value.value);
|
||||
data[0].segments[ri].startAngle = valueData.startAngle;
|
||||
data[0].segments[ri].endAngle = valueData.endAngle;
|
||||
|
||||
var maxData = value.maxData;
|
||||
var maxTickData = calcAngles(maxData.maxValue + 0.2);
|
||||
data[0].segments[ri].maxTickStartAngle = maxTickData.startAngle;
|
||||
data[0].segments[ri].maxTickEndAngle = maxTickData.endAngle;
|
||||
|
||||
var maxArcData = calcAngles(maxData.maxValue);
|
||||
data[0].segments[ri].maxArcStartAngle = maxArcData.startAngle;
|
||||
data[0].segments[ri].maxArcEndAngle = maxArcData.endAngle;
|
||||
|
||||
data[0].segments[ri].index = ri;
|
||||
});
|
||||
localData.push(data[0].segments);
|
||||
return localData[0];
|
||||
}
|
||||
|
||||
function generateArcs(_svg, data) {
|
||||
var chart = svg;
|
||||
var transitionTime = 750;
|
||||
$.each(data, function(index, value) {
|
||||
if (oldData[index] !== undefined) {
|
||||
data[index].previousEndAngle = oldData[index].endAngle;
|
||||
} else {
|
||||
data[index].previousEndAngle = 0;
|
||||
}
|
||||
});
|
||||
var thickness = parseInt(scope.thickness, 10);
|
||||
var ir = (parseInt(scope.graphWidth, 10) / 3);
|
||||
var path_group = svg.select('.path_group');
|
||||
var arc_group = path_group.selectAll(".arc_group").data(data);
|
||||
var arcEnter = arc_group.enter().append("g").attr("class", "arc_group");
|
||||
|
||||
arcEnter.append("path").attr("class", "bg-circle").attr("d", getBackgroundArc(thickness, ir));
|
||||
|
||||
arcEnter.append("path")
|
||||
.attr("class", function(d, i) { return 'max_tick_arc ' + d.maxData.maxTickClassNames; });
|
||||
|
||||
arcEnter.append("path")
|
||||
.attr("class", function(d, i) { return 'max_bg_arc ' + d.maxData.maxClassNames; });
|
||||
|
||||
arcEnter.append("path").attr("class", function(d, i) { return 'value_arc ' + d.classNames; });
|
||||
|
||||
var max_tick_arc = arc_group.select(".max_tick_arc");
|
||||
|
||||
max_tick_arc.transition()
|
||||
.attr("class", function(d, i) { return 'max_tick_arc ' + d.maxData.maxTickClassNames; })
|
||||
.attr("d", function(d) {
|
||||
var arc = maxArc(thickness, ir);
|
||||
arc.startAngle(d.maxTickStartAngle);
|
||||
arc.endAngle(d.maxTickEndAngle);
|
||||
return arc(d);
|
||||
});
|
||||
|
||||
var max_bg_arc = arc_group.select(".max_bg_arc");
|
||||
|
||||
max_bg_arc.transition()
|
||||
.attr("class", function(d, i) { return 'max_bg_arc ' + d.maxData.maxClassNames; })
|
||||
.attr("d", function(d) {
|
||||
var arc = maxArc(thickness, ir);
|
||||
arc.startAngle(d.maxArcStartAngle);
|
||||
arc.endAngle(d.maxArcEndAngle);
|
||||
return arc(d);
|
||||
});
|
||||
|
||||
var value_arc = arc_group.select(".value_arc");
|
||||
|
||||
value_arc.transition().ease("exp").attr("class", function(d, i) {
|
||||
return 'value_arc ' + d.classNames;
|
||||
}).duration(transitionTime).attrTween("d", function(d) { return arcTween(d, thickness, ir); });
|
||||
|
||||
arc_group.exit()
|
||||
.select(".value_arc")
|
||||
.transition()
|
||||
.ease("exp")
|
||||
.duration(transitionTime)
|
||||
.attrTween("d", function(d) { return arcTween(d, thickness, ir); })
|
||||
.remove();
|
||||
|
||||
drawLabels(chart, data, ir, thickness);
|
||||
buildLegend(chart, data);
|
||||
}
|
||||
|
||||
function arcTween(b, thickness, ir) {
|
||||
var prev = JSON.parse(JSON.stringify(b));
|
||||
prev.endAngle = b.previousEndAngle;
|
||||
var i = d3.interpolate(prev, b);
|
||||
return function(t) { return getArc(thickness, ir)(i(t)); };
|
||||
}
|
||||
|
||||
function maxArc(thickness, ir) {
|
||||
var arc = d3.svg.arc().innerRadius(function(d) {
|
||||
return getRadiusRing(ir, d.index);
|
||||
}).outerRadius(function(d) { return getRadiusRing(ir + thickness, d.index); });
|
||||
return arc;
|
||||
}
|
||||
|
||||
function drawLabels(chart, data, ir, thickness) {
|
||||
svg.select('.value_group').selectAll("*").remove();
|
||||
var counts = data.length;
|
||||
var value_group = chart.select('.value_group');
|
||||
var valueLabels = value_group.selectAll("text.value").data(data);
|
||||
valueLabels.enter()
|
||||
.append("svg:text")
|
||||
.attr("class", "value")
|
||||
.attr("dx", function(d, i) { return 68; })
|
||||
.attr("dy", function(d, i) { return (thickness + 3) * i; })
|
||||
.attr("text-anchor", function(d) { return "start"; })
|
||||
.text(function(d) { return d.value; });
|
||||
valueLabels.transition().duration(300).attrTween(
|
||||
"d", function(d) { return arcTween(d, thickness, ir); });
|
||||
valueLabels.exit().remove();
|
||||
}
|
||||
|
||||
function buildLegend(chart, data) {
|
||||
var svg = legendSvg;
|
||||
svg.select('.label_group').selectAll("*").remove();
|
||||
svg.select('.legend_group').selectAll("*").remove();
|
||||
svg.select('.stats_group').selectAll("*").remove();
|
||||
|
||||
var host_name = svg.select('.hostName');
|
||||
var label_group = svg.select('.label_group');
|
||||
var stats_group = svg.select('.stats_group');
|
||||
|
||||
host_name.text(data[0].hostName);
|
||||
|
||||
host_name = svg.selectAll("text.hostName").data(data);
|
||||
|
||||
host_name.attr("text-anchor", function(d) { return "start"; })
|
||||
.text(function(d) { return d.hostName; });
|
||||
host_name.exit().remove();
|
||||
|
||||
var labels = label_group.selectAll("text.labels").data(data);
|
||||
labels.enter()
|
||||
.append("svg:text")
|
||||
.attr("class", "labels")
|
||||
.attr("dy", function(d, i) { return 19 * i; })
|
||||
.attr("text-anchor", function(d) { return "start"; })
|
||||
.text(function(d) { return d.label; });
|
||||
labels.exit().remove();
|
||||
|
||||
var stats = stats_group.selectAll("text.stats").data(data);
|
||||
stats.enter()
|
||||
.append("svg:text")
|
||||
.attr("class", "stats")
|
||||
.attr("dy", function(d, i) { return 19 * i; })
|
||||
.attr("text-anchor", function(d) { return "start"; })
|
||||
.text(function(d) { return d.stats; });
|
||||
stats.exit().remove();
|
||||
|
||||
var legend_group = svg.select('.legend_group');
|
||||
var legend = legend_group.selectAll("rect").data(data);
|
||||
legend.enter()
|
||||
.append("svg:rect")
|
||||
.attr("x", 2)
|
||||
.attr("y", function(d, i) { return 19 * i; })
|
||||
.attr("width", 13)
|
||||
.attr("height", 13)
|
||||
.attr("class", function(d, i) { return "rect " + d.classNames; });
|
||||
|
||||
legend.exit().remove();
|
||||
}
|
||||
|
||||
function getRadiusRing(ir, i) { return ir - (i * 20); }
|
||||
|
||||
function getArc(thickness, ir) {
|
||||
var arc = d3.svg.arc()
|
||||
.innerRadius(function(d) { return getRadiusRing(ir, d.index); })
|
||||
.outerRadius(function(d) { return getRadiusRing(ir + thickness, d.index); })
|
||||
.startAngle(function(d, i) { return d.startAngle; })
|
||||
.endAngle(function(d, i) { return d.endAngle; });
|
||||
return arc;
|
||||
}
|
||||
|
||||
function getBackgroundArc(thickness, ir) {
|
||||
var arc = d3.svg.arc()
|
||||
.innerRadius(function(d) { return getRadiusRing(ir, d.index); })
|
||||
.outerRadius(function(d) { return getRadiusRing(ir + thickness, d.index); })
|
||||
.startAngle(0)
|
||||
.endAngle(function() { return 2 * Math.PI; });
|
||||
return arc;
|
||||
}
|
||||
|
||||
scope.render = function(data) {
|
||||
if (data === undefined || data === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
d3.select(element[0]).select("svg.chart").remove();
|
||||
d3.select(element[0]).select("svg.legend").remove();
|
||||
|
||||
var graph = $(element[0]);
|
||||
var w = scope.graphWidth;
|
||||
var h = scope.graphHeight;
|
||||
|
||||
var options = {
|
||||
data: data,
|
||||
width: w,
|
||||
height: h
|
||||
};
|
||||
|
||||
init(options);
|
||||
};
|
||||
};
|
||||
d3DashboardService.d3().then(draw);
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
}());
|
@@ -1,103 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('kubernetesApp.components.dashboard')
|
||||
.directive(
|
||||
'dashboardHeader',
|
||||
function() {
|
||||
'use strict';
|
||||
return {
|
||||
restrict: 'A',
|
||||
replace: true,
|
||||
scope: {user: '='},
|
||||
templateUrl: "components/dashboard/pages/header.html",
|
||||
controller: [
|
||||
'$scope',
|
||||
'$filter',
|
||||
'$location',
|
||||
'menu',
|
||||
'$rootScope',
|
||||
function($scope, $filter, $location, menu, $rootScope) {
|
||||
$scope.menu = menu;
|
||||
$scope.$watch('page', function(newValue, oldValue) {
|
||||
if (typeof newValue !== 'undefined') {
|
||||
$location.path(newValue);
|
||||
}
|
||||
});
|
||||
$scope.subpages = [
|
||||
{
|
||||
category: 'dashboard',
|
||||
name: 'Explore',
|
||||
value: '/dashboard/groups/type/selector/',
|
||||
id: 'groupsView'
|
||||
},
|
||||
{category: 'dashboard', name: 'Pods', value: '/dashboard/pods', id: 'podsView'},
|
||||
{category: 'dashboard', name: 'Nodes', value: '/dashboard/nodes', id: 'minionsView'},
|
||||
{
|
||||
category: 'dashboard',
|
||||
name: 'Replication Controllers',
|
||||
value: '/dashboard/replicationcontrollers',
|
||||
id: 'rcView'
|
||||
},
|
||||
{category: 'dashboard', name: 'Services', value: '/dashboard/services', id: 'servicesView'},
|
||||
{category: 'dashboard', name: 'Events', value: '/dashboard/events', id: 'eventsView'},
|
||||
];
|
||||
}
|
||||
]
|
||||
};
|
||||
})
|
||||
.directive('dashboardFooter',
|
||||
function() {
|
||||
'use strict';
|
||||
return {
|
||||
restrict: 'A',
|
||||
replace: true,
|
||||
templateUrl: "components/dashboard/pages/footer.html",
|
||||
controller: ['$scope', '$filter', function($scope, $filter) {}]
|
||||
};
|
||||
})
|
||||
.directive('mdTable', function() {
|
||||
'use strict';
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
headers: '=',
|
||||
content: '=',
|
||||
sortable: '=',
|
||||
filters: '=',
|
||||
customClass: '=customClass',
|
||||
thumbs: '=',
|
||||
count: '=',
|
||||
reverse: '=',
|
||||
doSelect: '&onSelect'
|
||||
},
|
||||
transclude: true,
|
||||
controller: function($scope, $filter, $window, $location) {
|
||||
var orderBy = $filter('orderBy');
|
||||
$scope.currentPage = 0;
|
||||
$scope.nbOfPages = function() { return Math.ceil($scope.content.length / $scope.count); };
|
||||
$scope.handleSort = function(field) {
|
||||
if ($scope.sortable.indexOf(field) > -1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
$scope.order = function(predicate, reverse) {
|
||||
$scope.content = orderBy($scope.content, predicate, reverse);
|
||||
$scope.predicate = predicate;
|
||||
};
|
||||
var reverse = false;
|
||||
if($scope.reverse)
|
||||
reverse = $scope.reverse;
|
||||
|
||||
$scope.order($scope.sortable[0], reverse);
|
||||
$scope.getNumber = function(num) { return new Array(num); };
|
||||
$scope.goToPage = function(page) { $scope.currentPage = page; };
|
||||
$scope.showMore = function() { return angular.isDefined($scope.moreClick);}
|
||||
},
|
||||
templateUrl: 'views/partials/md-table.tmpl.html'
|
||||
};
|
||||
});
|
||||
|
||||
}());
|
@@ -1,31 +0,0 @@
|
||||
angular.module('kubernetesApp.components.dashboard')
|
||||
.factory('d3DashboardService', [
|
||||
'$document',
|
||||
'$q',
|
||||
'$rootScope',
|
||||
function($document, $q, $rootScope) {
|
||||
var d = $q.defer();
|
||||
function onScriptLoad() {
|
||||
// Load client in the browser
|
||||
$rootScope.$apply(function() { d.resolve(window.d3); });
|
||||
}
|
||||
// Create a script tag with d3 as the source
|
||||
// and call our onScriptLoad callback when it
|
||||
// has been loaded
|
||||
var scriptTag = $document[0].createElement('script');
|
||||
scriptTag.type = 'text/javascript';
|
||||
scriptTag.async = true;
|
||||
scriptTag.src = 'vendor/d3/d3.min.js';
|
||||
scriptTag.onreadystatechange = function() {
|
||||
if (this.readyState == 'complete') onScriptLoad();
|
||||
};
|
||||
scriptTag.onload = onScriptLoad;
|
||||
|
||||
var s = $document[0].getElementsByTagName('body')[0];
|
||||
s.appendChild(scriptTag);
|
||||
|
||||
return {
|
||||
d3: function() { return d.promise; }
|
||||
};
|
||||
}
|
||||
]);
|
@@ -1,112 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('pods', []).service('podService', PodDataService);
|
||||
|
||||
/**
|
||||
* Pod DataService
|
||||
* Mock async data service.
|
||||
*
|
||||
* @returns {{loadAll: Function}}
|
||||
* @constructor
|
||||
*/
|
||||
function PodDataService($q) {
|
||||
var pods = {
|
||||
"kind": "Pod",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-master-c0r1n",
|
||||
"generateName": "redis-master-",
|
||||
"namespace": "default",
|
||||
"selfLink": "/api/v1/namespaces/default/pods/redis-master-c0r1n",
|
||||
"uid": "f12ddfaf-ff77-11e4-8f2d-080027213276",
|
||||
"resourceVersion": "39",
|
||||
"creationTimestamp": "2015-05-21T05:12:14Z",
|
||||
"labels": {
|
||||
"name": "redis-master"
|
||||
},
|
||||
"annotations": {
|
||||
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicationController\",\"namespace\":\"default\",\"name\":\"redis-master\",\"uid\":\"f12969e0-ff77-11e4-8f2d-080027213276\",\"apiVersion\":\"v1\",\"resourceVersion\":\"26\"}}"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"volumes": [
|
||||
{
|
||||
"name": "default-token-zb4rq",
|
||||
"secret": {
|
||||
"secretName": "default-token-zb4rq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
{
|
||||
"name": "master",
|
||||
"image": "redis",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 6379,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "default-token-zb4rq",
|
||||
"readOnly": true,
|
||||
"mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
|
||||
}
|
||||
],
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"capabilities": {},
|
||||
"securityContext": {
|
||||
"capabilities": {},
|
||||
"privileged": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"serviceAccount": "default",
|
||||
"host": "127.0.0.1"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"Condition": [
|
||||
{
|
||||
"type": "Ready",
|
||||
"status": "True"
|
||||
}
|
||||
],
|
||||
"hostIP": "127.0.0.1",
|
||||
"podIP": "172.17.0.1",
|
||||
"startTime": "2015-05-21T05:12:14Z",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "master",
|
||||
"state": {
|
||||
"running": {
|
||||
"startedAt": "2015-05-21T05:12:14Z"
|
||||
}
|
||||
},
|
||||
"lastState": {},
|
||||
"ready": true,
|
||||
"restartCount": 0,
|
||||
"image": "redis",
|
||||
"imageID": "docker://95af5842ddb9b03f7c6ec7601e65924cec516fcedd7e590ae31660057085cf67",
|
||||
"containerID": "docker://ae2a1e0a91a8b1015191a0b8e2ce8c55a86fb1a9a2b1e8e3b29430c9d93c8c09"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// Uses promises
|
||||
return {
|
||||
loadAll: function() {
|
||||
// Simulate async call
|
||||
return $q.when(pods);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
@@ -1,88 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('replicationControllers', [])
|
||||
.service('replicationControllerService', ReplicationControllerDataService);
|
||||
|
||||
/**
|
||||
* Replication Controller DataService
|
||||
* Mock async data service.
|
||||
*
|
||||
* @returns {{loadAll: Function}}
|
||||
* @constructor
|
||||
*/
|
||||
function ReplicationControllerDataService($q) {
|
||||
var replicationControllers = {
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "ReplicationController",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-master",
|
||||
"namespace": "default",
|
||||
"selfLink": "/api/v1/namespaces/default/replicationcontrollers/redis-master",
|
||||
"uid": "f12969e0-ff77-11e4-8f2d-080027213276",
|
||||
"resourceVersion": "28",
|
||||
"creationTimestamp": "2015-05-21T05:12:14Z",
|
||||
"labels": {
|
||||
"name": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"name": "redis-master"
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"name": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "master",
|
||||
"image": "redis",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 6379,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"capabilities": {},
|
||||
"securityContext": {
|
||||
"capabilities": {},
|
||||
"privileged": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"serviceAccount": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"replicas": 1
|
||||
}
|
||||
}
|
||||
]};
|
||||
|
||||
// Uses promises
|
||||
return {
|
||||
loadAll: function() {
|
||||
// Simulate async call
|
||||
return $q.when(replicationControllers);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
@@ -1,115 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('services', []).service('serviceService', ServiceDataService);
|
||||
|
||||
/**
|
||||
* Service DataService
|
||||
* Mock async data service.
|
||||
*
|
||||
* @returns {{loadAll: Function}}
|
||||
* @constructor
|
||||
*/
|
||||
function ServiceDataService($q) {
|
||||
var services = {
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "kubernetes",
|
||||
"namespace": "default",
|
||||
"selfLink": "/api/v1/namespaces/default/services/kubernetes",
|
||||
"resourceVersion": "6",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"component": "apiserver",
|
||||
"provider": "kubernetes"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"protocol": "TCP",
|
||||
"port": 443,
|
||||
"targetPort": 443
|
||||
}
|
||||
],
|
||||
"portalIP": "10.0.0.2",
|
||||
"sessionAffinity": "None"
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "kubernetes-ro",
|
||||
"namespace": "default",
|
||||
"selfLink": "/api/v1/namespaces/default/services/kubernetes-ro",
|
||||
"resourceVersion": "8",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"component": "apiserver",
|
||||
"provider": "kubernetes"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"protocol": "TCP",
|
||||
"port": 80,
|
||||
"targetPort": 80
|
||||
}
|
||||
],
|
||||
"portalIP": "10.0.0.1",
|
||||
"sessionAffinity": "None"
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-master",
|
||||
"namespace": "default",
|
||||
"selfLink": "/api/v1/namespaces/default/services/redis-master",
|
||||
"uid": "a6fde246-ff78-11e4-8f2d-080027213276",
|
||||
"resourceVersion": "72",
|
||||
"creationTimestamp": "2015-05-21T05:17:19Z",
|
||||
"labels": {
|
||||
"name": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"protocol": "TCP",
|
||||
"port": 6379,
|
||||
"targetPort": 6379
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"name": "redis-master"
|
||||
},
|
||||
"portalIP": "10.0.0.124",
|
||||
"sessionAffinity": "None"
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Uses promises
|
||||
return {
|
||||
loadAll: function() {
|
||||
// Simulate async call
|
||||
return $q.when(services);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
@@ -1,77 +0,0 @@
|
||||
.dashboard {
|
||||
.body-wrapper {
|
||||
padding: 25px;
|
||||
}
|
||||
// analogous to float:right when used with row layout
|
||||
[flex-align-self="end"] {
|
||||
-webkit-align-self: flex-end;
|
||||
-ms-flex-align-self: end;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.back {
|
||||
font-size: 18px;
|
||||
line-height: 27px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
font-size: 18px;
|
||||
line-height: 21px;
|
||||
color: #222222;
|
||||
margin-bottom: 25px;
|
||||
|
||||
.label {
|
||||
color: #777777;
|
||||
}
|
||||
}
|
||||
|
||||
@import "dashboard/pods";
|
||||
@import "dashboard/tables";
|
||||
@import "dashboard/servers";
|
||||
@import "dashboard/groups";
|
||||
|
||||
.detail {
|
||||
color: #222222;
|
||||
|
||||
.back {
|
||||
font-size: 18px;
|
||||
line-height: 27px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
font-size: 18px;
|
||||
line-height: 21px;
|
||||
color: #222222;
|
||||
margin-bottom: 25px;
|
||||
|
||||
.label {
|
||||
color: #777777;
|
||||
}
|
||||
}
|
||||
|
||||
td.name {
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
td.value {
|
||||
margin-left: 50px;
|
||||
font-size: 14px;
|
||||
color: #888888;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.containerTable {
|
||||
td {
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.align-top tbody {
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
@@ -1,124 +0,0 @@
|
||||
|
||||
@color-codes:
|
||||
"#2962FF",
|
||||
"#AA00FF",
|
||||
"#00C853",
|
||||
"#304FFE",
|
||||
"#0091EA",
|
||||
"#FF6D00",
|
||||
"#00BFA5",
|
||||
"#C51162",
|
||||
"#64DD17",
|
||||
"#6200EA",
|
||||
"#FFD600",
|
||||
"#00B8D4",
|
||||
"#FFAB00",
|
||||
"#DD2C00",
|
||||
"#2979FF",
|
||||
"#D500F9",
|
||||
"#00E676",
|
||||
"#3D5AFE",
|
||||
"#00B0FF",
|
||||
"#FF9100",
|
||||
"#1DE9B6",
|
||||
"#F50057",
|
||||
"#76FF03",
|
||||
"#651FFF",
|
||||
"#FFEA00",
|
||||
"#00E5FF",
|
||||
"#FFC400",
|
||||
"#FF3D00",
|
||||
"#448AFF",
|
||||
"#E040FB",
|
||||
"#69F0AE",
|
||||
"#536DFE",
|
||||
"#40C4FF",
|
||||
"#FFAB40",
|
||||
"#64FFDA",
|
||||
"#FF4081",
|
||||
"#B2FF59",
|
||||
"#7C4DFF",
|
||||
"#FFFF00",
|
||||
"#18FFFF",
|
||||
"#FFD740",
|
||||
"#FF6E40";
|
||||
|
||||
.dark-overlay {
|
||||
background-color: #292935;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.light-overlay {
|
||||
background-color: #FFFFFF;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
|
||||
// #D50000, //red-deep
|
||||
// #FF1744, //red-med
|
||||
// #FF5252, //red-light
|
||||
|
||||
@warningColor: #FF9800;
|
||||
@criticalColor: #F44336;
|
||||
|
||||
@freeColor: #2E2E3B;
|
||||
@errorColor: #FF1744;
|
||||
@waitingColor: #DAD462;
|
||||
|
||||
.getColorIndex(@i){
|
||||
@index: @i; //mod(@i - 1, 3) * 7 + round((@i - 1) / 3 - .3);
|
||||
}
|
||||
.creatcolorclasses(@i:1) when(@i <= length(@color-codes)) {
|
||||
@colorCodeString: extract(@color-codes, @i);
|
||||
@colorCode: color(@colorCodeString);
|
||||
|
||||
.getColorIndex(@i);
|
||||
.color-@{index} {
|
||||
background-color: @colorCode;
|
||||
fill: @colorCode;
|
||||
stroke: @colorCode;
|
||||
}
|
||||
|
||||
|
||||
.color-max-@{index} {
|
||||
background-color: lighten(@colorCode, 35%);
|
||||
border-color: lighten(@colorCode, 35%);
|
||||
fill: lighten(@colorCode, 35%);
|
||||
}
|
||||
|
||||
md-grid-list.list-color-@{i} md-grid-tile.colored {
|
||||
background-color: @colorCode;
|
||||
}
|
||||
.creatcolorclasses((@i + 1));
|
||||
}
|
||||
.creatcolorclasses();
|
||||
|
||||
.color-warning {
|
||||
background-color: @warningColor !important;
|
||||
border-color: @warningColor !important;
|
||||
fill: @warningColor !important;
|
||||
stroke: @warningColor !important;
|
||||
}
|
||||
|
||||
.color-critical {
|
||||
background-color: @criticalColor !important;
|
||||
border-color: @criticalColor !important;
|
||||
fill: @criticalColor !important;
|
||||
stroke: @criticalColor !important;
|
||||
}
|
||||
|
||||
.status-waiting {
|
||||
background-color: @freeColor !important;
|
||||
border-color: @waitingColor !important;
|
||||
border-width: 2px !important;
|
||||
border-style: solid !important;
|
||||
}
|
||||
|
||||
.status-succeeded {}
|
||||
|
||||
.status-terminated, .status-unknown {
|
||||
background-color: @errorColor !important;
|
||||
border-color: darken(@errorColor, 10%) !important;
|
||||
border-width: 1px !important;
|
||||
border-style: solid !important;
|
||||
}
|
@@ -1,158 +0,0 @@
|
||||
.groups {
|
||||
font-size: 13px;
|
||||
|
||||
.header {
|
||||
line-height: 21px;
|
||||
a {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.selector-area {
|
||||
|
||||
.filter-area {
|
||||
// font-size: 15px;
|
||||
// padding-left: 20px;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
|
||||
}
|
||||
|
||||
.filter-text {
|
||||
font-size: 13px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 0;
|
||||
|
||||
&:focus, &:hover {
|
||||
background-color: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cancel-icon {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
fill: #777777;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.group-heading {
|
||||
|
||||
.label {
|
||||
// font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-group-by {
|
||||
min-width: 110px;
|
||||
margin-left: 10px;
|
||||
margin-right: 40px;
|
||||
|
||||
.md-select-label {
|
||||
padding-top: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.group-item {
|
||||
padding-top: 20px;
|
||||
|
||||
.filter-button {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
|
||||
.filter-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
// fill: #777777;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.icon-area {
|
||||
// padding-right: 10px;
|
||||
min-width: 34px;
|
||||
.group-icon {
|
||||
border-radius: 21px;
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
.group-main-area {
|
||||
// padding-bottom: 10px;
|
||||
|
||||
.subtype {
|
||||
line-height: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
md-divider {
|
||||
margin-top: 40px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.group-name {
|
||||
padding-top: 10px;
|
||||
}
|
||||
.selectFilter {
|
||||
padding-top: 7px;
|
||||
margin-right: 30px;
|
||||
|
||||
.md-select-label {
|
||||
border-bottom: none !important;
|
||||
width: 17px;
|
||||
min-width: 17px;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
md-select-menu {
|
||||
min-height: 40px;
|
||||
max-height: 40px;
|
||||
}
|
||||
|
||||
|
||||
.group-link-area {
|
||||
padding-left: 15px;
|
||||
padding-bottom: 15px;
|
||||
|
||||
button {
|
||||
line-height: 12px;
|
||||
// line-height: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.group-type-circle {
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
}
|
||||
.group-type-circle span {
|
||||
|
||||
}
|
||||
// .group-type-area .pod-color
|
||||
// {
|
||||
// background-color: rgb(57,73,171);
|
||||
// }
|
||||
// .group-type-area .replicationController-color
|
||||
// {
|
||||
// background-color: rgb(57,73,171);
|
||||
// }
|
||||
|
||||
// .group-type-area .service-color
|
||||
// {
|
||||
// background-color: rgb(57,73,171);
|
||||
// }
|
||||
|
||||
md-select {
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
.clear-bg {
|
||||
background-color: transparent;
|
||||
}
|
||||
.list-pods {
|
||||
.pod-group {
|
||||
margin: 25px;
|
||||
|
||||
md-grid-list {
|
||||
margin-top: 50px;
|
||||
color: white;
|
||||
|
||||
// Header and footer
|
||||
figcaption {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
md-grid-tile-header {
|
||||
padding-left: 10px;
|
||||
.labels {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
md-grid-tile {
|
||||
transition: all 700ms ease-in 50ms;
|
||||
}
|
||||
|
||||
|
||||
// inner body
|
||||
.inner-box {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
// Footer
|
||||
md-grid-tile-footer {
|
||||
|
||||
background: rgba(0, 0, 0, 0.50);
|
||||
// height: 36px;
|
||||
|
||||
.pod-title
|
||||
{
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.pod-host {
|
||||
text-align: right;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
// Restart button
|
||||
.restarts {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
|
||||
.restart-button {
|
||||
&, &:not([disabled]):hover, &:not([disabled]):focus, &:hover, &:focus {
|
||||
background-color: @errorColor;
|
||||
width:30px;
|
||||
height:30px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gray {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
@import (multiple) "colors";
|
||||
}
|
@@ -1,126 +0,0 @@
|
||||
.server-overview {
|
||||
@import (multiple) "colors";
|
||||
|
||||
.color-1 {
|
||||
background-color: #512DA8;
|
||||
border-color: #512DA8;
|
||||
fill: #512DA8;
|
||||
stroke: #512DA8;
|
||||
}
|
||||
|
||||
.color-2 {
|
||||
background-color: #9C27B0;
|
||||
border-color: #9C27B0;
|
||||
fill: #9C27B0;
|
||||
stroke: #9C27B0;
|
||||
}
|
||||
|
||||
.color-3 {
|
||||
background-color: #00BCD4;
|
||||
border-color: #00BCD4;
|
||||
fill: #00BCD4;
|
||||
stroke: #00BCD4;
|
||||
}
|
||||
|
||||
.color-max-1 {
|
||||
background-color: lighten(#512DA8, 35%);
|
||||
border-color: lighten(#512DA8, 35%);
|
||||
fill: lighten(#512DA8, 35%);
|
||||
// stroke: lighten(#512DA8, 35%);
|
||||
}
|
||||
|
||||
.color-max-2 {
|
||||
background-color: lighten(#9C27B0, 35%);
|
||||
border-color: lighten(#9C27B0, 35%);
|
||||
fill: lighten(#9C27B0, 35%);
|
||||
// stroke: lighten(#9C27B0, 35%);
|
||||
}
|
||||
|
||||
.color-max-3 {
|
||||
background-color: lighten(#00BCD4, 35%);
|
||||
border-color: lighten(#00BCD4, 35%);
|
||||
fill: lighten(#00BCD4, 35%);
|
||||
// stroke: lighten(#00BCD4, 35%);
|
||||
}
|
||||
|
||||
.color-max-warning {
|
||||
background-color: lighten(@warningColor, 30%) !important;
|
||||
border-color: lighten(@warningColor, 30%) !important;
|
||||
fill: lighten(@warningColor, 30%) !important;
|
||||
// stroke: lighten(@warningColor, 30%) !important;
|
||||
}
|
||||
|
||||
.color-max-critical {
|
||||
background-color: lighten(@criticalColor, 30%) !important;
|
||||
border-color: lighten(@criticalColor, 30%) !important;
|
||||
fill: lighten(@criticalColor, 30%) !important;
|
||||
// stroke: lighten(@criticalColor, 30%) !important;
|
||||
}
|
||||
|
||||
.max_tick_arc {
|
||||
stroke: #FFF !important;
|
||||
}
|
||||
|
||||
.concentric {
|
||||
// float:left;
|
||||
// border: 0px; /* solid black; */
|
||||
}
|
||||
// Chart
|
||||
.concentricchart {
|
||||
|
||||
.bg-circle {
|
||||
background: #F9F9F9;
|
||||
fill: #F9F9F9;
|
||||
stroke: #FFFFFF;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
path {
|
||||
// stroke: #FFFFFF;
|
||||
// stroke-width: 1px;
|
||||
// opacity:0.8;
|
||||
}
|
||||
text {
|
||||
font-size:12px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
.value_group {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.legend_group rect {
|
||||
// stroke: #cccccc;
|
||||
// stroke-width: 1px;
|
||||
opacity:0.8;
|
||||
}
|
||||
}
|
||||
|
||||
svg.legend {
|
||||
height: auto;
|
||||
|
||||
text {
|
||||
font-size:12px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
.hostName {
|
||||
font-size:16px;
|
||||
}
|
||||
|
||||
.rect {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.minion-name {
|
||||
text-align: center;
|
||||
vertical-align: bottom;
|
||||
width: 100%;
|
||||
}
|
||||
.chart_area {
|
||||
width: 325px;
|
||||
// height: 425px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
@@ -1,95 +0,0 @@
|
||||
.dash-table {
|
||||
min-width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.dash-table tbody tr:hover, .dash-table tbody tr:focus {
|
||||
&:not(.no-link){
|
||||
cursor:pointer;
|
||||
background-color:rgba(63,81,181,0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.dash-table {
|
||||
|
||||
.dash-table-header {
|
||||
border-bottom: 1px solid rgb(230,230,230);
|
||||
color: rgb(130,130,130);
|
||||
text-align: left;
|
||||
font-size: 0.75em;
|
||||
font-weight: 700;
|
||||
padding: 16px 16px 16px 0;
|
||||
}
|
||||
|
||||
.dash-table-header a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.dash-table-caret {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.dash-table-content {
|
||||
font-size: 0.8em;
|
||||
padding: 16px 16px 16px 0;
|
||||
height: 72px;
|
||||
}
|
||||
|
||||
.dash-table-td-more {
|
||||
max-width:72px;
|
||||
width:72px;
|
||||
padding:16px;
|
||||
}
|
||||
|
||||
.dash-table-thumbs {
|
||||
max-width: 104px;
|
||||
width: 104px;
|
||||
padding: 16px 32px;
|
||||
}
|
||||
|
||||
.dash-table-thumbs div {
|
||||
overflow:hidden;
|
||||
width: 40px;
|
||||
height:40px;
|
||||
border-radius:20px;
|
||||
border: 1px solid rgba(0,0,0,0.2);
|
||||
background-size:cover;
|
||||
box-shadow: 0 8px 10px rgba(0,0,0,.3);
|
||||
-webkit-box-shadow: 0 8px 10px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.dash-table-footer {
|
||||
height:40px;
|
||||
}
|
||||
|
||||
.dash-table-count-info {
|
||||
line-height:40px;
|
||||
font-size:.75em;
|
||||
}
|
||||
|
||||
.dash-table-footer-item {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
.dash-table-active-page {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.grey {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
md-input-container.md-default-theme .md-input {
|
||||
color: white;
|
||||
border-color: white;
|
||||
margin-top: 24px;
|
||||
}
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"description": "The basic Kubernetes UI dashboard... ",
|
||||
"routes": [
|
||||
{
|
||||
"description": "Dashboard visualization.",
|
||||
"url": "/",
|
||||
"templateUrl": "components/dashboard/pages/home.html"
|
||||
},
|
||||
{
|
||||
"description": "Pods",
|
||||
"url": "/pods",
|
||||
"templateUrl": "components/dashboard/views/listPods.html"
|
||||
},
|
||||
{
|
||||
"description": "Pod Visualizer",
|
||||
"url": "/visualpods",
|
||||
"templateUrl": "components/dashboard/views/listPodsVisualizer.html"
|
||||
},
|
||||
{
|
||||
"description": "Services",
|
||||
"url": "/services",
|
||||
"templateUrl": "components/dashboard/views/listServices.html"
|
||||
},
|
||||
{
|
||||
"description": "Replication Controllers",
|
||||
"url": "/replicationcontrollers",
|
||||
"templateUrl": "components/dashboard/views/listReplicationControllers.html"
|
||||
},
|
||||
{
|
||||
"description": "Events",
|
||||
"url": "/events",
|
||||
"templateUrl": "components/dashboard/views/listEvents.html"
|
||||
},
|
||||
{
|
||||
"description": "Nodes",
|
||||
"url": "/nodes",
|
||||
"templateUrl": "components/dashboard/views/listMinions.html"
|
||||
},
|
||||
{
|
||||
"description": "Replication Controller",
|
||||
"url": "/replicationcontrollers/:replicationControllerId",
|
||||
"templateUrl": "components/dashboard/views/replication.html"
|
||||
},
|
||||
{
|
||||
"description": "Service",
|
||||
"url": "/services/:serviceId",
|
||||
"templateUrl": "components/dashboard/views/service.html"
|
||||
},
|
||||
{
|
||||
"description": "Node",
|
||||
"url": "/nodes/:nodeId",
|
||||
"templateUrl": "components/dashboard/views/node.html"
|
||||
},
|
||||
{
|
||||
"description": "Explore",
|
||||
"url": "/groups/:grouping*?/selector/:selector*?",
|
||||
"templateUrl": "components/dashboard/views/groups.html"
|
||||
},
|
||||
{
|
||||
"description": "Pod",
|
||||
"url": "/pods/:podId",
|
||||
"templateUrl": "components/dashboard/views/pod.html"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1 +0,0 @@
|
||||
<p></p>
|
@@ -1,26 +0,0 @@
|
||||
<div layout-fill>
|
||||
<md-toolbar md-scroll-shrink class="dashboard-subnav">
|
||||
<div class="md-toolbar-tools">
|
||||
<div layout="row" flex class="fill-height">
|
||||
<div class="md-toolbar-item md-breadcrumb"></div>
|
||||
<span ng-if="menu.currentPage.name !== menu.currentSection.name">
|
||||
<span hide-sm hide-md><a href="#{{menu.currentSection.url}}">{{menu.currentSection.name}}</a></span>
|
||||
<span class="menu-separator-icon" style="padding: 0 10px;" hide-sm hide-md>
|
||||
<img style="height: 12px;" src="assets/img/docArrow.png" alt="" aria-hidden="true">
|
||||
</span>
|
||||
</span>
|
||||
<span style="display: inline-block;">{{(menu.currentPage | humanizeDoc) || 'Kubernetes' }}</span>
|
||||
<span flex></span>
|
||||
<div class="md-toolbar-item md-tools" layout="row">
|
||||
<div layout="column" class="selectSubPages">
|
||||
<md-select ng-model="page" placeholder="Views" class="selectTitle">
|
||||
<md-optgroup label="Dashboard">
|
||||
<md-option id="{{subpage.id}}" ng-value="subpage.value" ng-repeat="subpage in subpages | filter: {category: 'dashboard' }">{{subpage.name}}</md-option>
|
||||
</md-option-group>
|
||||
</md-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
</div>
|
@@ -1,7 +0,0 @@
|
||||
<div dashboard-header></div>
|
||||
<div class="dashboard" ng-controller="DashboardCtrl" layout-fill>
|
||||
<md-content>
|
||||
<div ng-include="'components/dashboard/views/partials/cadvisor.html'">></div>
|
||||
</md-content>
|
||||
</div>
|
||||
<div dashboard-footer></div>
|