Revert "Upgrade from angularjs (v1) to angular (v6)"

This reverts commit 36aecc1229.
This reverts commit 683f50ed55.

This caused zuul.openstack.org to attempt to GET "https://api/status".

Change-Id: Ib25356f7ea5bfeec84e91195ac161d497f74d73d
This commit is contained in:
James E. Blair 2018-06-27 00:52:12 +00:00 committed by James E. Blair
parent 640fde3545
commit fc1a71f69f
50 changed files with 842 additions and 1781 deletions

View File

@ -3,5 +3,8 @@ plugins:
- standard
rules:
camelcase: off
indent:
- off
- 2
extends:
- ./node_modules/eslint-config-standard/eslintrc.json

View File

@ -39,31 +39,6 @@
ZUUL_REMOTE_IPV4: "{{ nodepool.interface_ip }}"
ZUUL_REMOTE_KEEP: "true"
- job:
name: zuul-build-dashboard
parent: build-javascript-content
success-url: 'npm/html/status.html'
files:
- package.json
- tsconfig.json
- tslint.json
- web/.*
- webpack.config.js
- yarn.lock
vars:
javascript_content_dir: zuul/web/static
zuul_api_url: https://zuul.openstack.org
run: playbooks/dashboard/run.yaml
- job:
name: zuul-build-dashboard-multi-tenant
parent: zuul-build-dashboard
success-url: 'npm/html/tenants.html'
post-run: playbooks/dashboard/multi.yaml
vars:
zuul_api_url: https://softwarefactory-project.io/zuul
javascript_copy_links: false
- project:
check:
jobs:
@ -83,19 +58,25 @@
irrelevant-files:
- zuul/cmd/migrate.py
- playbooks/zuul-migrate/.*
- zuul-build-dashboard
- zuul-build-dashboard-multi-tenant
- build-javascript-content:
success-url: 'npm/html/status.html'
files:
- package.json
- webpack.config.js
- yarn.lock
- web/.*
vars:
javascript_content_dir: zuul/web/static
npm_command: build:dist -- --define ZUUL_API_URL="'https://zuul.openstack.org'"
- nodejs-npm-run-lint:
vars:
node_version: 8
success-url: 'npm/reports/bundle.html'
files:
- package.json
- tsconfig.json
- tslint.json
- web/.*
- webpack.config.js
- yarn.lock
- web/.*
- zuul-stream-functional
- zuul-tox-remote
- nodepool-zuul-functional:
@ -118,18 +99,25 @@
irrelevant-files:
- zuul/cmd/migrate.py
- playbooks/zuul-migrate/.*
- zuul-build-dashboard
- build-javascript-content:
success-url: 'npm/html/status.html'
files:
- package.json
- webpack.config.js
- yarn.lock
- web/.*
vars:
javascript_content_dir: zuul/web/static
npm_command: build:dist -- --define ZUUL_API_URL="'https://zuul.openstack.org'"
- nodejs-npm-run-lint:
vars:
node_version: 8
success-url: 'npm/reports/bundle.html'
files:
- package.json
- tsconfig.json
- tslint.json
- web/.*
- webpack.config.js
- yarn.lock
- web/.*
- zuul-stream-functional
- zuul-tox-remote
post:

View File

@ -1,14 +1,13 @@
Zuul Dashboard Javascript
=========================
Zuul Web Javascript
===================
zuul-web has an html, css and javascript component, `zuul-dashboard`, that
is managed using Javascript toolchains. It is intended to be served by zuul-web
directly from zuul/web/static in the simple case, or to be published to
an alternate static web location, such as an Apache server.
The web dashboard is written in `Typescript`_ and `Angular`_ and is
managed by `yarn`_ and `webpack`_ which in turn both assume a functioning
and recent `nodejs`_ installation.
The web applications are managed by `yarn`_ and `webpack`_ which in turn both
assume a functioning and recent `nodejs`_ installation.
For the impatient who don't want deal with javascript toolchains
----------------------------------------------------------------
@ -106,21 +105,14 @@ such as minifying and transpiling for older browsers. It takes a
javascript-first approach, and generates a html file that includes the
appropriate javascript and CSS to get going.
We need to modify the html generated for each of our pages, so there are
templates in ``web/templates``.
The main `webpack`_ config file is ``webpack.config.js``. In the Zuul tree that
file is a stub file that includes either a dev or a prod environment from
``web/config/webpack.dev.js`` or ``web/config/webpack.prod.js``. Most of the
important bits are in ``web/config/webpack.common.js``.
Angular Components
------------------
Each page has an `Angular Component`_ associated with it. For instance, the
``status.html`` page has code in ``web/status/status.component.ts`` and the
relevant HTML can be found in ``web/status/status.component.html``.
Mapping of pages/urls to components can be found in the routing module in
``web/app-routing.module.ts``.
Development
-----------
@ -155,13 +147,6 @@ be configured to use the API endpoint from OpenStack's Zuul. The
``webpack-dev-server`` watches for changes to the files and
re-compiles/refresh as needed.
.. code-block:: bash
npm run start:multi
will do the same but will be pointed at the SoftwareFactory Project Zuul, which
is multi-tenant.
Arbitrary command line options will be passed through after a ``--`` such as:
.. code-block:: bash
@ -224,6 +209,3 @@ our case we use it for both.
.. _webpack: https://webpack.js.org/
.. _devtool: https://webpack.js.org/configuration/devtool/#devtool
.. _nodeenv: https://pypi.org/project/nodeenv
.. _Angular: https://angular.io
.. _Angular Component: https://angular.io/guide/architecture-components
.. _Typescript: https://www.typescriptlang.org/

View File

@ -2,7 +2,7 @@
"name": "@zuul-ci/dashboard",
"version": "1.0.0",
"description": "Web Dashboard for Zuul",
"main": "web/main.ts",
"main": "index.js",
"repository": "https://git.zuul-ci.org/zuul",
"author": "OpenStack Infra",
"license": "Apache-2.0",
@ -12,49 +12,31 @@
]
},
"dependencies": {
"@angular/common": "^6.0.3",
"@angular/compiler": "^6.0.3",
"@angular/core": "^6.0.3",
"@angular/forms": "^6.0.3",
"@angular/platform-browser": "^6.0.3",
"@angular/platform-browser-dynamic": "^6.0.3",
"@angular/router": "^6.0.3",
"angular": "^1.5.8",
"bootstrap": "3.1.1",
"core-js": "^2.5.3",
"graphitejs": "https://github.com/prestontimmons/graphitejs/archive/master.tar.gz",
"jquery": "^3.3.1",
"jquery-visibility": "https://github.com/mathiasbynens/jquery-visibility/archive/master.tar.gz",
"reflect-metadata": "^0.1.12",
"rxjs": "^6.2.0",
"rxjs-compat": "^6.0.0-rc.0",
"zone.js": "^0.8.26"
"jquery-visibility": "https://github.com/mathiasbynens/jquery-visibility/archive/master.tar.gz"
},
"scripts": {
"build": "npm run build:dist",
"build:dev": "webpack --env=dev",
"build:dist": "webpack --env=prod",
"build:dist-with-depends": "yarn install && npm run build:dist",
"format": "tslint --project tsconfig.json -c tslint.json --fix",
"format": "eslint --fix web/*.js",
"lint": "webpack --env=lint",
"start": "webpack-dev-server --env=dev --define ZUUL_API_URL=\"'https://zuul.openstack.org'\" --open-page='status.html'",
"start:multi": "webpack-dev-server --env=dev --define ZUUL_API_URL=\"'https://softwarefactory-project.io/zuul'\" --open-page='tenants.html'",
"start:basic": "webpack-dev-server --env=dev --open-page='status.html?demo=basic'",
"start:openstack": "webpack-dev-server --env=dev --open-page='status.html?demo=openstack'",
"start:tree": "webpack-dev-server --env=dev --open-page='status.html?demo=tree'"
},
"devDependencies": {
"@types/angular": "^1.6.43",
"@types/bootstrap": "^4.0.0",
"@types/core-js": "^0.9.46",
"@types/jquery": "^3.3.1",
"@types/node": "^9.4.7",
"babel-core": "^6.26.0",
"babel-eslint": "^8.0.3",
"babel-loader": "^7.1.2",
"babel-plugin-angularjs-annotate": "^0.8.2",
"babel-preset-env": "^1.6.1",
"clean-webpack-plugin": "^0.1.16",
"codelyzer": "^4.2.1",
"css-loader": "^0.28.10",
"eslint": ">=3.19.0",
"eslint-config-standard": "^11.0.0-beta.0",
@ -64,17 +46,9 @@
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"file-loader": "^1.1.11",
"fork-ts-checker-webpack-plugin": "^0.4.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.0.0",
"resolve-url-loader": "^2.1.0",
"style-loader": "^0.20.3",
"ts-loader": "^4.1.0",
"ts-node": "^5.0.1",
"tslint": "^5.9.1",
"tslint-angular": "^1.1.1",
"tslint-loader": "^3.6.0",
"typescript": "2.7.2",
"url-loader": "^0.5.9",
"webpack": "^4.4.0",
"webpack-archive-plugin": "^3.0.0",

View File

@ -1,11 +0,0 @@
- hosts: all
tasks:
- name: Make symlinks to allow multi-tenant preview to work
file:
src: .
dest: '{{ zuul.project.src_dir }}/{{ javascript_content_dir }}/{{ item }}'
state: link
with_items:
- local
- t

View File

@ -1,18 +0,0 @@
- hosts: all
roles:
- revoke-sudo
- set-zuul-log-path-fact
# Both sets of quotes are required.
# The "" quotes are for the shell to protect the '' quotes.
# We need the '' quotes because defines here are essentially
# direct string substitutions. Therefore:
# --define "ZUUL_API_URL='https://zuul.openstack.org'"
# with the javascript code:
# return ZUUL_API_URL
# results in
# return 'https://zuul.openstack.org'
# in the compiled javascript.
- role: npm
npm_command: >-
build:dist --
--define "ZUUL_API_URL='{{ zuul_api_url }}'"

View File

@ -1,17 +0,0 @@
{
"compilerOptions": {
"sourceMap": true,
"moduleResolution": "node",
"outDir": "./zuul/web/static/",
"noImplicitAny": false,
"target": "es6",
"lib": [ "es2015", "dom" ],
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowJs": false
},
"include": [
"webpack.config.ts",
"web/**/*.ts"
]
}

View File

@ -1,7 +0,0 @@
{
"extends": ["tslint-angular"],
"rules": {
"array-type": [true, "array-simple"],
"semicolon": [true, "never"]
}
}

View File

@ -1,80 +0,0 @@
// Routing information for Zuul dashboard pages
//
// Copyright 2018 Red Hat, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import { NgModule, isDevMode } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import BuildsComponent from './builds/builds.component'
import JobsComponent from './jobs/jobs.component'
import StatusComponent from './status/status.component'
import StreamComponent from './stream/stream.component'
import TenantsComponent from './tenants/tenants.component'
// Have all routes go to builds.html for now
const appRoutes: Routes = [
{
path: 't/:tenant/builds.html',
component: BuildsComponent
},
{
path: 'builds.html',
component: BuildsComponent
},
{
path: 't/:tenant/status.html',
component: StatusComponent
},
{
path: 'status.html',
component: StatusComponent
},
{
path: 't/:tenant/jobs.html',
component: JobsComponent
},
{
path: 'jobs.html',
component: JobsComponent
},
{
path: 'stream.html',
component: StreamComponent
},
{
path: 't/:tenant/stream.html',
component: StreamComponent
},
{
path: 'tenants.html',
component: TenantsComponent
},
{
path: '**',
component: StatusComponent
}
]
@NgModule({
imports: [
RouterModule.forRoot(
appRoutes,
// Enable router tracing in devel mode. This prints router decisions
// to the console.log.
{ enableTracing: isDevMode() }
)],
exports: [RouterModule]
})
export class AppRoutingModule { }

View File

@ -1,70 +0,0 @@
// Entrypoint for Zuul dashboard pages
//
// Copyright 2018 Red Hat, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import './styles/zuul.css'
import { APP_BASE_HREF } from '@angular/common'
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HttpClientModule } from '@angular/common/http'
import { FormsModule } from '@angular/forms'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { getBaseHref } from './util'
import BuildsComponent from './builds/builds.component'
import NavigationComponent from './navigation/navigation.component'
import JobsComponent from './jobs/jobs.component'
import StatusComponent from './status/status.component'
import StreamComponent from './stream/stream.component'
import TenantsComponent from './tenants/tenants.component'
import ZuulService from './zuul/zuul.service'
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
AppRoutingModule,
],
declarations: [
AppComponent,
BuildsComponent,
NavigationComponent,
JobsComponent,
StatusComponent,
StreamComponent,
TenantsComponent
],
entryComponents: [
BuildsComponent,
NavigationComponent,
JobsComponent,
StatusComponent,
StreamComponent,
TenantsComponent
],
providers: [
ZuulService,
{provide: APP_BASE_HREF, useValue: getBaseHref()}
],
bootstrap: [
AppComponent
]
})
export class AppModule { }

