Clean up ui build and generated files.
2
.gitignore
vendored
@ -54,5 +54,7 @@ network_closure.sh
|
||||
# Web UI
|
||||
www/master/node_modules/
|
||||
www/master/npm-debug.log
|
||||
www/master/shared/config/development.json
|
||||
|
||||
# Karma output
|
||||
www/test_out
|
||||
|
2409
pkg/ui/datafile.go
163
www/README.md
@ -1,32 +1,35 @@
|
||||
### Install dependencies
|
||||
### 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 have two kinds of dependencies in this project: tools and angular framework code. The tools help
|
||||
us manage and test the application.
|
||||
* 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/).
|
||||
|
||||
* We get the tools we depend upon via `npm`, the [node package manager](https://www.npmjs.com/).
|
||||
* We get the angular code via `bower`, a [client-side code package manager](http://bower.io/).
|
||||
|
||||
`npm` is configured to automatically run `bower install` and `gulp`. Before you run the application for the first time, simply run this command from the `www/master` directory:
|
||||
Before you build the application for the first time, run this command from the `www/master` directory:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
To start the application, run this command from the `www/master` directory:
|
||||
It creates a new directory, `www/master/node_modules`, which contains the tool dependencies.
|
||||
|
||||
### Building the app for development
|
||||
To build the application for development, run this command from the `www/master` directory:
|
||||
|
||||
```
|
||||
npm start
|
||||
```
|
||||
|
||||
The `gulp` command will start a file watcher which will update the generated `app` code after any changes are saved. Note: gulp file watcher does not currently support adding or deleting files, this will require a restart of gulp). Two new directories will also be created in the project.
|
||||
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.
|
||||
|
||||
* `master/node_modules` - contains npm dependencies
|
||||
* `master/bower_components` - contains the angular framework files and any custom dependencies
|
||||
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:
|
||||
|
||||
Bower components 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`.)
|
||||
|
||||
* `master/vendor.base.json` - 3rd party vendor javascript required to start the app. JS is compiled to `base.js` and loaded before `app.js`
|
||||
* `master/vendor.json` - 3rd party vendor scripts to make the app work, usually lazy loaded. Can be js or css. Copied to `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
|
||||
|
||||
@ -36,25 +39,54 @@ For development you can serve the files locally by installing a webserver as fol
|
||||
sudo npm install -g http-server
|
||||
```
|
||||
|
||||
The server can then be launched:
|
||||
The server can then be launched from the `app` directory as follows:
|
||||
|
||||
```
|
||||
cd app
|
||||
cd www/app
|
||||
http-server -a localhost -p 8000
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
It runs the `go-bindata` tool to package the generated `app` directory and other user interface content, such as the Swagger documentation, into `pkg/ui/datafile.go`. Note: go-bindata can be installed with `go get github.com/jteeuwen/go-bindata/...`.
|
||||
|
||||
Then, run one of the go build scripts, such as `hack/build-go.sh`, to build a new `kube-apiserver` binary that includes the updated `pkg/ui/datafile.go`.
|
||||
|
||||
### Serving the app in production
|
||||
The app is served in production by `kube-apiserver` at:
|
||||
|
||||
```
|
||||
https://<kubernetes-master>/static/app/
|
||||
```
|
||||
|
||||
### 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``` or ```www/master/shared/config/production.json``` can be created from the ```www/master/shared/config/development.example.json``` file.
|
||||
* ```development.example.json``` should be kept up to date with default values, since ```development.json``` is not under source control.
|
||||
* Component configuration can be added to ```www/master/components/<component name>/config/development.json``` and it will be combined with the main app config files and compiled into the intermediary ```www/master/shared/config/generated-config.js``` file.
|
||||
* All ```generated-config.js``` is compiled into ```app.js```
|
||||
* Production config can be generated using ```gulp config --env production``` or ```gulp --env production```
|
||||
* The generated angular constant is named ```ENV``` with the shared root and each component having their own child configuration. For example,
|
||||
|
||||
`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
|
||||
@ -62,7 +94,8 @@ www/master
|
||||
├── dashboard/config/development.json
|
||||
└── my_component/config/development.json
|
||||
```
|
||||
produces ```www/master/shared/config/generated-config.js```:
|
||||
generates the following in `www/master/shared/config/generated-config.js`:
|
||||
|
||||
```
|
||||
angular.module('kubernetesApp.config', [])
|
||||
.constant('ENV', {
|
||||
@ -73,56 +106,64 @@ angular.module('kubernetesApp.config', [])
|
||||
```
|
||||
|
||||
#### 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=.*`.
|
||||
|
||||
You'll need to run ```hack/build-ui.sh``` to create a new ```pkg/ui/datafile.go``` file.
|
||||
This is the file that is built-in to the kube-apiserver.
|
||||
|
||||
**RECOMMENDED**: When working in development mode the Kubernetes api server does not support CORS,
|
||||
so the `kube-apiserver.service` must be started with
|
||||
`--cors_allowed_origins=.*` or `--cors_allowed_origins=http://<your
|
||||
host here>`
|
||||
|
||||
**HACKS**: If you don't want to/cannot restart the Kubernetes api server:
|
||||
* Or you can start your browser with web security disabled. For
|
||||
Chrome, you can [launch](http://www.chromium.org/developers/how-tos/run-chromium-with-flags) it with flag ```--disable-web-security```.
|
||||
**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 kubernetes/www includes both unit-testing (run via [Karma](http://karma-runner.github.io/0.12/index.html)) and
|
||||
end-to-end testing (run via
|
||||
[Protractor](http://angular.github.io/protractor/#/)).
|
||||
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/#/).
|
||||
|
||||
#### Unittests via Karma
|
||||
#### Unit testing with Karma
|
||||
To run the existing Karma tests:
|
||||
* Install the Karma CLI: `sudo npm install -g karma-cli` (it needs to
|
||||
be installed globally, hence the `sudo` may be needed). Note that
|
||||
the other Karma packages (such as `karma`, `karma-jasmine`, and
|
||||
`karma-chrome-launcher` should be automatically installed when
|
||||
running `npm start`).
|
||||
* Go to the `www/master` directory, and run `karma start
|
||||
karma.conf.js`. The Karma configuration is defined in `karma.config.js`. The console should show the test results.
|
||||
|
||||
To write new Karma tests:
|
||||
* For testing each components, write test files (`*.spec.js`) under the
|
||||
corresponding `www/master/components/**/test/modules/` directory.
|
||||
* For testing the chrome and the framework, write test files
|
||||
(*.spec.js) under the `www/master/test/modules/*` directory.
|
||||
* 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
|
||||
```
|
||||
|
||||
#### End-to-end testing via Protractor
|
||||
* 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`.
|
||||
* Start the webdriver server: `sudo webdriver-manager start`
|
||||
* Start the kubernetes-ui app (see instructions above), assuming
|
||||
running at port 8000.
|
||||
* Go to the `www/master/protractor` directory and run `protractor
|
||||
conf.js`. The protractor configuration is in `conf.js`. The console
|
||||
should show the test results.
|
||||
|
||||
To write new protractor tests, put the test files (`*.spec.js`) in the
|
||||
corresponding `www/master/components/**/protractor/` directory.
|
||||
* 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.
|
||||
|
||||
[]()
|
||||
|
@ -201,7 +201,7 @@ angular.module("kubernetesApp.config", [])
|
||||
.constant("ENV", {
|
||||
"/": {
|
||||
"k8sApiServer": "/api/v1beta3",
|
||||
"k8sDataServer": "/cluster",
|
||||
"k8sDataServer": "",
|
||||
"k8sDataPollMinIntervalSec": 10,
|
||||
"k8sDataPollMaxIntervalSec": 120,
|
||||
"k8sDataPollErrorThreshold": 5,
|
||||
|
@ -1 +0,0 @@
|
||||
describe("Kubernetes UI Dashboard",function(){it("should have all the expected components loaded",function(){browser.get("http://localhost:8000"),expect(browser.getTitle()).toEqual("Kubernetes UI");var e=element(by.id("tab_001"));expect(e).toBeDefined(),e.click(),expect(browser.getLocationAbsUrl()).toBe("/dashboard/");var t=element(by.model("page"));expect(t).toBeDefined()}),it("should have the subnav view",function(){browser.get("http://localhost:8000/"),expect(by.css(".dashboard-subnav")).toBeDefined();var e=element(by.css(".selectSubPages"));expect(e).toBeDefined(),e.click();var t=element(by.model("page"));expect(t).toBeDefined(),e.click(),t.click(),expect(element(by.id("groupsView"))).toBeDefined(),expect(element(by.id("podsView"))).toBeDefined(),expect(element(by.id("minionsView"))).toBeDefined(),expect(element(by.id("rcView"))).toBeDefined(),expect(element(by.id("servicesView"))).toBeDefined(),expect(element(by.id("eventsView"))).toBeDefined(),expect(element(by.id("cAdvisorView"))).toBeDefined()}),it("should have the cAdvisor view by default",function(){browser.get("http://localhost:8000/"),expect(browser.getTitle()).toEqual("Kubernetes UI"),expect(element.all(by.css(".dashboard")).count()).toBeGreaterThan(0),expect(element.all(by.css(".server-overview")).count()).toEqual(1),expect(element(by.repeater("minion in minions.items"))).toBeDefined();var e=element(by.css("svg"));expect(e).toBeDefined()}),it("should have the correct subviews",function(){browser.get("http://localhost:8000/");for(var e=["podsView","minionsView","rcView","servicesView","eventsView"],t=0;t<e.length;t++){var o=e[t],i=element(by.model("page"));i.click();var n=element(by.id(o));expect(n).toBeDefined(),n.click(),expect(browser.getTitle()).toEqual("Kubernetes UI"),expect(by.css(".dashboard-subnav")).toBeDefined(),expect(element(by.css(".selectSubPages"))).toBeDefined();var c=element(by.model("page"));expect(c).toBeDefined(),expect(element.all(by.css(".list-pods")).count()).toEqual(1),expect(element(by.repeater("h in headers"))).toBeDefined()}}),it("should have the correct groups view",function(){browser.get("http://localhost:8000/");var e=element(by.model("page"));e.click();var t=element(by.id("groupsView"));expect(t).toBeDefined(),t.click(),expect(browser.getTitle()).toEqual("Kubernetes UI"),expect(by.css(".dashboard-subnav")).toBeDefined(),expect(element(by.css(".selectSubPages"))).toBeDefined();var o=element(by.model("page"));expect(o).toBeDefined();var e=element(by.model("selectedGroupBy"));expect(e).toBeDefined(),e.click(),expect(element(by.repeater("g in groupByOptions"))).toBeDefined()})});
|
@ -1 +0,0 @@
|
||||
"use strict";describe("header controller",function(){beforeEach(module("kubernetesApp.components.dashboard")),beforeEach(inject(function(e,t,o){this.rootScope=e,this.scope=e.$new(),this.location=t,spyOn(this.location,"path"),this.controller=o,this.ctrl=this.controller("HeaderCtrl",{$scope:this.scope}),this.scope.$apply()})),describe("subPages",function(){it("is defined",function(){expect(this.scope.subPages).not.toBeUndefined()}),it("is an array",function(){expect(Array.isArray(this.scope.subPages)).toBeTruthy()}),it("is not empty",function(){expect(this.scope.subPages.length).toBeGreaterThan(0)}),describe("each subPage",function(){it("has a category",function(){this.scope.subPages.forEach(function(e){expect(e.category).toBeTruthy()})}),it("has a name",function(){this.scope.subPages.forEach(function(e){expect(e.name).toBeTruthy()})}),it("has a value",function(){this.scope.subPages.forEach(function(e){expect(e.value).toBeTruthy()})})})}),describe("Pages",function(){it("does not change location on first detected change",function(){expect(this.location.path).not.toHaveBeenCalled()}),it("changes location on second detected change",function(){var e=this;this.scope.$apply(function(){e.scope.Pages="test_Pages"}),expect(this.location.path).toHaveBeenCalledWith("test_Pages")})})});
|
@ -1,60 +1,58 @@
|
||||
<!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" />
|
||||
<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>
|
||||
<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>
|
||||
|
0
www/app/vendor/.gitkeep
vendored
10
www/app/vendor/d3/d3.min.js
vendored
@ -1,14 +1,14 @@
|
||||
<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>
|
||||
<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,45 +1,47 @@
|
||||
<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_up_24px.svg"></span><span class="md-table-caret" ng-show="!reverse && h.field == predicate"><img src="assets/img/ic_arrow_drop_down_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>
|
||||
<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_up_24px.svg"></span><span class="md-table-caret" ng-show="!reverse && h.field == predicate"><img src="assets/img/ic_arrow_drop_down_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>
|
||||
<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,14 +1,10 @@
|
||||
<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 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>
|
||||
<li ng-repeat="page in section.pages">
|
||||
<menu-link section="page"></menu-link>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -1,11 +1,20 @@
|
||||
### Running the App in Production
|
||||
### Application source and project files
|
||||
|
||||
master/ directory
|
||||
|
||||
This directory contains the source files. You will find the following directorys inside
|
||||
|
||||
jade/ This directory contains JADE files. This files need to be compiled into html files to be displayed by a browser
|
||||
less/ This directory contains the LESS files for the core styles and material styles.
|
||||
js/ Here you will find pure JS files. All this files are concatenated into the file app.js.
|
||||
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,9 +1,10 @@
|
||||
Components
|
||||
==========
|
||||
|
||||
A tab in the Kubernetes UI with its set of visualizations is referred to as a *component*. Components are separated from the UI chrome and base data providers to simplify the development of new visualizations. This document provides reference for creation and modification of 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:
|
||||
|
||||
Each component has its own directory, which contains a manifest file, HTML views, Angular providers, CSS, Less and other assets. Below is the recommended directory structure for a component.
|
||||
```
|
||||
foo_component
|
||||
├── config
|
||||
@ -16,6 +17,8 @@ foo_component
|
||||
│ └── services
|
||||
├── less
|
||||
├── pages
|
||||
├── protractor
|
||||
├── test
|
||||
├── views
|
||||
│ └── partials
|
||||
└── manifest.json
|
||||
@ -23,9 +26,10 @@ foo_component
|
||||
|
||||
###Manifest file
|
||||
|
||||
The JSON-formatted manifest file, named ```manifest.json```, is located at the root of a component. Based on 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 to main AngularJS app and Angular routes for the component.
|
||||
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`:
|
||||
|
||||
For example, consider a manifest file at ```master/components/foo_component/manifest.json```:
|
||||
```
|
||||
{
|
||||
"routes": [
|
||||
@ -42,26 +46,28 @@ For example, consider a manifest file at ```master/components/foo_component/mani
|
||||
}
|
||||
```
|
||||
|
||||
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```.
|
||||
From the name of the component directory, the Kubernetes UI:
|
||||
|
||||
Every tab links to ```/``` relative to its component, so it is important to always define a ```/``` route.
|
||||
* 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
|
||||
In general, all files located in ```master/components/<component>``` are copied to ```app/components/<component>/``` on each gulp build. This includes (but is not limited to) HTML views, CSS and images. Exceptions to this copy are the ```config``` and ```less``` directories as well as all ```.js``` 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.
|
||||
|
||||
The sections below describe how the exceptions are built into the UI.
|
||||
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 uglified and concatenated together with the rest of the UI's JavaScript. Once aggregated, the JavaScript file is minified and written to ```app/assets/js/app.js```.
|
||||
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 [UI-wide configuration](../../README.md#configuration), components can define different configuration for each environment. The gulp task creates the constant ```ENV``` under the ```kubernetesApp.config``` module for configuration, which is an object with a property for the root UI and each component.
|
||||
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`:
|
||||
|
||||
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', ...)
|
||||
@ -72,7 +78,7 @@ angular.module('kubernetesApp.components.fooComponent', ['kubernetesApp.config']
|
||||
|
||||
####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 minified and copied to ```app/assets/css/app.css```.
|
||||
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.
|
||||
|
||||
@ -121,8 +127,4 @@ Sub-directories of this path are watched for changes, but not directly imported.
|
||||
}
|
||||
```
|
||||
|
||||
Content available under the [CC-By 3.0
|
||||
license](http://creativecommons.org/licenses/by/3.0/)
|
||||
|
||||
|
||||
[]()
|
||||
|
@ -1,17 +1,13 @@
|
||||
var gulp = require('gulp'), concat = require('gulp-concat'), uglify = require('gulp-uglify'),
|
||||
// jade = require('gulp-jade'),
|
||||
less = require('gulp-less'), path = require('path'),
|
||||
livereload = require('gulp-livereload'), // Livereload plugin needed:
|
||||
// https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei
|
||||
// marked = require('marked'), // For :markdown filter in jade
|
||||
livereload = require('gulp-livereload'),
|
||||
path = require('path'), changed = require('gulp-changed'), prettify = require('gulp-html-prettify'),
|
||||
w3cjs = require('gulp-w3cjs'), rename = require('gulp-rename'),
|
||||
// flip = require('css-flip'),
|
||||
through = require('through2'), gutil = require('gulp-util'), htmlify = require('gulp-angular-htmlify'),
|
||||
minifyCSS = require('gulp-minify-css'), gulpFilter = require('gulp-filter'), expect = require('gulp-expect-file'),
|
||||
gulpsync = require('gulp-sync')(gulp), ngAnnotate = require('gulp-ng-annotate'),
|
||||
sourcemaps = require('gulp-sourcemaps'), del = require('del'), jsoncombine = require('gulp-jsoncombine'),
|
||||
ngConstant = require('gulp-ng-constant'), argv = require('yargs').argv, foreach = require('gulp-foreach'),
|
||||
ngConstant = require('gulp-ng-constant'), foreach = require('gulp-foreach'),
|
||||
gcallback = require('gulp-callback'), changeCase = require('change-case'),
|
||||
tag_version = require('gulp-tag-version'), PluginError = gutil.PluginError;
|
||||
|
||||
@ -25,10 +21,10 @@ var W3C_OPTIONS = {
|
||||
output: 'json',
|
||||
// Remove some messages that angular will always display.
|
||||
filter: function(message) {
|
||||
if (/Element head is missing a required instance of child element title/.test(message)) return false;
|
||||
if (/Attribute .+ not allowed on element .+ at this point/.test(message)) return false;
|
||||
if (/Element .+ not allowed as child of element .+ in this context/.test(message)) return false;
|
||||
if (/Comments seen before doctype./.test(message)) return false;
|
||||
if (/Element head is missing a required instance of child element title/.test(message)) { return false; }
|
||||
if (/Attribute .+ not allowed on element .+ at this point/.test(message)) { return false; }
|
||||
if (/Element .+ not allowed as child of element .+ in this context/.test(message)) { return false; }
|
||||
if (/Comments seen before doctype./.test(message)) { return false; }
|
||||
}
|
||||
};
|
||||
|
||||
@ -40,15 +36,23 @@ var useSourceMaps = false;
|
||||
var hidden_files = '**/_*.*';
|
||||
var ignored_files = '!' + hidden_files;
|
||||
|
||||
var component_hidden_files = '**/js/**/*.*';
|
||||
var component_ignored_files = '!' + component_hidden_files;
|
||||
var output_folder = '../app';
|
||||
|
||||
// VENDOR CONFIG
|
||||
var vendor = {
|
||||
// vendor scripts required to start the app
|
||||
base: {source: require('./vendor.base.json'), dest: '../app/assets/js', name: 'base.js'},
|
||||
base: {
|
||||
source: require('./vendor.base.json'),
|
||||
dest: '../app/assets/js',
|
||||
name: 'base.js'
|
||||
},
|
||||
// vendor scripts to make to app work. Usually via lazy loading
|
||||
app: {source: require('./vendor.json'), dest: '../app/vendor'}
|
||||
app: {
|
||||
// instead of the bower downloaded versions of some files, we
|
||||
// pull hand edited versions from the shared/vendor directory.
|
||||
source: require('./vendor.json'),
|
||||
dest: '../app/vendor'
|
||||
}
|
||||
};
|
||||
|
||||
// SOURCES CONFIG
|
||||
@ -69,81 +73,75 @@ var source = {
|
||||
'shared/js/modules/controllers/*.js',
|
||||
'shared/js/modules/directives/*.js',
|
||||
'shared/js/modules/services/*.js',
|
||||
'components/*/js/**/*.js'
|
||||
'components/**/js/**/*.js'
|
||||
],
|
||||
watch: ['manifest.json', 'js/**/*.js', 'shared/**/*.js', 'components/*/js/**/*.js']
|
||||
dest: {
|
||||
name: 'app.js',
|
||||
dir: '../app/assets/js'
|
||||
},
|
||||
watch: [
|
||||
'manifest.json',
|
||||
'js/**/*.js',
|
||||
'shared/**/*.js',
|
||||
'shared/config/*.json',
|
||||
'components/*/js/**/*.js',
|
||||
'components/*/config/*.json'
|
||||
]
|
||||
},
|
||||
// templates: {
|
||||
// app: {
|
||||
// files : ['jade/index.jade'],
|
||||
// watch: ['jade/index.jade', hidden_files]
|
||||
// },
|
||||
// views: {
|
||||
// files : ['jade/views/*.jade', 'jade/views/**/*.jade', ignored_files],
|
||||
// watch: ['jade/views/**/*.jade']
|
||||
// },
|
||||
// pages: {
|
||||
// files : ['jade/pages/*.jade'],
|
||||
// watch: ['jade/pages/*.jade']
|
||||
// }
|
||||
// },
|
||||
|
||||
styles: {
|
||||
app: {
|
||||
// , 'components/*/less/*.less'
|
||||
source: ['less/app/base.less', 'components/*/less/*.less'],
|
||||
dir: ['less/app', 'components'],
|
||||
paths: ['less/app', 'components'],
|
||||
dest: '../app/assets/css',
|
||||
watch: ['less/*.less', 'less/**/*.less', 'components/**/less/*.less', 'components/**/less/**/*.less']
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
html: {
|
||||
app: {
|
||||
source: ['shared/index.html'],
|
||||
dest: '../app'
|
||||
},
|
||||
views: {
|
||||
source: ['shared/views/**/*.*'],
|
||||
dest: '../app'
|
||||
},
|
||||
watch: ['shared/index.html', 'shared/views/**/*.*']
|
||||
},
|
||||
|
||||
components: {
|
||||
source: [
|
||||
'components/**/*.*',
|
||||
component_ignored_files,
|
||||
'!components/**/config/*.*',
|
||||
'!master/shared/js/modules/config.js',
|
||||
'!components/*/less/*.*',
|
||||
'!components/**/js/**/*.*',
|
||||
'!components/**/config/**/*.*',
|
||||
'!components/**/protractor/**/*.*',
|
||||
'!components/**/test/**/*.*',
|
||||
'!components/**/less/**/*.*',
|
||||
'!components/**/README.md'
|
||||
],
|
||||
dest: 'components',
|
||||
dest: '../app/components',
|
||||
watch: [
|
||||
'components/**/*.*',
|
||||
component_ignored_files,
|
||||
'!components/**/config/*.*',
|
||||
'!master/shared/js/modules/config.js',
|
||||
'!components/**/less/*.*'
|
||||
'!components/**/js/**/*.*',
|
||||
'!components/**/config/**/*.*',
|
||||
'!components/**/protractor/**/*.*',
|
||||
'!components/**/test/**/*.*',
|
||||
'!components/**/less/**/*.*',
|
||||
'!components/**/README.md'
|
||||
]
|
||||
},
|
||||
|
||||
config: {
|
||||
watch: [
|
||||
'shared/config/development.json',
|
||||
'shared/config/production.json',
|
||||
'shared/config/development.json',
|
||||
'shared/config/production.json'
|
||||
],
|
||||
dest: 'shared/config'
|
||||
},
|
||||
|
||||
assets: {source: ['shared/assets/**/*.*'], dest: 'shared/assets', watch: ['shared/assets/**/*.*']}
|
||||
|
||||
//,
|
||||
// bootstrap: {
|
||||
// main: 'less/bootstrap/bootstrap.less',
|
||||
// dir: 'less/bootstrap',
|
||||
// watch: ['less/bootstrap/*.less']
|
||||
// }
|
||||
};
|
||||
|
||||
// BUILD TARGET CONFIG
|
||||
var build = {
|
||||
scripts: {app: {main: 'app.js', dir: '../app/assets/js'}},
|
||||
assets: '../app/shared/assets',
|
||||
styles: '../app/assets/css',
|
||||
components: {dir: '../app/components'}
|
||||
assets: {
|
||||
source: ['shared/assets/**/*.*'],
|
||||
dest: '../app/assets',
|
||||
watch: ['shared/assets/**/*.*']
|
||||
}
|
||||
};
|
||||
|
||||
function stringSrc(filename, string) {
|
||||
@ -155,6 +153,13 @@ function stringSrc(filename, string) {
|
||||
return src;
|
||||
}
|
||||
|
||||
// Error handler
|
||||
function handleError(err) {
|
||||
console.log(err.toString());
|
||||
this.emit('end');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
//---------------
|
||||
// TASKS
|
||||
//---------------
|
||||
@ -217,34 +222,37 @@ gulp.task('bundle-manifest-routes', function() {
|
||||
});
|
||||
|
||||
// JS APP
|
||||
gulp.task('scripts:app', ['bundle-manifest', 'bundle-manifest-routes', 'config', 'scripts:app:base']);
|
||||
gulp.task('scripts:app', gulpsync.sync(['bundle-manifest', 'bundle-manifest-routes', 'config', 'scripts:app:base']));
|
||||
|
||||
// JS APP BUILD
|
||||
gulp.task('scripts:app:base', function() {
|
||||
// Minify and copy all JavaScript (except vendor scripts)
|
||||
return gulp.src(source.scripts.app)
|
||||
.pipe(useSourceMaps ? sourcemaps.init() : gutil.noop())
|
||||
.pipe(concat(build.scripts.app.main))
|
||||
.pipe(concat(source.scripts.dest.name))
|
||||
.pipe(ngAnnotate())
|
||||
.on("error", handleError)
|
||||
.pipe(isProduction ? uglify({preserveComments: 'some'}) : gutil.noop())
|
||||
.on("error", handleError)
|
||||
// Now that we run a production build, uglification is breaking angular injection,
|
||||
// so disable it for now.
|
||||
// TODO: Find out which dependencies are not string based and upgrade them accordingly.
|
||||
// .pipe(isProduction ? uglify({preserveComments: 'some'}) : gutil.noop())
|
||||
.pipe(useSourceMaps ? sourcemaps.write() : gutil.noop())
|
||||
.pipe(gulp.dest(build.scripts.app.dir));
|
||||
.pipe(gulp.dest(source.scripts.dest.dir))
|
||||
.on("error", handleError);
|
||||
});
|
||||
|
||||
// VENDOR BUILD
|
||||
gulp.task('scripts:vendor', ['scripts:vendor:base', 'scripts:vendor:app']);
|
||||
gulp.task('scripts:vendor', gulpsync.sync(['scripts:vendor:base', 'scripts:vendor:app']));
|
||||
|
||||
// This will be included vendor files statically
|
||||
gulp.task('scripts:vendor:base', function() {
|
||||
|
||||
// Minify and copy all JavaScript (except vendor scripts)
|
||||
return gulp.src(vendor.base.source)
|
||||
.pipe(expect(vendor.base.source))
|
||||
.pipe(uglify())
|
||||
.pipe(expect({ errorOnFailure: true }, vendor.base.source))
|
||||
.pipe(isProduction ? uglify() : gutil.noop())
|
||||
.pipe(concat(vendor.base.name))
|
||||
.pipe(gulp.dest(vendor.base.dest));
|
||||
.pipe(gulp.dest(vendor.base.dest))
|
||||
.on("error", handleError);
|
||||
});
|
||||
|
||||
// copy file from bower folder into the app vendor folder
|
||||
@ -253,15 +261,16 @@ gulp.task('scripts:vendor:app', function() {
|
||||
var jsFilter = gulpFilter('**/*.js');
|
||||
var cssFilter = gulpFilter('**/*.css');
|
||||
|
||||
return gulp.src(vendor.app.source, {base: 'bower_components'})
|
||||
.pipe(expect(vendor.app.source))
|
||||
return gulp.src(vendor.app.source)
|
||||
.pipe(expect({ errorOnFailure: true }, vendor.app.source))
|
||||
.pipe(jsFilter)
|
||||
.pipe(uglify())
|
||||
.pipe(isProduction ? uglify() : gutil.noop())
|
||||
.pipe(jsFilter.restore())
|
||||
.pipe(cssFilter)
|
||||
.pipe(minifyCSS())
|
||||
.pipe(isProduction ? minifyCSS() : gutil.noop())
|
||||
.pipe(cssFilter.restore())
|
||||
.pipe(gulp.dest(vendor.app.dest));
|
||||
.pipe(gulp.dest(vendor.app.dest))
|
||||
.on("error", handleError);
|
||||
|
||||
});
|
||||
|
||||
@ -271,35 +280,14 @@ gulp.task('styles:app', function() {
|
||||
.pipe(foreach (function(stream, file) { return stringSrc('import.less', '@import "' + file.relative + '";\n'); }))
|
||||
.pipe(concat('app.less'))
|
||||
.pipe(useSourceMaps ? sourcemaps.init() : gutil.noop())
|
||||
.pipe(less({paths: source.styles.app.dir}))
|
||||
.on("error", handleError)
|
||||
.pipe(less({paths: source.styles.app.paths}))
|
||||
.pipe(isProduction ? minifyCSS() : gutil.noop())
|
||||
.pipe(useSourceMaps ? sourcemaps.write() : gutil.noop())
|
||||
.pipe(gulp.dest(build.styles));
|
||||
.pipe(gulp.dest(source.styles.app.dest))
|
||||
.on("error", handleError);
|
||||
});
|
||||
|
||||
// // APP RTL
|
||||
// gulp.task('styles:app:rtl', function() {
|
||||
// return gulp.src(source.styles.app.main)
|
||||
// .pipe( useSourceMaps ? sourcemaps.init() : gutil.noop())
|
||||
// .pipe(less({
|
||||
// paths: [source.styles.app.dir]
|
||||
// }))
|
||||
// .on("error", handleError)
|
||||
// .pipe(flipcss())
|
||||
// .pipe( isProduction ? minifyCSS() : gutil.noop() )
|
||||
// .pipe( useSourceMaps ? sourcemaps.write() : gutil.noop())
|
||||
// .pipe(rename(function(path) {
|
||||
// path.basename += "-rtl";
|
||||
// return path;
|
||||
// }))
|
||||
// .pipe(gulp.dest(build.styles));
|
||||
// });
|
||||
|
||||
// Environment based configuration
|
||||
// https://github.com/kubernetes-ui/kubernetes-ui/issues/21
|
||||
|
||||
gulp.task('config', ['config:base', 'config:copy']);
|
||||
gulp.task('config', gulpsync.sync(['config:base', 'config:copy']));
|
||||
|
||||
gulp.task('config:base', function() {
|
||||
return stringSrc('generated-config.js', 'angular.module("kubernetesApp.config", [])' +
|
||||
@ -308,23 +296,23 @@ gulp.task('config:base', function() {
|
||||
});
|
||||
|
||||
gulp.task('config:copy', function() {
|
||||
var environment = argv.env || 'development'; // change this to whatever default environment you need.
|
||||
|
||||
var environment = isProduction ? 'production' : 'development';
|
||||
return gulp.src(['shared/config/' + environment + '.json', 'components/**/config/' + environment + '.json'])
|
||||
.pipe(jsoncombine('generated-config.js',
|
||||
function(data) {
|
||||
var env = Object.keys(data).reduce(function(result, key) {
|
||||
// Map the key "environment" to "/" and the keys "component/config/environment" to
|
||||
// "component".
|
||||
var newKey = key.replace(environment, '/').replace(/\/config\/\/$/, '');
|
||||
result[newKey] = data[key];
|
||||
return result;
|
||||
}, {});
|
||||
.pipe(expect({ errorOnFailure: true }, 'shared/config/' + environment + '.json'))
|
||||
.on("error", handleError)
|
||||
.pipe(jsoncombine('generated-config.js',
|
||||
function(data) {
|
||||
var env = Object.keys(data).reduce(function(result, key) {
|
||||
// Map the key "environment" to "/" and the keys "component/config/environment" to "component".
|
||||
var newKey = key.replace(environment, '/').replace(/\/config\/\/$/, '');
|
||||
result[newKey] = data[key];
|
||||
return result;
|
||||
}, {});
|
||||
|
||||
return new Buffer(JSON.stringify({'ENV': env}));
|
||||
}))
|
||||
.pipe(ngConstant({name: 'kubernetesApp.config', deps: [], constants: {ngConstant: true}}))
|
||||
.pipe(gulp.dest(source.config.dest));
|
||||
return new Buffer(JSON.stringify({'ENV': env}));
|
||||
}))
|
||||
.pipe(ngConstant({name: 'kubernetesApp.config', deps: [], constants: {ngConstant: true}}))
|
||||
.pipe(gulp.dest(source.config.dest));
|
||||
});
|
||||
|
||||
gulp.task('copy:components', function() {
|
||||
@ -332,96 +320,51 @@ gulp.task('copy:components', function() {
|
||||
var jsFilter = gulpFilter('**/*.js');
|
||||
var cssFilter = gulpFilter('**/*.css');
|
||||
|
||||
del.sync([build.components.dir], {force: true});
|
||||
|
||||
return gulp.src(source.components.source, {base: 'components'})
|
||||
.pipe(expect(source.components.source))
|
||||
.pipe(expect({ errorOnFailure: true }, source.components.source))
|
||||
.pipe(jsFilter)
|
||||
.pipe(uglify())
|
||||
.pipe(isProduction ? uglify() : gutil.noop())
|
||||
.pipe(jsFilter.restore())
|
||||
.pipe(cssFilter)
|
||||
.pipe(minifyCSS())
|
||||
.pipe(isProduction ? minifyCSS() : gutil.noop())
|
||||
.pipe(cssFilter.restore())
|
||||
.pipe(gulp.dest(build.components.dir));
|
||||
.pipe(gulp.dest(source.components.dest))
|
||||
.on("error", handleError);
|
||||
});
|
||||
|
||||
gulp.task('copy:shared-assets', function() {
|
||||
del.sync([build.assets], {force: true});
|
||||
|
||||
return gulp.src(source.assets.source, {base: 'shared/assets'})
|
||||
.pipe(gulp.dest(build.assets));
|
||||
.pipe(gulp.dest(source.assets.dest));
|
||||
});
|
||||
|
||||
// Assuming there's "version: 1.2.3" in package.json,
|
||||
// tag the last commit as "v1.2.3"//
|
||||
gulp.task('tag', function() { return gulp.src(['./package.json']).pipe(tag_version()); });
|
||||
|
||||
// // BOOSTRAP
|
||||
// gulp.task('bootstrap', function() {
|
||||
// return gulp.src(source.bootstrap.main)
|
||||
// .pipe(less({
|
||||
// paths: [source.bootstrap.dir]
|
||||
// }))
|
||||
// .on("error", handleError)
|
||||
// .pipe(gulp.dest(build.styles));
|
||||
// });
|
||||
// VIEWS
|
||||
gulp.task('content:html', gulpsync.sync(['content:html:app', 'content:html:views']));
|
||||
|
||||
// JADE
|
||||
// gulp.task('templates:app', function() {
|
||||
// return gulp.src(source.templates.app.files)
|
||||
// .pipe(changed(build.templates.app, { extension: '.html' }))
|
||||
// .pipe(jade())
|
||||
// .on("error", handleError)
|
||||
// .pipe(prettify({
|
||||
// indent_char: ' ',
|
||||
// indent_size: 3,
|
||||
// unformatted: ['a', 'sub', 'sup', 'b', 'i', 'u']
|
||||
// }))
|
||||
// // .pipe(htmlify({
|
||||
// // customPrefixes: ['ui-']
|
||||
// // }))
|
||||
// // .pipe(w3cjs( W3C_OPTIONS ))
|
||||
// .pipe(gulp.dest(build.templates.app))
|
||||
// ;
|
||||
// });
|
||||
gulp.task('content:html:app', function() {
|
||||
return gulp.src(source.html.app.source, {base: 'shared'})
|
||||
.pipe(prettify({
|
||||
indent_char: ' ',
|
||||
indent_size: 4,
|
||||
unformatted: ['a', 'sub', 'sup', 'b', 'i', 'u']
|
||||
}))
|
||||
.pipe(gulp.dest(source.html.app.dest))
|
||||
.on("error", handleError);
|
||||
});
|
||||
|
||||
// // JADE
|
||||
// gulp.task('templates:pages', function() {
|
||||
// return gulp.src(source.templates.pages.files)
|
||||
// .pipe(changed(build.templates.pages, { extension: '.html' }))
|
||||
// .pipe(jade())
|
||||
// .on("error", handleError)
|
||||
// .pipe(prettify({
|
||||
// indent_char: ' ',
|
||||
// indent_size: 3,
|
||||
// unformatted: ['a', 'sub', 'sup', 'b', 'i', 'u']
|
||||
// }))
|
||||
// // .pipe(htmlify({
|
||||
// // customPrefixes: ['ui-']
|
||||
// // }))
|
||||
// // .pipe(w3cjs( W3C_OPTIONS ))
|
||||
// .pipe(gulp.dest(build.templates.pages))
|
||||
// ;
|
||||
// });
|
||||
|
||||
// // JADE
|
||||
// gulp.task('templates:views', function() {
|
||||
// return gulp.src(source.templates.views.files)
|
||||
// .pipe(changed(build.templates.views, { extension: '.html' }))
|
||||
// .pipe(jade())
|
||||
// .on("error", handleError)
|
||||
// .pipe(prettify({
|
||||
// indent_char: ' ',
|
||||
// indent_size: 3,
|
||||
// unformatted: ['a', 'sub', 'sup', 'b', 'i', 'u']
|
||||
// }))
|
||||
// // .pipe(htmlify({
|
||||
// // customPrefixes: ['ui-']
|
||||
// // }))
|
||||
// // .pipe(w3cjs( W3C_OPTIONS ))
|
||||
// .pipe(gulp.dest(build.templates.views))
|
||||
// ;
|
||||
// });
|
||||
gulp.task('content:html:views', function() {
|
||||
return gulp.src(source.html.views.source, {base: 'shared'})
|
||||
.pipe(prettify({
|
||||
indent_char: ' ',
|
||||
indent_size: 4,
|
||||
unformatted: ['a', 'sub', 'sup', 'b', 'i', 'u']
|
||||
}))
|
||||
.pipe(gulp.dest(source.html.views.dest))
|
||||
.on("error", handleError);
|
||||
});
|
||||
|
||||
//---------------
|
||||
// WATCH
|
||||
@ -431,87 +374,47 @@ gulp.task('tag', function() { return gulp.src(['./package.json']).pipe(tag_versi
|
||||
gulp.task('watch', function() {
|
||||
livereload.listen();
|
||||
|
||||
gulp.watch(source.html.watch, ['content:html']);
|
||||
gulp.watch(source.scripts.watch, ['scripts:app']);
|
||||
gulp.watch(source.styles.app.watch, ['styles:app']);
|
||||
gulp.watch(source.components.watch, ['copy:components']);
|
||||
gulp.watch(source.assets.watch, ['copy:shared-assets']);
|
||||
// gulp.watch(source.templates.pages.watch, ['templates:pages']);
|
||||
// gulp.watch(source.templates.views.watch, ['templates:views']);
|
||||
// gulp.watch(source.templates.app.watch, ['templates:app']);
|
||||
|
||||
gulp.watch([
|
||||
|
||||
'../app/**'
|
||||
|
||||
])
|
||||
gulp.watch(['../app/**'])
|
||||
.on('change', function(event) {
|
||||
|
||||
livereload.changed(event.path);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//---------------
|
||||
// DEFAULT TASK
|
||||
// ENTRY POINTS
|
||||
//---------------
|
||||
|
||||
// build for production (minify)
|
||||
gulp.task('build', ['prod', 'default']);
|
||||
gulp.task('build', gulpsync.sync(['prod', 'clean', 'compile']));
|
||||
gulp.task('prod', function() { isProduction = true; });
|
||||
|
||||
// build with sourcemaps (no minify)
|
||||
gulp.task('sourcemaps', ['usesources', 'default']);
|
||||
gulp.task('sourcemaps', gulpsync.sync(['usesources', 'compile']));
|
||||
gulp.task('usesources', function() { useSourceMaps = true; });
|
||||
|
||||
// default (no minify)
|
||||
gulp.task('default', gulpsync.sync(['scripts:vendor', 'copy:components', 'scripts:app', 'start']), function() {
|
||||
|
||||
// build for development (no minify)
|
||||
gulp.task('default', gulpsync.sync(['clean', 'compile', 'watch']), function() {
|
||||
gutil.log(gutil.colors.cyan('************'));
|
||||
gutil.log(gutil.colors.cyan('* All Done *'),
|
||||
'You can start editing your code, LiveReload will update your browser after any change..');
|
||||
gutil.log('You can start editing your code. LiveReload will update your browser after any change.');
|
||||
gutil.log(gutil.colors.cyan('************'));
|
||||
|
||||
});
|
||||
|
||||
gulp.task('start', [
|
||||
'styles:app',
|
||||
'copy:components',
|
||||
gulp.task('clean', function() {
|
||||
del.sync(['shared/config/generated-config.js'], {force: true});
|
||||
del.sync([output_folder], {force: true});
|
||||
});
|
||||
|
||||
gulp.task('compile', gulpsync.sync([
|
||||
'copy:shared-assets',
|
||||
// 'templates:app',
|
||||
// 'templates:pages',
|
||||
// 'templates:views',
|
||||
'watch'
|
||||
]);
|
||||
|
||||
gulp.task('done', function() {
|
||||
console.log('All Done!! You can start editing your code, LiveReload will update your browser after any change..');
|
||||
});
|
||||
|
||||
// Error handler
|
||||
function handleError(err) {
|
||||
console.log(err.toString());
|
||||
this.emit('end');
|
||||
}
|
||||
|
||||
// // Mini gulp plugin to flip css (rtl)
|
||||
// function flipcss(opt) {
|
||||
|
||||
// if (!opt) opt = {};
|
||||
|
||||
// // creating a stream through which each file will pass
|
||||
// var stream = through.obj(function(file, enc, cb) {
|
||||
// if(file.isNull()) return cb(null, file);
|
||||
|
||||
// if(file.isStream()) {
|
||||
// console.log("todo: isStream!");
|
||||
// }
|
||||
|
||||
// var flippedCss = flip(String(file.contents), opt);
|
||||
// file.contents = new Buffer(flippedCss);
|
||||
// cb(null, file);
|
||||
// });
|
||||
|
||||
// // returning the file stream
|
||||
// return stream;
|
||||
// }
|
||||
'copy:components',
|
||||
'content:html',
|
||||
'scripts:vendor',
|
||||
'scripts:app',
|
||||
'styles:app'
|
||||
]));
|
||||
|
@ -14,6 +14,7 @@
|
||||
"gulp-callback": "^0.0.3",
|
||||
"gulp-changed": "^1.1.0",
|
||||
"gulp-concat": "^2.4.1",
|
||||
"gulp-debug": "^2.0.1",
|
||||
"gulp-expect-file": "0.0.7",
|
||||
"gulp-filter": "^1.0.2",
|
||||
"gulp-foreach": "^0.1.0",
|
||||
@ -48,7 +49,10 @@
|
||||
"scripts": {
|
||||
"prestart": "bower install",
|
||||
"start": "npm install",
|
||||
"poststart": "gulp"
|
||||
"poststart": "gulp",
|
||||
"prebuild": "bower install --allow-root --config.interactive=false",
|
||||
"build": "npm install",
|
||||
"postbuild": "gulp build"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^3.3.0"
|
||||
|
BIN
www/master/shared/assets/img/docArrow.png
Normal file
After Width: | Height: | Size: 373 B |
4
www/master/shared/assets/img/ic_arrow_drop_down_24px.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<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>
|
After Width: | Height: | Size: 166 B |
25
www/master/shared/assets/img/ic_arrow_drop_up_24px.svg
Normal file
@ -0,0 +1,25 @@
|
||||
<?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>
|
After Width: | Height: | Size: 795 B |
@ -0,0 +1 @@
|
||||
<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>
|
After Width: | Height: | Size: 151 B |
@ -0,0 +1 @@
|
||||
<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>
|
After Width: | Height: | Size: 149 B |
BIN
www/master/shared/assets/img/icons/arrow-back.png
Normal file
After Width: | Height: | Size: 635 B |
BIN
www/master/shared/assets/img/icons/favicon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1 @@
|
||||
<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>
|
After Width: | Height: | Size: 158 B |
1
www/master/shared/assets/img/icons/ic_cancel_24px.svg
Normal file
@ -0,0 +1 @@
|
||||
<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>
|
After Width: | Height: | Size: 276 B |
1
www/master/shared/assets/img/icons/ic_close_24px.svg
Normal file
@ -0,0 +1 @@
|
||||
<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>
|
After Width: | Height: | Size: 202 B |
13
www/master/shared/assets/img/icons/ic_menu.svg
Normal file
@ -0,0 +1,13 @@
|
||||
<?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>
|
After Width: | Height: | Size: 791 B |
23
www/master/shared/assets/img/icons/ic_menu_24px.svg
Normal file
@ -0,0 +1,23 @@
|
||||
<?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>
|
After Width: | Height: | Size: 841 B |
BIN
www/master/shared/assets/img/icons/list_control_down.png
Normal file
After Width: | Height: | Size: 309 B |
6
www/master/shared/assets/img/kubernetes.svg
Normal file
After Width: | Height: | Size: 11 KiB |
@ -1,9 +1,9 @@
|
||||
{
|
||||
"k8sApiServer": "ENV_K8S_API_SERVER",
|
||||
"k8sDataServer": "ENV_K8S_DATA_SERVER",
|
||||
"k8sDataPollMinIntervalSec": "ENV_K8S_DATA_POLL_MIN_INTERVAL_SEC",
|
||||
"k8sDataPollMaxIntervalSec": "ENV_K8S_DATA_POLL_MAX_INTERVAL_SEC",
|
||||
"k8sDataPollErrorThreshold": "ENV_K8S_DATA_POLL_ERROR_THRESHOLD",
|
||||
"cAdvisorProxy": "ENV_C_ADVISOR_PROXY",
|
||||
"cAdvisorPort": "ENV_C_ADVISOR_PORT"
|
||||
"k8sApiServer": "/api/v1beta3",
|
||||
"k8sDataServer": "",
|
||||
"k8sDataPollMinIntervalSec": 10,
|
||||
"k8sDataPollMaxIntervalSec": 120,
|
||||
"k8sDataPollErrorThreshold": 5,
|
||||
"cAdvisorProxy": "",
|
||||
"cAdvisorPort": "4194"
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ angular.module("kubernetesApp.config", [])
|
||||
.constant("ENV", {
|
||||
"/": {
|
||||
"k8sApiServer": "/api/v1beta3",
|
||||
"k8sDataServer": "/cluster",
|
||||
"k8sDataServer": "",
|
||||
"k8sDataPollMinIntervalSec": 10,
|
||||
"k8sDataPollMaxIntervalSec": 120,
|
||||
"k8sDataPollErrorThreshold": 5,
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"k8sApiServer": "/api/v1beta3",
|
||||
"k8sDataServer": "/cluster",
|
||||
"k8sDataServer": "",
|
||||
"k8sDataPollMinIntervalSec": 10,
|
||||
"k8sDataPollMaxIntervalSec": 120,
|
||||
"k8sDataPollErrorThreshold": 5,
|
60
www/master/shared/index.html
Normal file
@ -0,0 +1,60 @@
|
||||
<!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
www/master/shared/vendor/angular-json-human/dist/angular-json-human.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
.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}
|
6
www/master/shared/vendor/angular-material/angular-material.css
vendored
Normal file
5
www/master/shared/vendor/d3/d3.min.js
vendored
Normal file
1
www/master/shared/views/partials/404.html
Normal file
@ -0,0 +1 @@
|
||||
<span>The page you're looking for could not be found.</span>
|
@ -0,0 +1,14 @@
|
||||
<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>
|
45
www/master/shared/views/partials/md-table.tmpl.html
Normal file
@ -0,0 +1,45 @@
|
||||
<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_up_24px.svg"></span><span class="md-table-caret" ng-show="!reverse && h.field == predicate"><img src="assets/img/ic_arrow_drop_down_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>
|
14
www/master/shared/views/partials/menu-toggle.tmpl.html
Normal file
@ -0,0 +1,14 @@
|
||||
<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,5 +1,3 @@
|
||||
[
|
||||
"../../third_party/ui/bower_components/angular-json-human/dist/angular-json-human.css",
|
||||
"../../third_party/ui/bower_components/angular-material/angular-material.css",
|
||||
"../../third_party/ui/bower_components/d3/d3.min.js"
|
||||
"shared/vendor/**/*.*"
|
||||
]
|
||||
|