View File

@ -1,28 +0,0 @@
// Copyright 2017 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
export default class Build {
constructor(
public job_name: string,
public result: string,
public project: string,
public pipeline: string,
public ref_url: string,
public duration: number,
public start_time: string,
public log_url?: string,
) {}
}

View File

@ -1,67 +0,0 @@
<!--
Copyright 2017 Red Hat
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<div class="container-fluid">
<span style="float: right; margin-top: 7px;">
<form class="form-inline" #buildsForm="ngForm">
<div class="form-group">
<label for="pipeline">Pipeline:</label>
<input class="form-control" id="pipeline"
[(ngModel)]="pipeline" name="pipeline" />
</div>
<div class="form-group">
<label for="job_name">Job:</label>
<input class="form-control" id="job_name"
[(ngModel)]="job_name" name="job_name" />
</div>
<div class="form-group">
<label for="project">Project:</label>
<input class="form-control" id="project"
[(ngModel)]="project" name="project">
</div>
<button type="submit" class="btn" (click)='buildsFetch()'>
Refresh
</button>
</form>
</span>
</div>
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Job</th>
<th>Project</th>
<th>Branch</th>
<th>Pipeline</th>
<th>Change</th>
<th>Duration</th>
<th>Log url</th>
<th>Start time</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let build of builds" [class]="getRowClass(build)">
<td>{{ build.job_name }}</td>
<td>{{ build.project }}</td>
<td>{{ build.branch }}</td>
<td>{{ build.pipeline }}</td>
<td><a href="{{ build.ref_url }}" target="_self">change</a></td>
<td>{{ build.duration }} seconds</td>
<td><a *ngIf="build.log_url" href="{{ build.log_url }}" target="_self">logs</a></td>
<td>{{ build.start_time }}</td>
<td>{{ build.result }}</td>
</tr>
</tbody>
</table>

View File

@ -1,78 +0,0 @@
// Copyright 2017 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import { Component, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { HttpClient, HttpParams } from '@angular/common/http'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/operator/map'
import ZuulService from '../zuul/zuul.service'
import Build from './build'
@Component({
template: require('./builds.component.html')
})
export default class BuildsComponent implements OnInit {
builds: Build[]
pipeline: string
job_name: string
project: string
tenant: string
constructor(
private http: HttpClient, private route: ActivatedRoute,
private zuul: ZuulService
) {}
ngOnInit() {
this.tenant = this.route.snapshot.paramMap.get('tenant')
this.pipeline = this.route.snapshot.queryParamMap.get('pipeline')
this.job_name = this.route.snapshot.queryParamMap.get('job_name')
this.project = this.route.snapshot.queryParamMap.get('project')
this.buildsFetch()
}
buildsFetch(): void {
let params = new HttpParams()
if (this.pipeline) { params = params.set('pipeline', this.pipeline) }
if (this.job_name) { params = params.set('job_name', this.job_name) }
if (this.project) { params = params.set('project', this.project) }
const remoteLocation = this.zuul.getSourceUrl('builds', this.tenant)
this.http.get<Build[]>(remoteLocation, {params: params})
.subscribe(builds => {
for (const build of builds) {
/* Fix incorect url for post_failure job */
/* TODO(mordred) Maybe let's fix this server side? */
if (build.log_url === build.job_name) {
build.log_url = undefined
}
}
this.builds = builds
})
}
getRowClass(build: Build): string {
if (build.result === 'SUCCESS') {
return 'success'
} else {
return 'warning'
}
}
}

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<!--
Copyright 2017 Red Hat
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title id='pagetitle'><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<zuul-dashboard></zuul-dashboard>
</body></html>

View File

@ -1,13 +1,9 @@
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './web/main.ts',
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
entry: './web/main.js',
output: {
filename: '[name].js',
// path.resolve(__dirname winds up relative to the config dir
@ -24,14 +20,13 @@ module.exports = {
cacheGroups: {
commons: {
test: /node_modules/,
name: 'vendor',
chunks: 'all'
name: "vendor",
chunks: "all"
}
}
}
},
plugins: [
new ForkTsCheckerWebpackPlugin(),
new webpack.ProvidePlugin({
$: 'jquery/dist/jquery',
jQuery: 'jquery/dist/jquery',
@ -41,43 +36,32 @@ module.exports = {
// output file.
new HtmlWebpackPlugin({
filename: 'status.html',
template: 'web/config/main.ejs',
template: 'web/templates/status.ejs',
title: 'Zuul Status'
}),
new HtmlWebpackPlugin({
title: 'Zuul Builds',
template: 'web/config/main.ejs',
template: 'web/templates/builds.ejs',
filename: 'builds.html'
}),
new HtmlWebpackPlugin({
title: 'Zuul Jobs',
template: 'web/config/main.ejs',
template: 'web/templates/jobs.ejs',
filename: 'jobs.html'
}),
new HtmlWebpackPlugin({
title: 'Zuul Tenants',
template: 'web/config/main.ejs',
template: 'web/templates/tenants.ejs',
filename: 'tenants.html'
}),
new HtmlWebpackPlugin({
title: 'Zuul Console Stream',
template: 'web/config/main.ejs',
template: 'web/templates/stream.ejs',
filename: 'stream.html'
})
],
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: 'ts-loader',
options: {
// disable type checker - we will use it in fork plugin
transpileOnly: true
}
}
},
{
test: /\.js$/,
exclude: /node_modules/,
@ -101,7 +85,7 @@ module.exports = {
{
test: /\.woff(2)?(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
loader: "url-loader",
options: {
limit: 10000,
mimetype: 'application/font-woff'
@ -111,7 +95,7 @@ module.exports = {
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
loader: "url-loader",
options: {
limit: 10000,
mimetype: 'application/octet-stream'
@ -125,7 +109,7 @@ module.exports = {
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
loader: "url-loader",
options: {
limit: 10000,
mimetype: 'image/svg+xml'
@ -134,7 +118,7 @@ module.exports = {
},
{
test: /\.html$/,
use: ['html-loader'],
use: ['raw-loader'],
exclude: /node_modules/
}
]

View File

@ -11,13 +11,26 @@ module.exports = Merge(CommonConfig, {
contentBase: path.resolve(__dirname, './zuul/web/static'),
publicPath: '/'
},
module: {
rules: [
{
enforce: 'pre',
test: /\.js$/,
use: [
'babel-loader',
'eslint-loader'
],
exclude: /node_modules/,
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
// We only need to bundle the demo files when we're running locally
new webpack.ProvidePlugin({
DemoStatusBasic: '../config/status-basic.json',
DemoStatusOpenStack: '../config/status-openstack.json',
DemoStatusTree: '../config/status-tree.json'
DemoStatusBasic: './status-basic.json',
DemoStatusOpenStack: './status-openstack.json',
DemoStatusTree: './status-tree.json'
}),
]
})

View File

@ -2,27 +2,12 @@ const path = require('path');
const webpack = require('webpack');
const Merge = require('webpack-merge');
const CommonConfig = require('./webpack.common.js');
const BundleAnalyzer = require('webpack-bundle-analyzer');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = Merge(CommonConfig, {
mode: 'development',
module: {
rules: [
{
enforce: 'pre',
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'tslint-loader',
options: {
emitErrors: true,
typeCheck: false,
}
}
]
},
{
enforce: 'pre',
test: /\.js$/,
@ -36,7 +21,7 @@ module.exports = Merge(CommonConfig, {
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new BundleAnalyzer.BundleAnalyzerPlugin({
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: '../../../reports/bundle.html',
generateStatsFile: true,

115
web/dashboard.js Normal file
View File

@ -0,0 +1,115 @@
// @licstart The following is the entire license notice for the
// JavaScript code in this page.
//
// Copyright 2017 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
// @licend The above is the entire license notice
// for the JavaScript code in this page.
import 'bootstrap/dist/css/bootstrap.css'
import angular from 'angular'
import './styles/zuul.css'
import './jquery.zuul'
import { getSourceUrl } from './util'
angular.module('zuulTenants', []).controller(
'mainController', function ($scope, $http, $location) {
$scope.tenants = undefined
$scope.tenants_fetch = function () {
$http.get(getSourceUrl('tenants', $location))
.then(function success (result) {
$scope.tenants = result.data
})
}
$scope.tenants_fetch()
})
angular.module('zuulJobs', [], function ($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
})
}).controller(
'mainController', function ($scope, $http, $location) {
$scope.jobs = undefined
$scope.jobs_fetch = function () {
$http.get(getSourceUrl('jobs', $location))
.then(function success (result) {
$scope.jobs = result.data
})
}
$scope.jobs_fetch()
})
angular.module('zuulBuilds', [], function ($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
})
}).controller('mainController', function ($scope, $http, $location) {
$scope.rowClass = function (build) {
if (build.result === 'SUCCESS') {
return 'success'
} else {
return 'warning'
}
}
let queryArgs = $location.search()
let url = $location.url()
if (queryArgs['source_url']) {
$scope.tenant = undefined
} else {
let tenantStart = url.lastIndexOf(
'/', url.lastIndexOf('/builds.html') - 1) + 1
let tenantLength = url.lastIndexOf('/builds.html') - tenantStart
$scope.tenant = url.substr(tenantStart, tenantLength)
}
$scope.builds = undefined
if (queryArgs['pipeline']) {
$scope.pipeline = queryArgs['pipeline']
} else { $scope.pipeline = '' }
if (queryArgs['job_name']) {
$scope.job_name = queryArgs['job_name']
} else { $scope.job_name = '' }
if (queryArgs['project']) {
$scope.project = queryArgs['project']
} else { $scope.project = '' }
$scope.builds_fetch = function () {
let queryString = ''
if ($scope.tenant) { queryString += '&tenant=' + $scope.tenant }
if ($scope.pipeline) { queryString += '&pipeline=' + $scope.pipeline }
if ($scope.job_name) { queryString += '&job_name=' + $scope.job_name }
if ($scope.project) { queryString += '&project=' + $scope.project }
if (queryString !== '') { queryString = '?' + queryString.substr(1) }
$http.get(getSourceUrl('builds', $location) + queryString)
.then(function success (result) {
for (let buildPos = 0;
buildPos < result.data.length;
buildPos += 1) {
let build = result.data[buildPos]
if (build.node_name == null) {
build.node_name = 'master'
}
/* Fix incorect url for post_failure job */
if (build.log_url === build.job_name) {
build.log_url = undefined
}
}
$scope.builds = result.data
})
}
$scope.builds_fetch()
})

View File

@ -1,17 +0,0 @@
// Copyright 2018 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
export default class JobDetails {
source_context: string
}

View File

@ -1,25 +0,0 @@
// Copyright 2018 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import JobDetails from './details'
export default class Job {
expanded: boolean
details: JobDetails
name: string
constructor() {
this.expanded = false
}
}

View File

@ -1,47 +0,0 @@
<!--
Copyright 2017 Red Hat
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<div class="container-fluid">
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Last builds</th>
</tr>
</thead>
<tbody>
<ng-container *ngFor="let job of jobs">
<tr>
<td>{{ job.name }}</td>
<td>{{ job.description }}</td>
<td><a [routerLink]="['../builds.html']"
[queryParams]="{job_name: job.name}" target="_self">
builds</a></td>
</tr>
<tr *ngIf="job.expanded">
<td colspan="3">
<ul class="list-group">
<li class="list-group-item" *ngFor="let detail of job.details">
<!-- TODO: make clickable link to cgit files ? -->
{{ detail.source_context }}
</li>
</ul>
</td>
</tr>
</ng-container>
</tbody>
</table>
</div>

View File

@ -1,52 +0,0 @@
// Copyright 2017 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import { Component, OnInit } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { ActivatedRoute } from '@angular/router'
import ZuulService from '../zuul/zuul.service'
import JobDetails from './details'
import Job from './job'
@Component({
template: require('./jobs.component.html')
})
export default class JobsComponent implements OnInit {
jobs: Job[]
tenant?: string
constructor(
private http: HttpClient, private route: ActivatedRoute,
private zuul: ZuulService
) {}
ngOnInit() {
this.tenant = this.route.snapshot.paramMap.get('tenant')
this.jobsFetch()
}
jobsFetch(): void {
this.http.get<Job[]>(this.zuul.getSourceUrl('jobs', this.tenant))
.subscribe(jobs => this.injestJobs(jobs))
}
injestJobs(jobs: Job[]): void {
for (const job of jobs) {
job.expanded = false
}
this.jobs = jobs
}
}

View File

@ -1,6 +1,9 @@
/* global Image, jQuery */
// jquery plugin for Zuul status page
//
// @licstart The following is the entire license notice for the
// JavaScript code in this page.
//
// Copyright 2012 OpenStack Foundation
// Copyright 2013 Timo Tijhof
// Copyright 2013 Wikimedia Foundation
@ -17,14 +20,17 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
// @licend The above is the entire license notice
// for the JavaScript code in this page.
import RedImage from '../images/red.png'
import GreyImage from '../images/grey.png'
import GreenImage from '../images/green.png'
import BlackImage from '../images/black.png'
import LineImage from '../images/line.png'
import LineAngleImage from '../images/line-angle.png'
import LineTImage from '../images/line-t.png';
import RedImage from './images/red.png'
import GreyImage from './images/grey.png'
import GreenImage from './images/green.png'
import BlackImage from './images/black.png'
import LineImage from './images/line.png'
import LineAngleImage from './images/line-angle.png'
import LineTImage from './images/line-t.png';
(function ($) {
function setCookie (name, value) {
@ -75,20 +81,20 @@ import LineTImage from '../images/line-t.png';
if (options.graphite_url !== '') {
if (!(pipelineName in zuulSparklineURLs)) {
zuulSparklineURLs[pipelineName] = $.fn.graphite
.geturl({
url: options.graphite_url,
from: '-8hours',
width: 100,
height: 26,
margin: 0,
hideLegend: true,
hideAxes: true,
hideGrid: true,
target: [
'color(stats.gauges.zuul.pipeline.' + pipelineName +
".current_changes, '6b8182')"
]
})
.geturl({
url: options.graphite_url,
from: '-8hours',
width: 100,
height: 26,
margin: 0,
hideLegend: true,
hideAxes: true,
hideGrid: true,
target: [
'color(stats.gauges.zuul.pipeline.' + pipelineName +
".current_changes, '6b8182')"
]
})
}
return zuulSparklineURLs[pipelineName]
}
@ -101,34 +107,34 @@ import LineTImage from '../images/line-t.png';
if (job.result !== null) {
$jobLine.append(
$('<a />')
.addClass('zuul-job-name')
.attr('href', job.report_url)
.text(job.name)
)
$('<a />')
.addClass('zuul-job-name')
.attr('href', job.report_url)
.text(job.name)
)
} else if (job.url !== null) {
$jobLine.append(
$('<a />')
.addClass('zuul-job-name')
.attr('href', job.url)
.text(job.name)
)
$('<a />')
.addClass('zuul-job-name')
.attr('href', job.url)
.text(job.name)
)
} else {
$jobLine.append(
$('<span />')
.addClass('zuul-job-name')
.text(job.name)
)
$('<span />')
.addClass('zuul-job-name')
.text(job.name)
)
}
$jobLine.append(this.job_status(job))
if (job.voting === false) {
$jobLine.append(
$(' <small />')
.addClass('zuul-non-voting-desc')
.text(' (non-voting)')
)
$(' <small />')
.addClass('zuul-non-voting-desc')
.text(' (non-voting)')
)
}
$jobLine.append($('<div style="clear: both"></div>'))
@ -143,7 +149,7 @@ import LineTImage from '../images/line-t.png';
if (result === 'in progress') {
return this.job_progress_bar(job.elapsed_time,
job.remaining_time)
job.remaining_time)
} else {
return this.status_label(result)
}
@ -178,17 +184,17 @@ import LineTImage from '../images/line-t.png';
let progressPercent = 100 * (elapsedTime / (elapsedTime +
remainingTime))
let $barInner = $('<div />')
.addClass('progress-bar')
.attr('role', 'progressbar')
.attr('aria-valuenow', 'progressbar')
.attr('aria-valuemin', progressPercent)
.attr('aria-valuemin', '0')
.attr('aria-valuemax', '100')
.css('width', progressPercent + '%')
.addClass('progress-bar')
.attr('role', 'progressbar')
.attr('aria-valuenow', 'progressbar')
.attr('aria-valuemin', progressPercent)
.attr('aria-valuemin', '0')
.attr('aria-valuemax', '100')
.css('width', progressPercent + '%')
let $barOutter = $('<div />')
.addClass('progress zuul-job-result')
.append($barInner)
.addClass('progress zuul-job-result')
.append($barInner)
return $barOutter
},
@ -244,7 +250,7 @@ import LineTImage from '../images/line-t.png';
changeTotalProgressBar: function (change) {
let jobPercent = Math.floor(100 / change.jobs.length)
let $barOutter = $('<div />')
.addClass('progress zuul-change-total-result')
.addClass('progress zuul-change-total-result')
$.each(change.jobs, function (i, job) {
let result = job.result ? job.result.toLowerCase() : null
@ -254,7 +260,7 @@ import LineTImage from '../images/line-t.png';
if (result !== 'queued') {
let $barInner = $('<div />')
.addClass('progress-bar')
.addClass('progress-bar')
switch (result) {
case 'success':
@ -272,7 +278,7 @@ import LineTImage from '../images/line-t.png';
break
}
$barInner.attr('title', job.name)
.css('width', jobPercent + '%')
.css('width', jobPercent + '%')
$barOutter.append($barInner)
}
})
@ -287,25 +293,25 @@ import LineTImage from '../images/line-t.png';
let githubId = changeId.match(/^([0-9]+),([0-9a-f]{40})$/)
if (githubId) {
$changeLink.append(
$('<a />').attr('href', change.url).append(
$('<abbr />')
.attr('title', changeId)
.text('#' + githubId[1])
)
)
$('<a />').attr('href', change.url).append(
$('<abbr />')
.attr('title', changeId)
.text('#' + githubId[1])
)
)
} else if (/^[0-9a-f]{40}$/.test(changeId)) {
let changeIdShort = changeId.slice(0, 7)
$changeLink.append(
$('<a />').attr('href', change.url).append(
$('<abbr />')
.attr('title', changeId)
.text(changeIdShort)
)
)
$('<a />').attr('href', change.url).append(
$('<abbr />')
.attr('title', changeId)
.text(changeIdShort)
)
)
} else {
$changeLink.append(
$('<a />').attr('href', change.url).text(changeId)
)
$('<a />').attr('href', change.url).text(changeId)
)
}
} else {
if (changeId.length === 40) {
@ -315,54 +321,54 @@ import LineTImage from '../images/line-t.png';
}
let $changeProgressRowLeft = $('<div />')
.addClass('col-xs-4')
.append($changeLink)
.addClass('col-xs-4')
.append($changeLink)
let $changeProgressRowRight = $('<div />')
.addClass('col-xs-8')
.append(this.changeTotalProgressBar(change))
.addClass('col-xs-8')
.append(this.changeTotalProgressBar(change))
let $changeProgressRow = $('<div />')
.addClass('row')
.append($changeProgressRowLeft)
.append($changeProgressRowRight)
.addClass('row')
.append($changeProgressRowLeft)
.append($changeProgressRowRight)
let $projectSpan = $('<span />')
.addClass('change_project')
.text(change.project)
.addClass('change_project')
.text(change.project)
let $left = $('<div />')
.addClass('col-xs-8')
.append($projectSpan, $changeProgressRow)
.addClass('col-xs-8')
.append($projectSpan, $changeProgressRow)
let remainingTime = this.time(change.remaining_time, true)
let enqueueTime = this.enqueueTime(change.enqueue_time)
let $remainingTime = $('<small />').addClass('time')
.attr('title', 'Remaining Time').html(remainingTime)
.attr('title', 'Remaining Time').html(remainingTime)
let $enqueueTime = $('<small />').addClass('time')
.attr('title', 'Elapsed Time').html(enqueueTime)
.attr('title', 'Elapsed Time').html(enqueueTime)
let $right = $('<div />')
if (change.live === true) {
$right.addClass('col-xs-4 text-right')
.append($remainingTime, $('<br />'), $enqueueTime)
.append($remainingTime, $('<br />'), $enqueueTime)
}
let $header = $('<div />')
.addClass('row')
.append($left, $right)
.addClass('row')
.append($left, $right)
return $header
},
change_list: function (jobs) {
let format = this
let $list = $('<ul />')
.addClass('list-group zuul-patchset-body')
.addClass('list-group zuul-patchset-body')
$.each(jobs, function (i, job) {
let $item = $('<li />')
.addClass('list-group-item')
.addClass('zuul-change-job')
.append(format.job(job))
.addClass('list-group-item')
.addClass('zuul-change-job')
.append(format.job(job))
$list.append($item)
})
@ -371,17 +377,17 @@ import LineTImage from '../images/line-t.png';
changePanel: function (change) {
let $header = $('<div />')
.addClass('panel-heading zuul-patchset-header')
.append(this.changeHeader(change))
.addClass('panel-heading zuul-patchset-header')
.append(this.changeHeader(change))
let panelId = change.id ? change.id.replace(',', '_')
: change.project.replace('/', '_') +
: change.project.replace('/', '_') +
'-' + change.enqueue_time
let $panel = $('<div />')
.attr('id', panelId)
.addClass('panel panel-default zuul-change')
.append($header)
.append(this.change_list(change.jobs))
.attr('id', panelId)
.addClass('panel panel-default zuul-change')
.append($header)
.append(this.change_list(change.jobs))
$header.click(this.toggle_patchset)
return $panel
@ -414,9 +420,9 @@ import LineTImage from '../images/line-t.png';
}
let $icon = $('<img />')
.attr('src', iconFile)
.attr('title', iconTitle)
.css('display', 'block')
.attr('src', iconFile)
.attr('title', iconTitle)
.css('margin-top', '-6px')
return $icon
},
@ -426,27 +432,27 @@ import LineTImage from '../images/line-t.png';
for (let i = 0; i < changeQueue._tree_columns; i++) {
let $treeCell = $('<td />')
.css('height', '100%')
.css('padding', '0 0 10px 0')
.css('margin', '0')
.css('width', '16px')
.css('min-width', '16px')
.css('overflow', 'hidden')
.css('vertical-align', 'top')
.css('height', '100%')
.css('padding', '0 0 10px 0')
.css('margin', '0')
.css('width', '16px')
.css('min-width', '16px')
.css('overflow', 'hidden')
.css('vertical-align', 'top')
if (i < change._tree.length && change._tree[i] !== null) {
$treeCell.css('background-image',
'url(' + LineImage + ')')
.css('background-repeat', 'repeat-y')
'url(' + LineImage + ')')
.css('background-repeat', 'repeat-y')
}
if (i === change._tree_index) {
$treeCell.append(
this.change_status_icon(change))
this.change_status_icon(change))
}
if (change._tree_branches.indexOf(i) !== -1) {
let $image = $('<img />')
.css('vertical-align', 'baseline')
.css('vertical-align', 'baseline')
if (change._tree_branches.indexOf(i) ===
change._tree_branches.length - 1) {
// Angle line
@ -462,17 +468,17 @@ import LineTImage from '../images/line-t.png';
let changeWidth = 360 - 16 * changeQueue._tree_columns
let $changeColumn = $('<td />')
.css('width', changeWidth + 'px')
.addClass('zuul-change-cell')
.append(this.changePanel(change))
.css('width', changeWidth + 'px')
.addClass('zuul-change-cell')
.append(this.changePanel(change))
$changeRow.append($changeColumn)
let $changeTable = $('<table />')
.addClass('zuul-change-box')
.css('-moz-box-sizing', 'content-box')
.css('box-sizing', 'content-box')
.append($changeRow)
.addClass('zuul-change-box')
.css('-moz-box-sizing', 'content-box')
.css('box-sizing', 'content-box')
.append($changeRow)
return $changeTable
},
@ -480,8 +486,8 @@ import LineTImage from '../images/line-t.png';
pipeline_sparkline: function (pipelineName) {
if (options.graphite_url !== '') {
let $sparkline = $('<img />')
.addClass('pull-right')
.attr('src', getSparklineURL(pipelineName))
.addClass('pull-right')
.attr('src', getSparklineURL(pipelineName))
return $sparkline
}
return false
@ -490,28 +496,28 @@ import LineTImage from '../images/line-t.png';
pipeline_header: function (pipeline, count) {
// Format the pipeline name, sparkline and description
let $headerDiv = $('<div />')
.addClass('zuul-pipeline-header')
.addClass('zuul-pipeline-header')
let $heading = $('<h3 />')
.css('vertical-align', 'middle')
.text(pipeline.name)
.append(
$('<span />')
.addClass('badge pull-right')
.css('vertical-align', 'middle')
.css('margin-top', '0.5em')
.text(count)
)
.append(this.pipeline_sparkline(pipeline.name))
.css('vertical-align', 'middle')
.text(pipeline.name)
.append(
$('<span />')
.addClass('badge pull-right')
.css('vertical-align', 'middle')
.css('margin-top', '0.5em')
.text(count)
)
.append(this.pipeline_sparkline(pipeline.name))
$headerDiv.append($heading)
if (typeof pipeline.description === 'string') {
let descr = $('<small />')
$.each(pipeline.description.split(/\r?\n\r?\n/),
function (index, descrPart) {
descr.append($('<p />').text(descrPart))
})
function (index, descrPart) {
descr.append($('<p />').text(descrPart))
})
$headerDiv.append($('<p />').append(descr))
}
return $headerDiv
@ -520,44 +526,34 @@ import LineTImage from '../images/line-t.png';
pipeline: function (pipeline, count) {
let format = this
let $html = $('<div />')
.addClass('zuul-pipeline col-md-4')
.append(this.pipeline_header(pipeline, count))
.addClass('zuul-pipeline col-md-4')
.append(this.pipeline_header(pipeline, count))
$.each(pipeline.change_queues, function (queueIndex, changeQueue) {
$.each(changeQueue.heads, function (headIndex, changes) {
let $changeQueueHtml = $('<div />')
.addClass('change-queue')
.data('zuul-pipeline', pipeline.name)
$html.append($changeQueueHtml)
if (pipeline.change_queues.length > 1 && headIndex === 0) {
let name = changeQueue.name
let shortName = name
if (shortName.length > 32) {
shortName = shortName.substr(0, 32) + '...'
}
$changeQueueHtml.append($('<p />')
.text('Queue: ')
.append(
$('<abbr />')
.attr('title', name)
.text(shortName)
)
)
$html.append($('<p />')
.text('Queue: ')
.append(
$('<abbr />')
.attr('title', name)
.text(shortName)
)
)
}
let $changeBoxes = $.map(changes, function (change) {
return format.change_with_status_tree(change, changeQueue)
$.each(changes, function (changeIndex, change) {
let $changeBox =
format.change_with_status_tree(
change, changeQueue)
$html.append($changeBox)
format.display_patchset($changeBox)
})
let visible = $.map($changeBoxes, function (changeBox) {
$changeQueueHtml.append(changeBox)
return format.display_patchset(changeBox)
}).some(function (visible) {
return visible
})
if (!visible) $changeQueueHtml.remove()
})
})
return $html
@ -566,7 +562,7 @@ import LineTImage from '../images/line-t.png';
toggle_patchset: function (e) {
// Toggle showing/hiding the patchset when the header is clicked.
if (e.target.nodeName.toLowerCase() === 'a') {
// Ignore clicks from gerrit patch set link
// Ignore clicks from gerrit patch set link
return
}
@ -575,7 +571,7 @@ import LineTImage from '../images/line-t.png';
let $body = $panel.children('.zuul-patchset-body')
$body.toggle(200)
let collapsedIndex = collapsedExceptions.indexOf(
$panel.attr('id'))
$panel.attr('id'))
if (collapsedIndex === -1) {
// Currently not an exception, add it to list
collapsedExceptions.push($panel.attr('id'))
@ -594,10 +590,10 @@ import LineTImage from '../images/line-t.png';
let panelChange = $panel.attr('id')
let $body = $panel.children('.zuul-patchset-body')
let expandByDefault = $('#expand_by_default')
.prop('checked')
.prop('checked')
let collapsedIndex = collapsedExceptions
.indexOf(panelChange)
.indexOf(panelChange)
if ((expandByDefault && collapsedIndex === -1) ||
(!expandByDefault && collapsedIndex !== -1)) {
@ -609,18 +605,16 @@ import LineTImage from '../images/line-t.png';
// Check if we should hide the whole panel
let panelProject = $panel.find('.change_project').text()
.toLowerCase()
.toLowerCase()
let panelPipeline = $changeBox
.parents('.zuul-pipeline')
.find('.zuul-pipeline-header > h3')
.html()
.toLowerCase()
let showPanel = true
.parents('.zuul-pipeline')
.find('.zuul-pipeline-header > h3')
.html()
.toLowerCase()
if (currentFilter !== '') {
showPanel = false
let showPanel = false
let filter = currentFilter.trim().split(/[\s,]+/)
$.each(filter, function (index, filterVal) {
if (filterVal !== '') {
@ -632,15 +626,14 @@ import LineTImage from '../images/line-t.png';
}
}
})
}
if (showPanel === true) {
$changeBox.show(animate)
if (showPanel === true) {
$changeBox.show(animate)
} else {
$changeBox.hide(animate)
}
} else {
$changeBox.hide(animate)
$changeBox.show(animate)
}
return showPanel
}
}
@ -664,12 +657,12 @@ import LineTImage from '../images/line-t.png';
injest: function (data, $msg) {
if ('message' in data) {
$msg.removeClass('alert-danger')
.addClass('alert-info')
.text(data.message)
.show()
.addClass('alert-info')
.text(data.message)
.show()
} else {
$msg.empty()
.hide()
.hide()
}
if ('zuul_version' in data) {
@ -679,7 +672,7 @@ import LineTImage from '../images/line-t.png';
let lastReconfigured =
new Date(data.last_reconfigured)
$('#last-reconfigured-span').text(
lastReconfigured.toString())
lastReconfigured.toString())
}
let $pipelines = $(options.pipelines_id)
@ -687,17 +680,17 @@ import LineTImage from '../images/line-t.png';
$.each(data.pipelines, function (i, pipeline) {
let count = app.create_tree(pipeline)
$pipelines.append(
format.pipeline(pipeline, count))
format.pipeline(pipeline, count))
})
$(options.queue_events_num).text(
data.trigger_event_queue
? data.trigger_event_queue.length : '0'
)
data.trigger_event_queue
? data.trigger_event_queue.length : '0'
)
$(options.queue_results_num).text(
data.result_event_queue
? data.result_event_queue.length : '0'
)
data.result_event_queue
? data.result_event_queue.length : '0'
)
},
/** @return {jQuery.Promise} */
update: function () {
@ -715,22 +708,22 @@ import LineTImage from '../images/line-t.png';
return
}
xhr = $.getJSON(options.source)
.done(function (data) {
app.injest(data, $msg)
})
.fail(function (jqXHR, statusText, errMsg) {
if (statusText === 'abort') {
return
}
$msg.text(options.source + ': ' + errMsg)
.addClass('alert-danger')
.removeClass('zuul-msg-wrap-off')
.show()
})
.always(function () {
xhr = undefined
app.emit('update-end')
})
.done(function (data) {
app.injest(data, $msg)
})
.fail(function (jqXHR, statusText, errMsg) {
if (statusText === 'abort') {
return
}
$msg.text(options.source + ': ' + errMsg)
.addClass('alert-danger')
.removeClass('zuul-msg-wrap-off')
.show()
})
.always(function () {
xhr = undefined
app.emit('update-end')
})
return xhr
},
@ -763,13 +756,13 @@ import LineTImage from '../images/line-t.png';
// Build the filter form filling anything from cookies
let $controlForm = $('<form />')
.attr('role', 'form')
.addClass('form-inline')
.submit(this.handleFilterChange)
.attr('role', 'form')
.addClass('form-inline')
.submit(this.handleFilterChange)
$controlForm
.append(this.filterFormGroup())
.append(this.expandFormGroup())
.append(this.filterFormGroup())
.append(this.expandFormGroup())
return $controlForm
},
@ -778,28 +771,28 @@ import LineTImage from '../images/line-t.png';
// Update the filter form with a clear button if required
let $label = $('<label />')
.addClass('control-label')
.attr('for', 'filter_string')
.text('Filters')
.css('padding-right', '0.5em')
.addClass('control-label')
.attr('for', 'filter_string')
.text('Filters')
.css('padding-right', '0.5em')
let $input = $('<input />')
.attr('type', 'text')
.attr('id', 'filter_string')
.addClass('form-control')
.attr('title',
'project(s), pipeline(s) or review(s) comma ' +
.attr('type', 'text')
.attr('id', 'filter_string')
.addClass('form-control')
.attr('title',
'project(s), pipeline(s) or review(s) comma ' +
'separated')
.attr('value', currentFilter)
.attr('value', currentFilter)
$input.change(this.handleFilterChange)
let $clearIcon = $('<span />')
.addClass('form-control-feedback')
.addClass('glyphicon glyphicon-remove-circle')
.attr('id', 'filter_form_clear_box')
.attr('title', 'clear filter')
.css('cursor', 'pointer')
.addClass('form-control-feedback')
.addClass('glyphicon glyphicon-remove-circle')
.attr('id', 'filter_form_clear_box')
.attr('title', 'clear filter')
.css('cursor', 'pointer')
$clearIcon.click(function () {
$('#filter_string').val('').change()
@ -810,29 +803,29 @@ import LineTImage from '../images/line-t.png';
}
let $formGroup = $('<div />')
.addClass('form-group has-feedback')
.append($label, $input, $clearIcon)
.addClass('form-group has-feedback')
.append($label, $input, $clearIcon)
return $formGroup
},
expandFormGroup: function () {
let expandByDefault = (
readCookie('zuul_expand_by_default', false) === 'true')
readCookie('zuul_expand_by_default', false) === 'true')
let $checkbox = $('<input />')
.attr('type', 'checkbox')
.attr('id', 'expand_by_default')
.prop('checked', expandByDefault)
.change(this.handleExpandByDefault)
.attr('type', 'checkbox')
.attr('id', 'expand_by_default')
.prop('checked', expandByDefault)
.change(this.handleExpandByDefault)
let $label = $('<label />')
.css('padding-left', '1em')
.html('Expand by default: ')
.append($checkbox)
.css('padding-left', '1em')
.html('Expand by default: ')
.append($checkbox)
let $formGroup = $('<div />')
.addClass('checkbox')
.append($label)
.addClass('checkbox')
.append($label)
return $formGroup
},
@ -846,7 +839,10 @@ import LineTImage from '../images/line-t.png';
$('#filter_form_clear_box').show()
}
this.update()
$('.zuul-change-box').each(function (index, obj) {
let $changeBox = $(obj)
format.display_patchset($changeBox, 200)
})
return false
},
@ -864,59 +860,59 @@ import LineTImage from '../images/line-t.png';
let count = 0
let pipelineMaxTreeColumns = 1
$.each(pipeline.change_queues,
function (changeQueueIndex, changeQueue) {
let tree = []
let maxTreeColumns = 1
let changes = []
let lastTreeLength = 0
$.each(changeQueue.heads, function (headIndex, head) {
$.each(head, function (changeIndex, change) {
changes[change.id] = change
change._tree_position = changeIndex
})
})
$.each(changeQueue.heads, function (headIndex, head) {
$.each(head, function (changeIndex, change) {
if (change.live === true) {
count += 1
}
let idx = tree.indexOf(change.id)
if (idx > -1) {
change._tree_index = idx
// remove...
tree[idx] = null
while (tree[tree.length - 1] === null) {
tree.pop()
}
} else {
change._tree_index = 0
}
change._tree_branches = []
change._tree = []
if (typeof (change.items_behind) === 'undefined') {
change.items_behind = []
}
change.items_behind.sort(function (a, b) {
return (changes[b]._tree_position - changes[a]._tree_position)
function (changeQueueIndex, changeQueue) {
let tree = []
let maxTreeColumns = 1
let changes = []
let lastTreeLength = 0
$.each(changeQueue.heads, function (headIndex, head) {
$.each(head, function (changeIndex, change) {
changes[change.id] = change
change._tree_position = changeIndex
})
})
$.each(changeQueue.heads, function (headIndex, head) {
$.each(head, function (changeIndex, change) {
if (change.live === true) {
count += 1
}
let idx = tree.indexOf(change.id)
if (idx > -1) {
change._tree_index = idx
// remove...
tree[idx] = null
while (tree[tree.length - 1] === null) {
tree.pop()
}
} else {
change._tree_index = 0
}
change._tree_branches = []
change._tree = []
if (typeof (change.items_behind) === 'undefined') {
change.items_behind = []
}
change.items_behind.sort(function (a, b) {
return (changes[b]._tree_position - changes[a]._tree_position)
})
$.each(change.items_behind, function (i, id) {
tree.push(id)
if (tree.length > lastTreeLength && lastTreeLength > 0) {
change._tree_branches.push(tree.length - 1)
}
})
if (tree.length > maxTreeColumns) {
maxTreeColumns = tree.length
}
if (tree.length > pipelineMaxTreeColumns) {
pipelineMaxTreeColumns = tree.length
}
change._tree = tree.slice(0) // make a copy
lastTreeLength = tree.length
})
})
changeQueue._tree_columns = maxTreeColumns
})
$.each(change.items_behind, function (i, id) {
tree.push(id)
if (tree.length > lastTreeLength && lastTreeLength > 0) {
change._tree_branches.push(tree.length - 1)
}
})
if (tree.length > maxTreeColumns) {
maxTreeColumns = tree.length
}
if (tree.length > pipelineMaxTreeColumns) {
pipelineMaxTreeColumns = tree.length
}
change._tree = tree.slice(0) // make a copy
lastTreeLength = tree.length
})
})
changeQueue._tree_columns = maxTreeColumns
})
pipeline._tree_columns = pipelineMaxTreeColumns
return count
}

View File

@ -1,6 +1,9 @@
// Main dashboard component
// Main library entrypoint
//
// Copyright 2018 Red Hat, Inc
// @licstart The following is the entire license notice for the
// JavaScript code in this page.
//
// Copyright 2018 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
@ -13,16 +16,10 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
// @licend The above is the entire license notice
// for the JavaScript code in this page.
import { Component } from '@angular/core'
@Component({
selector: 'zuul-dashboard',
template: `
<navigation></navigation>
<div class="container-fluid">
<router-outlet></router-outlet>
</div>
`
})
export class AppComponent {}
import './status'
import './stream'
import './dashboard'

View File

@ -1,22 +0,0 @@
// Copyright 2018 Red Hat, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import 'zone.js'
import 'reflect-metadata'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { AppModule } from './app.module'
platformBrowserDynamic().bootstrapModule(AppModule)

View File

@ -1,18 +0,0 @@
// Copyright 2018 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
export default class RouteDescription {
title: string
url: string[]
}

View File

@ -1,29 +0,0 @@
<!--
Copyright 2017 Red Hat
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" [routerLink]="zuul.getBaseHref()" target="_self">Zuul Dashboard</a>
</div>
<ul class="nav navbar-nav" *ngIf="showNavbar">
<li routerLinkActive="active" *ngFor="let route of navbarRoutes">
<a [routerLink]="route.url">
{{ route.title }}
</a>
</li>
</ul>
</div>
</nav>

View File

@ -1,75 +0,0 @@
// Copyright 2018 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import { OnInit, Component } from '@angular/core'
import { Router, ResolveEnd } from '@angular/router'
import { Observable } from 'rxjs/Observable'
import { filter } from 'rxjs/operators'
import ZuulService from '../zuul/zuul.service'
import RouteDescription from './description'
@Component({
selector: 'navigation',
template: require('./navigation.component.html')
})
export default class NavigationComponent implements OnInit {
navbarRoutes: RouteDescription[]
resolveEnd$: Observable<ResolveEnd>
showNavbar = true
private routePages = ['status', 'jobs', 'builds']
constructor(private router: Router, private zuul: ZuulService) {}
ngOnInit() {
this.resolveEnd$ = this.router.events.pipe(
filter(evt => evt instanceof ResolveEnd)
) as Observable<ResolveEnd>
this.resolveEnd$.subscribe(evt => {
this.showNavbar = (evt.url !== '/tenants.html')
this.navbarRoutes = this.getNavbarRoutes(evt.url)
})
}
getNavbarRoutes(url: string): RouteDescription[] {
const routes = []
for (const routePage of this.routePages) {
const description: RouteDescription = {
title: this.getRouteTitle(routePage),
url: this.getRouterLink(routePage, url)
}
routes.push(description)
}
return routes
}
getRouteTitle(target: string): string {
return target.charAt(0).toUpperCase() + target.slice(1)
}
getRouterLink(target: string, url: string): string[] {
const htmlTarget = target + '.html'
// NOTE: This won't work if there is a tenant name with a / in it. It would
// be great to pull the tenant name from the paramMap- but so far I can't
// find a way to get to the current paramMap of the current component from
// inside of this component.
if (url.startsWith('/t/')) {
return ['/t', url.split('/')[2], htmlTarget]
} else {
return ['/' + htmlTarget]
}
}
}

View File

@ -1,6 +1,9 @@
/* global URL, DemoStatusBasic, DemoStatusOpenStack, DemoStatusTree, BuiltinConfig */
/* global jQuery, URL, DemoStatusBasic, DemoStatusOpenStack, DemoStatusTree, BuiltinConfig */
// Client script for Zuul status page
//
// @licstart The following is the entire license notice for the
// JavaScript code in this page.
//
// Copyright 2013 OpenStack Foundation
// Copyright 2013 Timo Tijhof
// Copyright 2013 Wikimedia Foundation
@ -17,16 +20,23 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
// @licend The above is the entire license notice
// for the JavaScript code in this page.
import 'bootstrap/dist/css/bootstrap.css'
import 'jquery-visibility/jquery-visibility'
import 'graphitejs/jquery.graphite.js'
import angular from 'angular'
import './styles/zuul.css'
import './jquery.zuul'
import { getSourceUrl } from './util'
/**
* @return The $.zuul instance
*/
function zuulStart ($, tenant, zuulService) {
function zuulStart ($, $location) {
// Start the zuul app (expects default dom)
let $container, $indicator
@ -50,7 +60,7 @@ function zuulStart ($, tenant, zuulService) {
params['source_data'] = DemoStatusTree
}
} else {
params['source'] = zuulService.getSourceUrl('status', tenant)
params['source'] = getSourceUrl('status', $location)
}
let zuul = $.zuul(params)
@ -99,4 +109,25 @@ function zuulStart ($, tenant, zuulService) {
return zuul
}
export default zuulStart
if (module.hot) {
// This doesn't fully work with our jquery plugin because $.zuul is already
// instantiated. Leaving it here to show where a hook can happen if we can
// figure out a way to live update it. When it's not there, an update to
// jquery.zuul.js triggers a page reload.
// module.hot.accept('./jquery.zuul', function() {
// console.log('Accepting the updated module!');
// })
}
angular.module('zuulStatus', [], function ($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false,
rewriteLinks: false
})
$locationProvider.hashPrefix('')
}).controller(
'mainController', function ($location) {
zuulStart(jQuery, $location)
}
)

View File

@ -1,32 +0,0 @@
<!--
Copyright 2017 Red Hat
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<div class="container">
<div class="zuul-container" id="zuul-container">
<div style="display: none;" class="alert" id="zuul_msg"></div>
<button class="btn pull-right zuul-spinner">
updating <span class="glyphicon glyphicon-refresh"></span>
</button>
<p>Queue lengths:
<span id="zuul_queue_events_num">0</span> events,
<span id="zuul_queue_management_events_num">0</span> management events,
<span id="zuul_queue_results_num">0</span> results.
</p>
<div id="zuul_controls"></div>
<div id="zuul_pipelines" class="row"></div>
<p>Zuul version: <span id="zuul-version-span"></span></p>
<p>Last reconfigured: <span id="last-reconfigured-span"></span></p>
</div>
</div>

View File

@ -1,50 +0,0 @@
// Copyright 2018 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import { Component, OnInit, OnDestroy } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import ZuulService from '../zuul/zuul.service'
import zuulStart from './zuulStart'
interface ZuulStatusOption {
enabled: boolean
}
interface ZuulStatus {
options: ZuulStatusOption
}
@Component({
template: require('./status.component.html')
})
export default class StatusComponent implements OnInit, OnDestroy {
tenant: string
app: ZuulStatus
constructor(private route: ActivatedRoute, private zuul: ZuulService) {}
ngOnInit() {
if (this.app) {
this.app.options.enabled = true
} else {
this.app = zuulStart(
jQuery, this.route.snapshot.paramMap.get('tenant'), this.zuul)
}
}
ngOnDestroy() {
this.app.options.enabled = false
}
}

View File

@ -1,6 +1,9 @@
/* global URL, WebSocket, BuiltinConfig */
// Client script for Zuul Log Streaming
//
// @licstart The following is the entire license notice for the
// JavaScript code in this page.
//
// Copyright 2017 BMW Car IT GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,6 +17,14 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
// @licend The above is the entire license notice for the JavaScript code in
// this page.
import angular from 'angular'
import './styles/stream.css'
import { getSourceUrl } from './util'
function escapeLog (text) {
const pattern = /[<>&"']/g
@ -23,7 +34,7 @@ function escapeLog (text) {
})
}
function zuulStartStream (tenant, zuulService) {
function zuulStartStream ($location) {
let pageUpdateInMS = 250
let receiveBuffer = ''
@ -54,8 +65,16 @@ function zuulStartStream (tenant, zuulService) {
} else if (url.searchParams.has('websocket_url')) {
params['websocket_url'] = url.searchParams.get('websocket_url')
} else {
params['websocket_url'] = zuulService.getWebsocketUrl(
'console-stream', tenant)
// Websocket doesn't accept relative urls so construct an
// absolute one.
let protocol = ''
if (url['protocol'] === 'https:') {
protocol = 'wss://'
} else {
protocol = 'ws://'
}
let path = getSourceUrl('console-stream', $location)
params['websocket_url'] = protocol + url['host'] + path
}
let ws = new WebSocket(params['websocket_url'])
@ -75,4 +94,8 @@ function zuulStartStream (tenant, zuulService) {
}
}
export default zuulStartStream
angular.module('zuulStream', []).controller(
'mainController', function ($scope, $http, $location) {
window.onload = zuulStartStream($location)
}
)

View File

@ -1,24 +0,0 @@
<!--
Copyright 2017 BMW Car IT GmbH
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<div class="container-fluid">
<span id="zuulstreamoverlay">
<form>
<input type="checkbox" id="autoscroll" checked> autoscroll
</form>
</span>
</div>
<pre id="zuulstreamcontent"></pre>

View File

@ -1,32 +0,0 @@
// Copyright 2018 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import { Component, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import ZuulService from '../zuul/zuul.service'
import zuulStartStream from './zuulStartStream'
@Component({
styles: [require('./stream.component.css').toString()],
template: require('./stream.component.html')
})
export default class StreamComponent implements OnInit {
constructor(private route: ActivatedRoute, private zuul: ZuulService) {}
ngOnInit() {
zuulStartStream(this.route.snapshot.paramMap.get('tenant'), this.zuul)
}
}

View File

@ -1,15 +1,18 @@
body#zuulstream {
font-family: monospace;
background-color: black;
color: lightgrey;
}
#zuulstreamoverlay {
float: right;
position: fixed;
top: 5px;
right: 5px;
background-color: white;
padding: 2px;
background-color: darkgrey;
color: black;
}
pre#zuulstreamcontent {
font-family: monospace;
white-space: pre;
margin: 0px 10px;
background-color: black;

View File

@ -1,5 +1,3 @@
@import url('~bootstrap/dist/css/bootstrap.css');
.zuul-change {
margin-bottom: 10px;
}
@ -58,7 +56,3 @@
font-size: small;
padding: 8px 12px;
}
.form-inline > .form-group {
padding-right: 5px;
}

74
web/templates/builds.ejs Normal file
View File

@ -0,0 +1,74 @@
<!DOCTYPE html>
<!--
Copyright 2017 Red Hat
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title id='pagetitle'><%= htmlWebpackPlugin.options.title %></title>
</head>
<body ng-app="zuulBuilds" ng-controller="mainController"><div class="container-fluid">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="../../" target="_self">Zuul Dashboard</a>
</div>
<ul class="nav navbar-nav">
<li><a href="status.html" target="_self">Status</a></li>
<li><a href="jobs.html" target="_self">Jobs</a></li>
<li class="active"><a href="builds.html" target="_self">Builds</a></li>
</ul>
<span style="float: right; margin-top: 7px;">
<form ng-submit="builds_fetch()">
<label>Pipeline:</label>
<input name="pipeline" ng-model="pipeline" />
<label>Job:</label>
<input name="job_name" ng-model="job_name" />
<label>Project:</label>
<input name="project" ng-model="project" />
<input type="submit" value="Refresh" />
</form>
</span>
</div>
</nav>
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Job</th>
<th>Project</th>
<th>Branch</th>
<th>Pipeline</th>
<th>Change</th>
<th>Duration</th>
<th>Log url</th>
<th>Start time</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="build in builds" ng-class="rowClass(build)">
<td>{{ build.job_name }}</td>
<td>{{ build.project }}</td>
<td>{{ build.branch }}</td>
<td>{{ build.pipeline }}</td>
<td><a href="{{ build.ref_url }}" target="_self">change</a></td>
<td>{{ build.duration }} seconds</td>
<td><a ng-if="build.log_url" href="{{ build.log_url }}" target="_self">logs</a></td>
<td>{{ build.start_time }}</td>
<td>{{ build.result }}</td>
</tr>
</tbody>
</table>
</div></body></html>

51
web/templates/jobs.ejs Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<!--
Copyright 2017 Red Hat
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title id='pagetitle'><%= htmlWebpackPlugin.options.title %></title>
</head>
<body ng-app="zuulJobs" ng-controller="mainController"><div class="container-fluid">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="../../" target="_self">Zuul Dashboard</a>
</div>
<ul class="nav navbar-nav">
<li><a href="status.html" target="_self">Status</a></li>
<li class="active"><a href="jobs.html" target="_self">Jobs</a></li>
<li><a href="builds.html" target="_self">Builds</a></li>
</ul>
</div>
</nav>
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Last builds</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="job in jobs">
<td>{{ job.name }}</td>
<td>{{ job.description }}</td>
<td><a href="builds.html?job_name={{ job.name }}">builds</a></td>
</tr>
</tbody>
</table>
</div></body></html>

52
web/templates/status.ejs Normal file
View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<!--
Copyright 2017 Red Hat
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title id='pagetitle'><%= htmlWebpackPlugin.options.title %></title>
</head>
<body ng-app="zuulStatus" ng-controller="mainController">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="../../" target="_self">Zuul Dashboard</a>
</div>
<ul class="nav navbar-nav">
<li class="active"><a href="status.html" target="_self">Status</a></li>
<li><a href="jobs.html" target="_self">Jobs</a></li>
<li><a href="builds.html" target="_self">Builds</a></li>
</ul>
</div>
</nav>
<div class="container">
<div class="zuul-container" id="zuul-container">
<div style="display: none;" class="alert" id="zuul_msg"></div>
<button class="btn pull-right zuul-spinner">
updating <span class="glyphicon glyphicon-refresh"></span>
</button>
<p>Queue lengths:
<span id="zuul_queue_events_num">0</span> events,
<span id="zuul_queue_management_events_num">0</span> management events,
<span id="zuul_queue_results_num">0</span> results.
</p>
<div id="zuul_controls"></div>
<div id="zuul_pipelines" class="row"></div>
<p>Zuul version: <span id="zuul-version-span"></span></p>
<p>Last reconfigured: <span id="last-reconfigured-span"></span></p>
</div>
</div>
</body></html>

17
web/templates/stream.ejs Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title id='pagetitle'><%= htmlWebpackPlugin.options.title %></title>
</head>
<body ng-app="zuulStream" ng-controller="mainController" id="zuulstream">
<div id="zuulstreamoverlay">
<form>
<input type="checkbox" id="autoscroll" checked> autoscroll
</form>
</div>
<pre id="zuulstreamcontent"></pre>
</div></body>
</html>

View File

@ -1,3 +1,4 @@
<!DOCTYPE html>
<!--
Copyright 2017 Red Hat
@ -13,8 +14,22 @@ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<div class="container-fluid">
<!-- TODO(mordred) Make navigation smarter to handle tenants list -->
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title id='pagetitle'><%= htmlWebpackPlugin.options.title %></title>
</head>
<body ng-app="zuulTenants" ng-controller="mainController"><div class="container-fluid">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand">Zuul Dashboard</a>
</div>
<ul class="nav navbar-nav">
<li class="active"><a href=".">Tenants</a></li>
</ul>
</div>
</nav>
<table class="table table-hover table-condensed">
<thead>
<tr>
@ -27,14 +42,14 @@ under the License.
</tr>
</thead>
<tbody>
<tr *ngFor="let tenant of tenants">
<tr ng-repeat="tenant in tenants">
<td>{{ tenant.name }}</td>
<td><a [routerLink]="['/t', tenant.name, 'status.html']">status</a></td>
<td><a [routerLink]="['/t', tenant.name, 'jobs.html']">jobs</a></td>
<td><a [routerLink]="['/t', tenant.name, 'builds.html']">builds</a></td>
<td><a href="t/{{ tenant.name }}/status.html">status</a></td>
<td><a href="t/{{ tenant.name }}/jobs.html">jobs</a></td>
<td><a href="t/{{ tenant.name }}/builds.html">builds</a></td>
<td>{{ tenant.projects }}</td>
<td>{{ tenant.queue }}</td>
</tr>
</tbody>
</table>
</div>
</div></body></html>

View File

@ -1,18 +0,0 @@
// Copyright 2018 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
class Tenant {
name: string
projects: number
}

View File

@ -1,37 +0,0 @@
// Copyright 2017 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import { Component, OnInit } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import ZuulService from '../zuul/zuul.service'
@Component({
template: require('./tenants.component.html')
})
export default class TenantsComponent implements OnInit {
tenants: Tenant[]
constructor(private http: HttpClient, private zuul: ZuulService) {}
ngOnInit() {
this.tenantsFetch()
}
tenantsFetch(): void {
this.http.get<Tenant[]>(this.zuul.getSourceUrl('tenants'))
.subscribe(tenants => { this.tenants = tenants })
}
}

60
web/util.js Normal file
View File

@ -0,0 +1,60 @@
/* global URL, ZUUL_API_URL */
// @licstart The following is the entire license notice for the
// JavaScript code in this page.
//
// Copyright 2017 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
// @licend The above is the entire license notice
// for the JavaScript code in this page.
// TODO(mordred) This is a temporary hack until we're on @angular/router
function extractTenant (url) {
if (url.includes('/t/')) {
// This is a multi-tenant deploy, find the tenant
const tenantStart = url.lastIndexOf('/t/') + 3
const tenantEnd = url.indexOf('/', tenantStart)
return url.slice(tenantStart, tenantEnd)
} else {
return null
}
}
// TODO(mordred) This should be encapsulated in an Angular Service singleton
// that fetches the other things from the info endpoint.
export function getSourceUrl (filename, $location) {
if (typeof ZUUL_API_URL !== 'undefined') {
return `${ZUUL_API_URL}/api/${filename}`
} else {
const currentUrl = new URL(window.location)
const tenant = extractTenant(currentUrl.href)
const baseHref = getBaseHrefFromPath(currentUrl.pathname)
if (tenant) {
// Multi-tenant deploy. This is at t/a-tenant/x.html
return `${baseHref}api/tenant/${tenant}/${filename}`
} else {
// Whitelabel deploy or tenants list, such as /status.html, /tenants.html
// or /zuul/status.html or /zuul/tenants.html
return `${baseHref}api/${filename}`
}
}
}
function getBaseHrefFromPath (path) {
if (path.includes('/t/')) {
return path.slice(0, path.lastIndexOf('/t/') + 1)
} else {
return path.split('/').slice(0, -1).join('/') + '/'
}
}

View File

@ -1,31 +0,0 @@
// Copyright 2017 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
declare var ZUUL_BASE_HREF: string
export function getBaseHrefFromPath (path: string) {
if (path.includes('/t/')) {
return path.slice(0, path.lastIndexOf('/t/') + 1)
} else {
return path.split('/').slice(0, -1).join('/') + '/'
}
}
export function getBaseHref (): string {
if (typeof ZUUL_BASE_HREF !== 'undefined') {
return ZUUL_BASE_HREF
} else {
return getBaseHrefFromPath(window.location.pathname)
}
}

View File

@ -1,80 +0,0 @@
// Copyright 2017 Red Hat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import { Injectable } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { getBaseHrefFromPath } from '../util'
import * as url from 'url'
declare var ZUUL_API_URL: string
declare var ZUUL_BASE_HREF: string
@Injectable()
class ZuulService {
private baseHref: string
constructor() {
if (typeof ZUUL_API_URL !== 'undefined') {
this.baseHref = ZUUL_API_URL
} else {
this.baseHref = getBaseHrefFromPath(window.location.pathname)
}
if (this.baseHref.endsWith('/')) {
this.baseHref = this.baseHref.slice(0, 1)
}
}
getSourceUrl (filename: string, tenant?: string): string {
if (tenant) {
// Multi-tenant deploy. This is at t/a-tenant/x.html
return `${this.baseHref}/api/tenant/${tenant}/${filename}`
} else {
// Whitelabel deploy or tenants list, such as /status.html,
// /tenants.html or /zuul/status.html or /zuul/tenants.html
return `${this.baseHref}/api/${filename}`
}
}
getWebsocketUrl (filename: string, tenant?: string): string {
let apiBase: string
if (typeof ZUUL_API_URL !== 'undefined') {
apiBase = ZUUL_API_URL
} else {
apiBase = window.location.href
}
return url
.resolve(apiBase, this.getSourceUrl(filename, tenant))
.replace(/(http)(s)?\:\/\//, 'ws$2://')
}
getBaseHrefFromPath (path: string) {
if (path.includes('/t/')) {
return path.slice(0, path.lastIndexOf('/t/') + 1)
} else {
return path.split('/').slice(0, -1).join('/') + '/'
}
}
getBaseHref (): string {
if (typeof ZUUL_BASE_HREF !== 'undefined') {
return ZUUL_BASE_HREF
} else {
return this.getBaseHrefFromPath(window.location.pathname)
}
}
}
export default ZuulService

343
yarn.lock
View File

@ -2,48 +2,6 @@
# yarn lockfile v1
"@angular/common@^6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-6.0.3.tgz#8b2af3bb74add35c10cd969a5d179cb6a8b21545"
dependencies:
tslib "^1.9.0"
"@angular/compiler@^6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-6.0.3.tgz#47e988012e94f9e3477a4c5557c997d7910a3b2d"
dependencies:
tslib "^1.9.0"
"@angular/core@^6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-6.0.3.tgz#50502115105c3784d24338dd8ffb7dddcb55b58d"
dependencies:
tslib "^1.9.0"
"@angular/forms@^6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-6.0.3.tgz#57328c9ec0ddf4ae7823ec807315501813c22752"
dependencies:
tslib "^1.9.0"
"@angular/platform-browser-dynamic@^6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-6.0.3.tgz#b27e26c06df4ce34879cefd818e7ff394764f834"
dependencies:
tslib "^1.9.0"
"@angular/platform-browser@^6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-6.0.3.tgz#67941ac1dc0e89c1a18bb97ef17d574f469be6d2"
dependencies:
tslib "^1.9.0"
"@angular/router@^6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@angular/router/-/router-6.0.3.tgz#c2b63401c30788b78c90e4209cd06a653eae6428"
dependencies:
tslib "^1.9.0"
"@babel/code-frame@7.0.0-beta.42", "@babel/code-frame@^7.0.0-beta.40":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.42.tgz#a9c83233fa7cd06b39dc77adbb908616ff4f1962"
@ -124,33 +82,6 @@
version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
"@types/angular@^1.6.43":
version "1.6.43"
resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.6.43.tgz#6235ef416053a86302970717510a936d889cbb9a"
"@types/bootstrap@^4.0.0":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-4.0.1.tgz#7eddfc4e56143cfc54de0fba573d9724ec8b2712"
dependencies:
"@types/jquery" "*"
popper.js "^1.14.1"
"@types/core-js@^0.9.46":
version "0.9.46"
resolved "https://registry.yarnpkg.com/@types/core-js/-/core-js-0.9.46.tgz#ea701ee34cbb6dfe6d100f1530319547c93c8d79"
"@types/jquery@*", "@types/jquery@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.1.tgz#55758d44d422756d6329cbf54e6d41931d7ba28f"
"@types/node@*":
version "9.6.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.1.tgz#e2d374ef15b315b48e7efc308fa1a7cd51faa06c"
"@types/node@^9.4.7":
version "9.6.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.0.tgz#d3480ee666df9784b1001a1872a2f6ccefb6c2d7"
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@ -234,6 +165,10 @@ amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
angular@^1.5.8:
version "1.6.9"
resolved "https://registry.yarnpkg.com/angular/-/angular-1.6.9.tgz#bc812932e18909038412d594a5990f4bb66c0619"
ansi-escapes@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
@ -272,13 +207,6 @@ any-observable@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242"
anymatch@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
dependencies:
micromatch "^2.1.5"
normalize-path "^2.0.0"
anymatch@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@ -286,10 +214,6 @@ anymatch@^2.0.0:
micromatch "^3.1.4"
normalize-path "^2.1.1"
app-root-path@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46"
aproba@^1.0.3, aproba@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@ -433,10 +357,6 @@ ast-types@0.11.3:
version "0.11.3"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8"
ast-types@0.9.6:
version "0.9.6"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@ -1524,21 +1444,6 @@ check-types@^7.3.0:
version "7.3.0"
resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.3.0.tgz#468f571a4435c24248f5fd0cb0e8d87c3c341e7d"
chokidar@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
dependencies:
anymatch "^1.3.0"
async-each "^1.0.0"
glob-parent "^2.0.0"
inherits "^2.0.1"
is-binary-path "^1.0.0"
is-glob "^2.0.0"
path-is-absolute "^1.0.0"
readdirp "^2.0.0"
optionalDependencies:
fsevents "^1.0.0"
chokidar@^2.0.0, chokidar@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176"
@ -1700,17 +1605,6 @@ code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
codelyzer@^4.0.2, codelyzer@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-4.2.1.tgz#d56eaacefca7e8138aac0a630e484bdb09988544"
dependencies:
app-root-path "^2.0.1"
css-selector-tokenizer "^0.7.0"
cssauron "^1.4.0"
semver-dsl "^1.0.1"
source-map "^0.5.6"
sprintf-js "^1.0.3"
collection-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
@ -1768,7 +1662,7 @@ combined-stream@^1.0.5, combined-stream@~1.0.5:
dependencies:
delayed-stream "~1.0.0"
commander@2.15.x, commander@^2.12.1, commander@^2.13.0, commander@~2.15.0:
commander@2.15.x, commander@^2.13.0, commander@~2.15.0:
version "2.15.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
@ -1885,7 +1779,7 @@ copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0, core-js@^2.5.3:
core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0:
version "2.5.3"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e"
@ -2024,12 +1918,6 @@ css@^2.0.0:
source-map-resolve "^0.3.0"
urix "^0.1.0"
cssauron@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8"
dependencies:
through X.X.X
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
@ -2246,7 +2134,7 @@ detect-node@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127"
diff@^3.1.0, diff@^3.2.0, diff@^3.3.1, diff@^3.5.0:
diff@^3.3.1, diff@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
@ -2450,13 +2338,6 @@ es-to-primitive@^1.1.1:
is-date-object "^1.0.1"
is-symbol "^1.0.1"
es6-templates@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/es6-templates/-/es6-templates-0.2.3.tgz#5cb9ac9fb1ded6eb1239342b81d792bbb4078ee4"
dependencies:
recast "~0.11.12"
through "~2.3.6"
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@ -2594,10 +2475,6 @@ esprima@^4.0.0, esprima@~4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
esprima@~3.1.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
esquery@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa"
@ -2947,22 +2824,6 @@ forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
fork-ts-checker-webpack-plugin@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-0.4.1.tgz#718801621c50c7f20de9c8e6a68a2db228a4081f"
dependencies:
babel-code-frame "^6.22.0"
chalk "^1.1.3"
chokidar "^1.7.0"
lodash.endswith "^4.2.1"
lodash.isfunction "^3.0.8"
lodash.isstring "^4.0.1"
lodash.startswith "^4.2.1"
minimatch "^3.0.4"
resolve "^1.5.0"
tapable "^1.0.0"
vue-parser "^1.1.5"
form-data@~2.1.1:
version "2.1.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
@ -3005,7 +2866,7 @@ fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
fsevents@^1.0.0, fsevents@^1.1.2:
fsevents@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8"
dependencies:
@ -3112,7 +2973,7 @@ glob-parent@^3.1.0:
is-glob "^3.1.0"
path-dirname "^1.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2:
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
@ -3391,17 +3252,7 @@ html-entities@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
html-loader@^0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-0.5.5.tgz#6356dbeb0c49756d8ebd5ca327f16ff06ab5faea"
dependencies:
es6-templates "^0.2.3"
fastparse "^1.1.1"
html-minifier "^3.5.8"
loader-utils "^1.1.0"
object-assign "^4.1.1"
html-minifier@^3.2.3, html-minifier@^3.5.8:
html-minifier@^3.2.3:
version "3.5.12"
resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.12.tgz#6bfad4d0327f5b8d2b62f5854654ac3703b9b031"
dependencies:
@ -3943,7 +3794,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
js-yaml@^3.7.0, js-yaml@^3.9.1:
js-yaml@^3.9.1:
version "3.11.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef"
dependencies:
@ -4282,10 +4133,6 @@ lodash.defaults@^4.0.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
lodash.endswith@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/lodash.endswith/-/lodash.endswith-4.2.1.tgz#fed59ac1738ed3e236edd7064ec456448b37bc09"
lodash.isarguments@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
@ -4294,14 +4141,6 @@ lodash.isarray@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
lodash.isfunction@^3.0.8:
version "3.0.9"
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
lodash.keys@^3.0.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
@ -4318,10 +4157,6 @@ lodash.restparam@^3.0.0:
version "3.6.1"
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
lodash.startswith@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/lodash.startswith/-/lodash.startswith-4.2.1.tgz#c598c4adce188a27e53145731cdc6c0e7177600c"
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
@ -4399,10 +4234,6 @@ make-dir@^1.0.0, make-dir@^1.1.0:
dependencies:
pify "^3.0.0"
make-error@^1.1.1:
version "1.3.4"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.4.tgz#19978ed575f9e9545d2ff8c13e33b5d18a67d535"
map-cache@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
@ -4491,7 +4322,7 @@ methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7:
micromatch@^2.3.11, micromatch@^2.3.7:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
dependencies:
@ -5100,12 +4931,6 @@ parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
parse5@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
dependencies:
"@types/node" "*"
parseurl@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
@ -5220,10 +5045,6 @@ pluralize@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
popper.js@^1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.1.tgz#b8815e5cda6f62fc2042e47618649f75866e6753"
portfinder@^1.0.9:
version "1.0.13"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
@ -5767,15 +5588,6 @@ recast@^0.14.1:
private "~0.1.5"
source-map "~0.6.1"
recast@~0.11.12:
version "0.11.23"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
dependencies:
ast-types "0.9.6"
esprima "~3.1.0"
private "~0.1.5"
source-map "~0.5.0"
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
@ -5803,10 +5615,6 @@ reduce-function-call@^1.0.1:
dependencies:
balanced-match "^0.4.2"
reflect-metadata@^0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2"
regenerate@^1.2.1:
version "1.3.3"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f"
@ -5995,7 +5803,7 @@ resolve-url@^0.2.1, resolve-url@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
resolve@^1.1.6, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.5.0:
resolve@^1.1.6, resolve@^1.3.3, resolve@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.6.0.tgz#0fbd21278b27b4004481c395349e7aba60a9ff5c"
dependencies:
@ -6036,7 +5844,7 @@ rework@^1.0.1:
convert-source-map "^0.3.3"
css "^2.0.0"
rimraf@2, rimraf@^2.2.8, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
@ -6075,22 +5883,12 @@ rx-lite@*, rx-lite@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
rxjs-compat@^6.0.0-rc.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/rxjs-compat/-/rxjs-compat-6.2.0.tgz#2eb49cc6ac20d0d7057c6887d1895beaab0966f9"
rxjs@^5.4.2, rxjs@^5.5.2:
version "5.5.7"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.7.tgz#afb3d1642b069b2fbf203903d6501d1acb4cda27"
dependencies:
symbol-observable "1.0.1"
rxjs@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.0.tgz#e024d0e180b72756a83c2aaea8f25423751ba978"
dependencies:
tslib "^1.9.0"
safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
@ -6126,13 +5924,7 @@ selfsigned@^1.9.1:
dependencies:
node-forge "0.7.1"
semver-dsl@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/semver-dsl/-/semver-dsl-1.0.1.tgz#d3678de5555e8a61f629eed025366ae5f27340a0"
dependencies:
semver "^5.3.0"
"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0:
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
@ -6360,12 +6152,6 @@ source-map-support@^0.4.15:
dependencies:
source-map "^0.5.6"
source-map-support@^0.5.3:
version "0.5.4"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.4.tgz#54456efa89caa9270af7cd624cc2f123e51fbae8"
dependencies:
source-map "^0.6.0"
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@ -6374,7 +6160,7 @@ source-map-url@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9"
source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0:
source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@ -6384,7 +6170,7 @@ source-map@^0.1.38:
dependencies:
amdefine ">=0.0.4"
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
source-map@^0.6.1, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
@ -6439,10 +6225,6 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies:
extend-shallow "^3.0.0"
sprintf-js@^1.0.3:
version "1.1.1"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
@ -6712,7 +6494,7 @@ through2@^2.0.0:
readable-stream "^2.1.5"
xtend "~4.0.1"
through@X.X.X, through@^2.3.6, through@~2.3.6:
through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@ -6792,77 +6574,6 @@ tryer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.0.tgz#027b69fa823225e551cace3ef03b11f6ab37c1d7"
ts-loader@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-4.1.0.tgz#6216e75600941df3270bc4a7125e20aefb2dc5ea"
dependencies:
chalk "^2.3.0"
enhanced-resolve "^4.0.0"
loader-utils "^1.0.2"
micromatch "^3.1.4"
semver "^5.0.1"
ts-node@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-5.0.1.tgz#78e5d1cb3f704de1b641e43b76be2d4094f06f81"
dependencies:
arrify "^1.0.0"
chalk "^2.3.0"
diff "^3.1.0"
make-error "^1.1.1"
minimist "^1.2.0"
mkdirp "^0.5.1"
source-map-support "^0.5.3"
yn "^2.0.0"
tslib@^1.8.0, tslib@^1.8.1:
version "1.9.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
tslib@^1.9.0:
version "1.9.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.2.tgz#8be0cc9a1f6dc7727c38deb16c2ebd1a2892988e"
tslint-angular@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/tslint-angular/-/tslint-angular-1.1.1.tgz#ae4724ae9b31e34ccc068600a6ea710113a1a161"
dependencies:
codelyzer "^4.0.2"
tslint "^5.8.0"
tslint-loader@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/tslint-loader/-/tslint-loader-3.6.0.tgz#12ed4d5ef57d68be25cd12692fb2108b66469d76"
dependencies:
loader-utils "^1.0.2"
mkdirp "^0.5.1"
object-assign "^4.1.1"
rimraf "^2.4.4"
semver "^5.3.0"
tslint@^5.8.0, tslint@^5.9.1:
version "5.9.1"
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae"
dependencies:
babel-code-frame "^6.22.0"
builtin-modules "^1.1.1"
chalk "^2.3.0"
commander "^2.12.1"
diff "^3.2.0"
glob "^7.1.1"
js-yaml "^3.7.0"
minimatch "^3.0.4"
resolve "^1.3.2"
semver "^5.3.0"
tslib "^1.8.0"
tsutils "^2.12.1"
tsutils@^2.12.1:
version "2.22.2"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.22.2.tgz#0b9f3d87aa3eb95bd32d26ce2b88aa329a657951"
dependencies:
tslib "^1.8.1"
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@ -6894,10 +6605,6 @@ typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
typescript@2.7.2:
version "2.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836"
uglify-es@^3.3.4:
version "3.3.9"
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
@ -7145,12 +6852,6 @@ vm-browserify@0.0.4:
dependencies:
indexof "0.0.1"
vue-parser@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/vue-parser/-/vue-parser-1.1.6.tgz#3063c8431795664ebe429c23b5506899706e6355"
dependencies:
parse5 "^3.0.3"
walkdir@^0.0.11:
version "0.0.11"
resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.11.tgz#a16d025eb931bd03b52f308caed0f40fcebe9532"
@ -7513,10 +7214,6 @@ yeoman-generator@^2.0.3:
through2 "^2.0.0"
yeoman-environment "^2.0.5"
yn@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a"
zip-stream@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04"
@ -7525,7 +7222,3 @@ zip-stream@^1.1.0:
compress-commons "^1.2.0"
lodash "^4.8.0"
readable-stream "^2.0.0"
zone.js@^0.8.26:
version "0.8.26"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.26.tgz#7bdd72f7668c5a7ad6b118148b4ea39c59d08d2d"