Merge pull request #2846 from alecmerdler/QUAY-682
Optimize Webpack JS Bundle Size
This commit is contained in:
commit
ad61df66c5
28 changed files with 383 additions and 366 deletions
|
@ -20,12 +20,11 @@ RUN virtualenv --distribute venv \
|
|||
|
||||
# Install front-end dependencies
|
||||
# JS depedencies
|
||||
COPY yarn.lock ./
|
||||
COPY yarn.lock package.json tsconfig.json webpack.config.js tslint.json ./
|
||||
RUN yarn install --ignore-engines
|
||||
|
||||
# JS compile
|
||||
COPY static static
|
||||
COPY package.json tsconfig.json webpack.config.js tslint.json ./
|
||||
RUN yarn build \
|
||||
&& jpegoptim static/img/**/*.jpg \
|
||||
&& optipng -clobber -quiet static/img/**/*.png
|
||||
|
|
|
@ -24,6 +24,9 @@ from _init import __version__
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
JS_BUNDLE_NAME = 'bundle'
|
||||
|
||||
|
||||
def common_login(user_uuid, permanent_session=True):
|
||||
""" Performs login of the given user, with optional non-permanence on the session. """
|
||||
user = model.get_user(user_uuid)
|
||||
|
@ -56,10 +59,10 @@ def common_login(user_uuid, permanent_session=True):
|
|||
return False
|
||||
|
||||
|
||||
def _list_files(path, extension):
|
||||
def _list_files(path, extension, contains=""):
|
||||
""" Returns a list of all the files with the given extension found under the given path. """
|
||||
def matches(f):
|
||||
return os.path.splitext(f)[1] == '.' + extension and f.split(os.path.extsep)[1] != 'spec'
|
||||
return os.path.splitext(f)[1] == '.' + extension and contains in os.path.splitext(f)[0]
|
||||
|
||||
def join_path(dp, f):
|
||||
# Remove the static/ prefix. It is added in the template.
|
||||
|
@ -71,10 +74,7 @@ def _list_files(path, extension):
|
|||
|
||||
def render_page_template(name, route_data=None, **kwargs):
|
||||
""" Renders the page template with the given name as the response and returns its contents. """
|
||||
library_styles = []
|
||||
main_styles = []
|
||||
library_scripts = []
|
||||
main_scripts = _list_files('build', 'js')
|
||||
main_scripts = _list_files('build', 'js', JS_BUNDLE_NAME)
|
||||
|
||||
use_cdn = app.config.get('USE_CDN', True)
|
||||
if request.args.get('use_cdn') is not None:
|
||||
|
@ -118,10 +118,7 @@ def render_page_template(name, route_data=None, **kwargs):
|
|||
route_data=route_data,
|
||||
external_styles=external_styles,
|
||||
external_scripts=external_scripts,
|
||||
main_styles=main_styles,
|
||||
library_styles=library_styles,
|
||||
main_scripts=main_scripts,
|
||||
library_scripts=library_scripts,
|
||||
feature_set=features.get_features(),
|
||||
config_set=frontend_visible_config(app.config),
|
||||
oauth_set=get_oauth_config(),
|
||||
|
|
23
package.json
23
package.json
|
@ -4,13 +4,15 @@
|
|||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "./node_modules/.bin/karma start --browsers ChromeHeadless",
|
||||
"test": "./node_modules/.bin/karma start --single-run --browsers ChromeHeadless",
|
||||
"test:node": "JASMINE_CONFIG_PATH=static/test/jasmine.json ./node_modules/.bin/jasmine-ts './static/js/**/*.spec.ts'",
|
||||
"e2e": "./node_modules/.bin/ts-node ./node_modules/.bin/protractor static/test/protractor.conf.ts",
|
||||
"build": "NODE_ENV=production ./node_modules/.bin/webpack --progress",
|
||||
"watch": "./node_modules/.bin/webpack --watch",
|
||||
"lint": "./node_modules/.bin/tslint --type-check -p tsconfig.json -e **/*.spec.ts"
|
||||
"dev": "karma start --browsers ChromeHeadless",
|
||||
"test": "karma start --single-run --browsers ChromeHeadless",
|
||||
"test:node": "JASMINE_CONFIG_PATH=static/test/jasmine.json jasmine-ts './static/js/**/*.spec.ts'",
|
||||
"e2e": "ts-node ./node_modules/.bin/protractor static/test/protractor.conf.ts",
|
||||
"build": "npm run clean && NODE_ENV=production webpack --progress",
|
||||
"watch": "npm run clean && webpack --watch",
|
||||
"lint": "tslint --type-check -p tsconfig.json -e **/*.spec.ts",
|
||||
"analyze": "NODE_ENV=production webpack --profile --json | awk '{if(NR>1)print}' > static/build/stats.json && webpack-bundle-analyzer --mode static -r static/build/report.html static/build/stats.json",
|
||||
"clean": "rm -f static/build/*"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -32,13 +34,13 @@
|
|||
"d3": "^3.3.3",
|
||||
"eonasdan-bootstrap-datetimepicker": "^4.17.43",
|
||||
"file-saver": "^1.3.3",
|
||||
"highlight.js": "^9.12.0",
|
||||
"jquery": "1.12.4",
|
||||
"ng-metadata": "^4.0.1",
|
||||
"raven-js": "^3.1.0",
|
||||
"restangular": "^1.2.0",
|
||||
"rxjs": "^5.0.1",
|
||||
"showdown": "^1.6.4",
|
||||
"showdown-highlightjs-extension": "^0.1.2",
|
||||
"underscore": "^1.5.2",
|
||||
"urijs": "^1.18.10",
|
||||
"zeroclipboard": "^2.3.0"
|
||||
|
@ -51,8 +53,6 @@
|
|||
"@types/core-js": "^0.9.39",
|
||||
"@types/jasmine": "^2.5.41",
|
||||
"@types/jquery": "^2.0.40",
|
||||
"@types/react": "0.14.39",
|
||||
"@types/react-dom": "0.14.17",
|
||||
"@types/showdown": "^1.4.32",
|
||||
"angular-mocks": "1.6.2",
|
||||
"css-loader": "0.25.0",
|
||||
|
@ -75,6 +75,7 @@
|
|||
"ts-node": "^3.0.6",
|
||||
"tslint": "^5.4.3",
|
||||
"typescript": "^2.2.1",
|
||||
"webpack": "^2.2"
|
||||
"webpack": "^2.2",
|
||||
"webpack-bundle-analyzer": "^2.8.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -920,16 +920,6 @@ a:focus {
|
|||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.realtime-area-chart, .realtime-line-chart {
|
||||
margin: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rickshaw_graph {
|
||||
overflow: hidden;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.cor-container {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<div class="realtime-area-chart-element">
|
||||
<div ng-show="counter >= 1">
|
||||
<div class="chart"></div>
|
||||
</div>
|
||||
<div class="cor-loader-inline" ng-if="counter < 1"></div>
|
||||
</div>
|
|
@ -1,6 +0,0 @@
|
|||
<div class="realtime-line-chart-element">
|
||||
<div ng-show="counter >= 1">
|
||||
<div class="chart"></div>
|
||||
</div>
|
||||
<div class="cor-loader-inline" ng-if="counter < 1"></div>
|
||||
</div>
|
8
static/js/constants/highlighted-languages.constant.json
Normal file
8
static/js/constants/highlighted-languages.constant.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
[
|
||||
"javascript",
|
||||
"python",
|
||||
"bash",
|
||||
"nginx",
|
||||
"xml",
|
||||
"shell"
|
||||
]
|
|
@ -302,236 +302,6 @@ angular.module("core-ui", [])
|
|||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
.directive('realtimeAreaChart', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/realtime-area-chart.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'data': '=data',
|
||||
'labels': '=labels',
|
||||
'colors': '=colors',
|
||||
'counter': '=counter'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
var graph = null;
|
||||
var series = [];
|
||||
var palette = new Rickshaw.Color.Palette( { scheme: 'spectrum14' } );
|
||||
var colors = $scope.colors || [];
|
||||
|
||||
var setupGraph = function() {
|
||||
for (var i = 0; i < $scope.labels.length; ++i) {
|
||||
series.push({
|
||||
name: $scope.labels[i],
|
||||
color: i >= colors.length ? palette.color(): $scope.colors[i],
|
||||
stroke: 'rgba(0,0,0,0.15)',
|
||||
data: []
|
||||
});
|
||||
}
|
||||
|
||||
var options = {
|
||||
element: $element.find('.chart')[0],
|
||||
renderer: 'area',
|
||||
stroke: true,
|
||||
series: series,
|
||||
min: 0,
|
||||
padding: {
|
||||
'top': 0.3,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0.3
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.minimum != null) {
|
||||
options['min'] = $scope.minimum == 'auto' ? 'auto' : $scope.minimum * 1;
|
||||
} else {
|
||||
options['min'] = 0;
|
||||
}
|
||||
|
||||
if ($scope.maximum != null) {
|
||||
options['max'] = $scope.maximum == 'auto' ? 'auto' : $scope.maximum * 1;
|
||||
}
|
||||
|
||||
graph = new Rickshaw.Graph(options);
|
||||
|
||||
xaxes = new Rickshaw.Graph.Axis.Time({
|
||||
graph: graph,
|
||||
timeFixture: new Rickshaw.Fixtures.Time.Local()
|
||||
});
|
||||
|
||||
yaxes = new Rickshaw.Graph.Axis.Y({
|
||||
graph: graph,
|
||||
tickFormat: Rickshaw.Fixtures.Number.formatKMBT
|
||||
});
|
||||
|
||||
hoverDetail = new Rickshaw.Graph.HoverDetail({
|
||||
graph: graph,
|
||||
xFormatter: function(x) {
|
||||
return new Date(x * 1000).toString();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var refresh = function(data) {
|
||||
if (!data || $scope.counter < 0) { return; }
|
||||
if (!graph) {
|
||||
setupGraph();
|
||||
}
|
||||
|
||||
var timecode = new Date().getTime() / 1000;
|
||||
for (var i = 0; i < $scope.data.length; ++i) {
|
||||
var arr = series[i].data;
|
||||
arr.push(
|
||||
{'x': timecode, 'y': $scope.data[i] }
|
||||
);
|
||||
|
||||
if (arr.length > 10) {
|
||||
series[i].data = arr.slice(arr.length - 10, arr.length);
|
||||
}
|
||||
}
|
||||
|
||||
graph.renderer.unstack = true;
|
||||
graph.update();
|
||||
};
|
||||
|
||||
$scope.$watch('counter', function() {
|
||||
refresh($scope.data_raw);
|
||||
});
|
||||
|
||||
$scope.$watch('data', function(data) {
|
||||
$scope.data_raw = data;
|
||||
refresh($scope.data_raw);
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
|
||||
.directive('realtimeLineChart', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/realtime-line-chart.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'data': '=data',
|
||||
'labels': '=labels',
|
||||
'counter': '=counter',
|
||||
'labelTemplate': '@labelTemplate',
|
||||
'minimum': '@minimum',
|
||||
'maximum': '@maximum'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
var graph = null;
|
||||
var xaxes = null;
|
||||
var yaxes = null;
|
||||
var hoverDetail = null;
|
||||
var series = [];
|
||||
var counter = 0;
|
||||
var palette = new Rickshaw.Color.Palette( { scheme: 'spectrum14' } );
|
||||
|
||||
var setupGraph = function() {
|
||||
var options = {
|
||||
element: $element.find('.chart')[0],
|
||||
renderer: 'line',
|
||||
series: series,
|
||||
padding: {
|
||||
'top': 0.3,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0.3
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.minimum != null) {
|
||||
options['min'] = $scope.minimum == 'auto' ? 'auto' : $scope.minimum * 1;
|
||||
} else {
|
||||
options['min'] = 0;
|
||||
}
|
||||
|
||||
if ($scope.maximum != null) {
|
||||
options['max'] = $scope.maximum == 'auto' ? 'auto' : $scope.maximum * 1;
|
||||
}
|
||||
|
||||
graph = new Rickshaw.Graph(options);
|
||||
xaxes = new Rickshaw.Graph.Axis.Time({
|
||||
graph: graph,
|
||||
timeFixture: new Rickshaw.Fixtures.Time.Local()
|
||||
});
|
||||
|
||||
yaxes = new Rickshaw.Graph.Axis.Y({
|
||||
graph: graph,
|
||||
tickFormat: Rickshaw.Fixtures.Number.formatKMBT
|
||||
});
|
||||
|
||||
hoverDetail = new Rickshaw.Graph.HoverDetail({
|
||||
graph: graph,
|
||||
xFormatter: function(x) {
|
||||
return new Date(x * 1000).toString();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var refresh = function(data) {
|
||||
if (data == null) { return; }
|
||||
if (!graph) {
|
||||
setupGraph();
|
||||
}
|
||||
|
||||
if (typeof data == 'number') {
|
||||
data = [data];
|
||||
}
|
||||
|
||||
if ($scope.labels) {
|
||||
data = data.slice(0, $scope.labels.length);
|
||||
}
|
||||
|
||||
if (series.length == 0){
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
var title = $scope.labels ? $scope.labels[i] : $scope.labelTemplate.replace('{x}', i + 1);
|
||||
series.push({
|
||||
'color': palette.color(),
|
||||
'data': [],
|
||||
'name': title
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
counter++;
|
||||
var timecode = new Date().getTime() / 1000;
|
||||
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
var arr = series[i].data;
|
||||
arr.push({
|
||||
'x': timecode,
|
||||
'y': data[i]
|
||||
})
|
||||
|
||||
if (arr.length > 10) {
|
||||
series[i].data = arr.slice(arr.length - 10, arr.length);
|
||||
}
|
||||
}
|
||||
|
||||
graph.update();
|
||||
};
|
||||
|
||||
$scope.$watch('counter', function(counter) {
|
||||
refresh($scope.data_raw);
|
||||
});
|
||||
|
||||
$scope.$watch('data', function(data) {
|
||||
$scope.data_raw = data;
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
.directive('corProgressBar', function() {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 4,
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import { Inject } from './inject.decorator';
|
||||
|
||||
|
||||
describe("Decorator: Inject", () => {
|
||||
|
||||
describe("parameter injection", () => {
|
||||
|
||||
it("adds given string to the 'inject' property of the annotated class", () => {
|
||||
expect(ValidService.$inject).toContain('$scope');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
class ValidService {
|
||||
constructor(@Inject('$scope') private $scope: any) {}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Adds the given value to the inject property of the annotated class.
|
||||
* Used to annotate the constructor parameters of an AngularJS service/component class.
|
||||
* @param value The string name of the dependency.
|
||||
*/
|
||||
export function Inject(value: string) {
|
||||
return (target: any, propertyKey: string | symbol, parameterIndex: number): void => {
|
||||
target.$inject = target.$inject = [];
|
||||
target.$inject[parameterIndex] = value;
|
||||
};
|
||||
}
|
|
@ -8,15 +8,37 @@ describe("MarkdownEditorComponent", () => {
|
|||
var component: MarkdownEditorComponent;
|
||||
var textarea: Mock<ng.IAugmentedJQuery | any>;
|
||||
var documentMock: Mock<HTMLElement & Document>;
|
||||
var $windowMock: Mock<ng.IWindowService>;
|
||||
|
||||
beforeEach(() => {
|
||||
textarea = new Mock<ng.IAugmentedJQuery | any>();
|
||||
documentMock = new Mock<HTMLElement & Document>();
|
||||
$windowMock = new Mock<ng.IWindowService>();
|
||||
const $documentMock: any = [documentMock.Object];
|
||||
component = new MarkdownEditorComponent($documentMock, 'chrome');
|
||||
component = new MarkdownEditorComponent($documentMock, $windowMock.Object, 'chrome');
|
||||
component.textarea = textarea.Object;
|
||||
});
|
||||
|
||||
describe("onBeforeUnload", () => {
|
||||
|
||||
it("returns false to alert user about losing current changes", () => {
|
||||
component.changeEditMode("write");
|
||||
const allow: boolean = component.onBeforeUnload();
|
||||
|
||||
expect(allow).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ngOnDestroy", () => {
|
||||
|
||||
it("removes 'beforeunload' event listener", () => {
|
||||
$windowMock.setup(mock => mock.onbeforeunload).is(() => 1);
|
||||
component.ngOnDestroy();
|
||||
|
||||
expect($windowMock.Object.onbeforeunload.call(this)).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("changeEditMode", () => {
|
||||
|
||||
it("sets component's edit mode to given mode", () => {
|
||||
|
@ -135,7 +157,15 @@ describe("MarkdownEditorComponent", () => {
|
|||
|
||||
describe("discardChanges", () => {
|
||||
|
||||
it("emits output event with no content", (done) => {
|
||||
it("prompts user to confirm discarding changes", () => {
|
||||
const confirmSpy: Spy = $windowMock.setup(mock => mock.confirm).is((message) => false).Spy;
|
||||
component.discardChanges();
|
||||
|
||||
expect(confirmSpy.calls.argsFor(0)[0]).toEqual(`Are you sure you want to discard your changes?`);
|
||||
});
|
||||
|
||||
it("emits output event with no content if user confirms discarding changes", (done) => {
|
||||
$windowMock.setup(mock => mock.confirm).is((message) => true);
|
||||
component.discard.subscribe((event: {}) => {
|
||||
expect(event).toEqual({});
|
||||
done();
|
||||
|
@ -143,5 +173,16 @@ describe("MarkdownEditorComponent", () => {
|
|||
|
||||
component.discardChanges();
|
||||
});
|
||||
|
||||
it("does not emit output event if user declines confirmation of discarding changes", (done) => {
|
||||
$windowMock.setup(mock => mock.confirm).is((message) => false);
|
||||
component.discard.subscribe((event: {}) => {
|
||||
fail(`Should not emit output event`);
|
||||
done();
|
||||
});
|
||||
|
||||
component.discardChanges();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, Inject, Input, Output, EventEmitter, ViewChild } from 'ng-metadata/core';
|
||||
import { Component, Inject, Input, Output, EventEmitter, ViewChild, HostListener, OnDestroy } from 'ng-metadata/core';
|
||||
import { MarkdownSymbol } from '../../../types/common.types';
|
||||
import { BrowserPlatform } from '../../../constants/platform.constant';
|
||||
import './markdown-editor.component.css';
|
||||
|
@ -11,9 +11,10 @@ import './markdown-editor.component.css';
|
|||
selector: 'markdown-editor',
|
||||
templateUrl: '/static/js/directives/ui/markdown/markdown-editor.component.html'
|
||||
})
|
||||
export class MarkdownEditorComponent {
|
||||
export class MarkdownEditorComponent implements OnDestroy {
|
||||
|
||||
@Input('<') public content: string;
|
||||
|
||||
@Output() public save: EventEmitter<{editedContent: string}> = new EventEmitter();
|
||||
@Output() public discard: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
|
@ -23,8 +24,18 @@ export class MarkdownEditorComponent {
|
|||
private editMode: EditMode = "write";
|
||||
|
||||
constructor(@Inject('$document') private $document: ng.IDocumentService,
|
||||
@Inject('$window') private $window: ng.IWindowService,
|
||||
@Inject('BrowserPlatform') private browserPlatform: BrowserPlatform) {
|
||||
this.$window.onbeforeunload = this.onBeforeUnload.bind(this);
|
||||
}
|
||||
|
||||
@HostListener('window:beforeunload', [])
|
||||
public onBeforeUnload(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.$window.onbeforeunload = () => null;
|
||||
}
|
||||
|
||||
public changeEditMode(newMode: EditMode): void {
|
||||
|
@ -103,8 +114,10 @@ export class MarkdownEditorComponent {
|
|||
}
|
||||
|
||||
public discardChanges(): void {
|
||||
if (this.$window.confirm(`Are you sure you want to discard your changes?`)) {
|
||||
this.discard.emit({});
|
||||
}
|
||||
}
|
||||
|
||||
public get currentEditMode(): EditMode {
|
||||
return this.editMode;
|
||||
|
|
|
@ -14,7 +14,9 @@ export class MarkdownInputComponent {
|
|||
@Input('<') public content: string;
|
||||
@Input('<') public canWrite: boolean;
|
||||
@Input('@') public fieldTitle: string;
|
||||
|
||||
@Output() public contentChanged: EventEmitter<{content: string}> = new EventEmitter();
|
||||
|
||||
private isEditing: boolean = false;
|
||||
|
||||
public editContent(): void {
|
||||
|
|
|
@ -15,9 +15,7 @@ describe("MarkdownViewComponent", () => {
|
|||
markdownConverterMock = new Mock<Converter>();
|
||||
$sceMock = new Mock<ng.ISCEService>();
|
||||
$sanitizeMock = jasmine.createSpy('$sanitizeSpy').and.callFake((html: string) => html);
|
||||
component = new MarkdownViewComponent((options: ConverterOptions) => markdownConverterMock.Object,
|
||||
$sceMock.Object,
|
||||
$sanitizeMock);
|
||||
component = new MarkdownViewComponent(markdownConverterMock.Object, $sceMock.Object, $sanitizeMock);
|
||||
});
|
||||
|
||||
describe("ngOnChanges", () => {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { Component, Input, Inject, OnChanges, SimpleChanges } from 'ng-metadata/core';
|
||||
import { Converter, ConverterOptions } from 'showdown';
|
||||
import 'showdown-highlightjs-extension';
|
||||
import 'highlightjs/styles/vs.css';
|
||||
import './markdown-view.component.css';
|
||||
|
||||
|
||||
|
@ -17,15 +15,15 @@ export class MarkdownViewComponent implements OnChanges {
|
|||
@Input('<') public content: string;
|
||||
@Input('<') public firstLineOnly: boolean = false;
|
||||
@Input('<') public placeholderNeeded: boolean = false;
|
||||
|
||||
private convertedHTML: string = '';
|
||||
private readonly placeholder: string = `<p style="visibility:hidden">placeholder</p>`;
|
||||
private readonly markdownChars: string[] = ['#', '-', '>', '`'];
|
||||
private markdownConverter: Converter;
|
||||
|
||||
constructor(@Inject('markdownConverterFactory') private makeConverter: (options?: ConverterOptions) => Converter,
|
||||
constructor(@Inject('markdownConverter') private markdownConverter: Converter,
|
||||
@Inject('$sce') private $sce: ng.ISCEService,
|
||||
@Inject('$sanitize') private $sanitize: ng.sanitize.ISanitizeService) {
|
||||
this.markdownConverter = makeConverter({extensions: ['highlightjs']});
|
||||
|
||||
}
|
||||
|
||||
public ngOnChanges(changes: SimpleChanges): void {
|
||||
|
|
76
static/js/directives/ui/markdown/markdown.module.ts
Normal file
76
static/js/directives/ui/markdown/markdown.module.ts
Normal file
|
@ -0,0 +1,76 @@
|
|||
import { NgModule } from 'ng-metadata/core';
|
||||
import { Converter } from 'showdown';
|
||||
import * as showdown from 'showdown';
|
||||
import { registerLanguage, highlightAuto } from 'highlight.js/lib/highlight';
|
||||
import 'highlight.js/styles/vs.css';
|
||||
const highlightedLanguages: string[] = require('../../../constants/highlighted-languages.constant.json');
|
||||
|
||||
|
||||
/**
|
||||
* Dynamically fetch and register a new language with Highlight.js
|
||||
*/
|
||||
export const addHighlightedLanguage = (language: string): Promise<{}> => {
|
||||
return new Promise(async(resolve, reject) => {
|
||||
try {
|
||||
// TODO(alecmerdler): Use `import()` here instead of `System.import()` after upgrading to TypeScript 2.4
|
||||
const langModule = await System.import(`highlight.js/lib/languages/${language}`);
|
||||
registerLanguage(language, langModule);
|
||||
console.debug(`Language ${language} registered for syntax highlighting`);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
console.debug(`Language ${language} not supported for syntax highlighting`);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Showdown JS extension for syntax highlighting using Highlight.js. Will attempt to register detected languages.
|
||||
*/
|
||||
export const showdownHighlight = (): showdown.FilterExtension => {
|
||||
const htmlunencode = (text: string) => {
|
||||
return (text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>'));
|
||||
};
|
||||
|
||||
const left = '<pre><code\\b[^>]*>';
|
||||
const right = '</code></pre>';
|
||||
const flags = 'g';
|
||||
const replacement = (wholeMatch: string, match: string, leftSide: string, rightSide: string) => {
|
||||
const language: string = leftSide.slice(leftSide.indexOf('language-') + ('language-').length,
|
||||
leftSide.indexOf('"', leftSide.indexOf('language-')));
|
||||
addHighlightedLanguage(language).catch(error => null);
|
||||
|
||||
match = htmlunencode(match);
|
||||
return leftSide + highlightAuto(match).value + rightSide;
|
||||
};
|
||||
|
||||
return {
|
||||
type: 'output',
|
||||
filter: (text, converter, options) => {
|
||||
return (<any>showdown).helper.replaceRecursiveRegExp(text, replacement, left, right, flags);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Import default syntax-highlighting supported languages
|
||||
highlightedLanguages.forEach((langName) => addHighlightedLanguage(langName));
|
||||
|
||||
|
||||
/**
|
||||
* Markdown editor and view module.
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [],
|
||||
declarations: [],
|
||||
providers: [
|
||||
{provide: 'markdownConverter', useValue: new Converter({extensions: [<any>showdownHighlight]})},
|
||||
],
|
||||
})
|
||||
export class MarkdownModule {
|
||||
|
||||
}
|
|
@ -4,6 +4,7 @@ import { QuayModule } from './quay.module';
|
|||
import { provideRun } from './quay-run';
|
||||
import * as angular from 'angular';
|
||||
|
||||
|
||||
// Load all JS/CSS files into bundle: http://stackoverflow.com/a/30652110
|
||||
declare var require: any;
|
||||
function requireAll(r) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { NAME_PATTERNS } from "./constants/name-patterns.constant";
|
|||
import * as Raven from "raven-js";
|
||||
|
||||
|
||||
|
||||
var quayDependencies: string[] = [
|
||||
'chieffancypants.loadingBar',
|
||||
'cfp.hotkeys',
|
||||
|
|
|
@ -37,7 +37,7 @@ import { ManageTriggerComponent } from './directives/ui/manage-trigger/manage-tr
|
|||
import { ClipboardCopyDirective } from './directives/ui/clipboard-copy/clipboard-copy.directive';
|
||||
import { CorTabsModule } from './directives/ui/cor-tabs/cor-tabs.module';
|
||||
import { TriggerDescriptionComponent } from './directives/ui/trigger-description/trigger-description.component';
|
||||
import { Converter, ConverterOptions } from 'showdown';
|
||||
import { MarkdownModule } from './directives/ui/markdown/markdown.module';
|
||||
import * as Clipboard from 'clipboard';
|
||||
|
||||
|
||||
|
@ -49,6 +49,7 @@ import * as Clipboard from 'clipboard';
|
|||
QuayRoutesModule,
|
||||
QuayConfigModule,
|
||||
CorTabsModule,
|
||||
MarkdownModule,
|
||||
],
|
||||
declarations: [
|
||||
RegexMatchViewComponent,
|
||||
|
@ -86,7 +87,6 @@ import * as Clipboard from 'clipboard';
|
|||
DockerfileServiceImpl,
|
||||
DataFileServiceImpl,
|
||||
{provide: 'fileReaderFactory', useValue: () => new FileReader()},
|
||||
{provide: 'markdownConverterFactory', useValue: (options?: ConverterOptions) => new Converter(options)},
|
||||
{provide: 'BrowserPlatform', useValue: browserPlatform},
|
||||
{provide: 'clipboardFactory', useValue: (trigger, options) => new Clipboard(trigger, options)},
|
||||
],
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import * as Raven from 'raven-js';
|
||||
|
||||
|
||||
/**
|
||||
* Service which monitors the current user session and provides methods for returning information
|
||||
* about the user.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* Service which exposes various utility methods.
|
||||
*/
|
||||
angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverterFactory',
|
||||
function($sanitize, markdownConverterFactory) {
|
||||
angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverter',
|
||||
function($sanitize, markdownConverter) {
|
||||
var utilService = {};
|
||||
|
||||
var adBlockEnabled = null;
|
||||
|
@ -34,7 +34,7 @@ angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverterFa
|
|||
};
|
||||
|
||||
utilService.getMarkedDown = function(string) {
|
||||
return markdownConverterFactory().makeHtml(string || '');
|
||||
return markdownConverter.makeHtml(string || '');
|
||||
};
|
||||
|
||||
utilService.getFirstMarkdownLineAsText = function(commentString, placeholderNeeded) {
|
||||
|
|
3
static/js/types/custom.d.ts
vendored
Normal file
3
static/js/types/custom.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
declare var System: {
|
||||
import: (module: string) => Promise<any>;
|
||||
};
|
1
static/lib/rickshaw.min.css
vendored
1
static/lib/rickshaw.min.css
vendored
File diff suppressed because one or more lines are too long
3
static/lib/rickshaw.min.js
vendored
3
static/lib/rickshaw.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
|||
declare var require: any;
|
||||
declare var require: NodeRequire;
|
||||
|
||||
// Require all modules ending in ".spec.ts" from the js directory and all subdirectories
|
||||
var testsContext = (<any>require).context("../js", true, /\.spec\.ts$/);
|
||||
|
|
|
@ -22,14 +22,6 @@
|
|||
<meta property="og:image" content="{{ preferred_scheme }}://{{ hostname }}/static/img/quay_preview.png" />
|
||||
<!-- /Icons -->
|
||||
|
||||
{% for style_path in main_styles %}
|
||||
<link rel="stylesheet" href="/static/{{ style_path }}" type="text/css">
|
||||
{% endfor %}
|
||||
|
||||
{% for style_path in library_styles %}
|
||||
<link rel="stylesheet" href="/static/{{ style_path }}" type="text/css">
|
||||
{% endfor %}
|
||||
|
||||
{% block added_stylesheets %}
|
||||
|
||||
{% endblock %}
|
||||
|
@ -57,10 +49,6 @@
|
|||
<script src="{{ script_url }}"></script>
|
||||
{% endfor %}
|
||||
|
||||
{% for script_path in library_scripts %}
|
||||
<script src="/static/{{ script_path }}"></script>
|
||||
{% endfor %}
|
||||
|
||||
{% block added_dependencies %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
var webpack = require('webpack');
|
||||
var path = require("path");
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
|
||||
var config = {
|
||||
|
||||
let config = {
|
||||
entry: "./static/js/main.ts",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "static/build"),
|
||||
filename: 'quay-frontend.js'
|
||||
publicPath: "/static/build/",
|
||||
filename: '[name]-quay-frontend.bundle.js',
|
||||
chunkFilename: '[name]-quay-frontend.chunk.js'
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".ts", ".tsx", ".js", ".scss"],
|
||||
alias: {
|
||||
sass: path.resolve(__dirname, 'static/css/directives/components/pages/')
|
||||
}
|
||||
extensions: [".ts", ".js"],
|
||||
},
|
||||
// Use global variables to maintain compatibility with non-Webpack components
|
||||
externals: {
|
||||
angular: "angular",
|
||||
jquery: "$",
|
||||
moment: "moment",
|
||||
"raven-js": "Raven",
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
|
@ -47,7 +49,10 @@ var config = {
|
|||
FileSaver: 'file-saver',
|
||||
angular: "angular",
|
||||
$: "jquery",
|
||||
moment: "moment",
|
||||
}),
|
||||
// Restrict the extra locales that moment.js can load; en is always included
|
||||
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/),
|
||||
],
|
||||
devtool: "cheap-module-source-map",
|
||||
};
|
||||
|
@ -57,14 +62,15 @@ var config = {
|
|||
* Production settings
|
||||
*/
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
config.plugins.push(
|
||||
config.plugins.concat([
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
sourceMap: true,
|
||||
// Disable mangle to prevent AngularJS errors
|
||||
mangle: false
|
||||
})
|
||||
);
|
||||
config.output.filename = 'quay-frontend-[hash].js';
|
||||
}),
|
||||
new webpack.optimize.CommonsChunkPlugin({name: 'common'}),
|
||||
]);
|
||||
config.output.filename = '[name]-quay-frontend-[hash].bundle.js';
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
|
|
194
yarn.lock
194
yarn.lock
|
@ -70,7 +70,7 @@ abbrev@1, abbrev@1.0.x:
|
|||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
|
||||
|
||||
accepts@1.3.3:
|
||||
accepts@1.3.3, accepts@~1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
|
||||
dependencies:
|
||||
|
@ -87,6 +87,10 @@ acorn@^4.0.3, acorn@^4.0.4:
|
|||
version "4.0.11"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
|
||||
|
||||
acorn@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75"
|
||||
|
||||
adm-zip@0.4.4:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736"
|
||||
|
@ -207,6 +211,10 @@ array-find-index@^1.0.1:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||
|
||||
array-flatten@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||
|
||||
array-slice@^0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5"
|
||||
|
@ -779,10 +787,18 @@ constants-browserify@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
||||
|
||||
content-disposition@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||
|
||||
content-type@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed"
|
||||
|
||||
cookie-signature@1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
|
||||
cookie@0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||
|
@ -1016,6 +1032,10 @@ des.js@^1.0.0:
|
|||
inherits "^2.0.1"
|
||||
minimalistic-assert "^1.0.0"
|
||||
|
||||
destroy@~1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||
|
||||
di@^0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
|
||||
|
@ -1045,6 +1065,10 @@ domain-browser@^1.1.1:
|
|||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
|
||||
|
||||
duplexer@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
|
||||
|
@ -1055,6 +1079,10 @@ ee-first@1.1.1:
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
|
||||
ejs@^2.5.6:
|
||||
version "2.5.7"
|
||||
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.7.tgz#cc872c168880ae3c7189762fd5ffc00896c9518a"
|
||||
|
||||
electron-to-chromium@^1.2.3:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.4.tgz#9751cbea89fa120bf88c226ba41eb8d0b6f1b597"
|
||||
|
@ -1210,6 +1238,10 @@ esutils@^2.0.2:
|
|||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
||||
|
||||
etag@~1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051"
|
||||
|
||||
eventemitter3@1.x.x:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508"
|
||||
|
@ -1255,6 +1287,39 @@ expand-range@^1.8.1:
|
|||
dependencies:
|
||||
fill-range "^2.1.0"
|
||||
|
||||
express@^4.15.2:
|
||||
version "4.15.3"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662"
|
||||
dependencies:
|
||||
accepts "~1.3.3"
|
||||
array-flatten "1.1.1"
|
||||
content-disposition "0.5.2"
|
||||
content-type "~1.0.2"
|
||||
cookie "0.3.1"
|
||||
cookie-signature "1.0.6"
|
||||
debug "2.6.7"
|
||||
depd "~1.1.0"
|
||||
encodeurl "~1.0.1"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.0"
|
||||
finalhandler "~1.0.3"
|
||||
fresh "0.5.0"
|
||||
merge-descriptors "1.0.1"
|
||||
methods "~1.1.2"
|
||||
on-finished "~2.3.0"
|
||||
parseurl "~1.3.1"
|
||||
path-to-regexp "0.1.7"
|
||||
proxy-addr "~1.1.4"
|
||||
qs "6.4.0"
|
||||
range-parser "~1.2.0"
|
||||
send "0.15.3"
|
||||
serve-static "1.12.3"
|
||||
setprototypeof "1.0.3"
|
||||
statuses "~1.3.1"
|
||||
type-is "~1.6.15"
|
||||
utils-merge "1.0.0"
|
||||
vary "~1.1.1"
|
||||
|
||||
extend@3, extend@^3.0.0, extend@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
|
||||
|
@ -1285,6 +1350,10 @@ filename-regex@^2.0.0:
|
|||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
|
||||
|
||||
filesize@^3.5.9:
|
||||
version "3.5.10"
|
||||
resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f"
|
||||
|
||||
fill-range@^2.1.0:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
|
||||
|
@ -1295,7 +1364,7 @@ fill-range@^2.1.0:
|
|||
repeat-element "^1.1.2"
|
||||
repeat-string "^1.5.2"
|
||||
|
||||
finalhandler@1.0.3:
|
||||
finalhandler@1.0.3, finalhandler@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89"
|
||||
dependencies:
|
||||
|
@ -1340,6 +1409,14 @@ form-data@~2.1.1:
|
|||
combined-stream "^1.0.5"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
forwarded@~0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363"
|
||||
|
||||
fresh@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e"
|
||||
|
||||
fs-access@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a"
|
||||
|
@ -1474,6 +1551,12 @@ graceful-fs@^4.1.2:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||
|
||||
gzip-size@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520"
|
||||
dependencies:
|
||||
duplexer "^0.1.1"
|
||||
|
||||
handlebars@^4.0.1:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
|
||||
|
@ -1542,9 +1625,9 @@ he@1.1.x:
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||
|
||||
highlightjs@^9.8.0:
|
||||
version "9.10.0"
|
||||
resolved "https://registry.yarnpkg.com/highlightjs/-/highlightjs-9.10.0.tgz#fca9b78ddaa3b1abca89d6c3ee105ad270a80190"
|
||||
highlight.js@^9.12.0:
|
||||
version "9.12.0"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.0"
|
||||
|
@ -1678,6 +1761,10 @@ invert-kv@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
|
||||
|
||||
ipaddr.js@1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0"
|
||||
|
||||
is-absolute-url@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
|
||||
|
@ -2118,7 +2205,7 @@ lodash@^3.8.0:
|
|||
version "3.10.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
|
||||
|
||||
lodash@^4.0.0, lodash@^4.14.0, lodash@^4.5.0, lodash@~4.17.0:
|
||||
lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.5.0, lodash@~4.17.0:
|
||||
version "4.17.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||
|
||||
|
@ -2194,6 +2281,14 @@ meow@^3.3.0:
|
|||
redent "^1.0.0"
|
||||
trim-newlines "^1.0.0"
|
||||
|
||||
merge-descriptors@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||
|
||||
methods@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||
|
||||
micromatch@^2.1.5:
|
||||
version "2.3.11"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
|
||||
|
@ -2229,7 +2324,7 @@ mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7:
|
|||
dependencies:
|
||||
mime-db "~1.27.0"
|
||||
|
||||
mime@^1.3.4:
|
||||
mime@1.3.4, mime@^1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
|
||||
|
||||
|
@ -2456,6 +2551,10 @@ once@~1.3.3:
|
|||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
opener@^1.4.3:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
|
||||
|
||||
optimist@^0.6.1, optimist@~0.6.0:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
|
||||
|
@ -2571,6 +2670,10 @@ path-parse@^1.0.5:
|
|||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
|
||||
|
||||
path-to-regexp@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
|
||||
path-type@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||
|
@ -2881,6 +2984,13 @@ protractor@^5.1.2:
|
|||
webdriver-js-extender "^1.0.0"
|
||||
webdriver-manager "^12.0.6"
|
||||
|
||||
proxy-addr@~1.1.4:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918"
|
||||
dependencies:
|
||||
forwarded "~0.1.0"
|
||||
ipaddr.js "1.4.0"
|
||||
|
||||
prr@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
|
||||
|
@ -2945,7 +3055,7 @@ randombytes@^2.0.0, randombytes@^2.0.1:
|
|||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec"
|
||||
|
||||
range-parser@^1.0.3, range-parser@^1.2.0:
|
||||
range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
|
||||
|
||||
|
@ -3199,6 +3309,10 @@ safe-buffer@^5.0.1:
|
|||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
|
||||
|
||||
safe-buffer@~5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
|
||||
|
||||
saucelabs@~1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.3.0.tgz#d240e8009df7fa87306ec4578a69ba3b5c424fee"
|
||||
|
@ -3254,6 +3368,33 @@ semver@~5.0.1:
|
|||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a"
|
||||
|
||||
send@0.15.3:
|
||||
version "0.15.3"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309"
|
||||
dependencies:
|
||||
debug "2.6.7"
|
||||
depd "~1.1.0"
|
||||
destroy "~1.0.4"
|
||||
encodeurl "~1.0.1"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.0"
|
||||
fresh "0.5.0"
|
||||
http-errors "~1.6.1"
|
||||
mime "1.3.4"
|
||||
ms "2.0.0"
|
||||
on-finished "~2.3.0"
|
||||
range-parser "~1.2.0"
|
||||
statuses "~1.3.1"
|
||||
|
||||
serve-static@1.12.3:
|
||||
version "1.12.3"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2"
|
||||
dependencies:
|
||||
encodeurl "~1.0.1"
|
||||
escape-html "~1.0.3"
|
||||
parseurl "~1.3.1"
|
||||
send "0.15.3"
|
||||
|
||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
|
@ -3276,12 +3417,6 @@ sha.js@^2.3.6:
|
|||
dependencies:
|
||||
inherits "^2.0.1"
|
||||
|
||||
showdown-highlightjs-extension@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/showdown-highlightjs-extension/-/showdown-highlightjs-extension-0.1.2.tgz#0fc90190283c1ae03fc4cccce3f1be6a5a58e4ce"
|
||||
dependencies:
|
||||
highlightjs "^9.8.0"
|
||||
|
||||
showdown@^1.6.4:
|
||||
version "1.6.4"
|
||||
resolved "https://registry.yarnpkg.com/showdown/-/showdown-1.6.4.tgz#056bbb654ecdb8d8643ae12d6d597893ccaf46c6"
|
||||
|
@ -3740,6 +3875,10 @@ ultron@1.0.x:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
|
||||
|
||||
ultron@~1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864"
|
||||
|
||||
underscore@^1.5.2:
|
||||
version "1.8.3"
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
|
||||
|
@ -3819,6 +3958,10 @@ validate-npm-package-license@^3.0.1:
|
|||
spdx-correct "~1.0.0"
|
||||
spdx-expression-parse "~1.0.0"
|
||||
|
||||
vary@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"
|
||||
|
||||
vendors@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22"
|
||||
|
@ -3870,6 +4013,22 @@ webdriver-manager@^12.0.6:
|
|||
semver "^5.3.0"
|
||||
xml2js "^0.4.17"
|
||||
|
||||
webpack-bundle-analyzer@^2.8.3:
|
||||
version "2.8.3"
|
||||
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.8.3.tgz#8e7b3deb3832698c24b09c84dfe5b43902a83991"
|
||||
dependencies:
|
||||
acorn "^5.1.1"
|
||||
chalk "^1.1.3"
|
||||
commander "^2.9.0"
|
||||
ejs "^2.5.6"
|
||||
express "^4.15.2"
|
||||
filesize "^3.5.9"
|
||||
gzip-size "^3.0.0"
|
||||
lodash "^4.17.4"
|
||||
mkdirp "^0.5.1"
|
||||
opener "^1.4.3"
|
||||
ws "^2.3.1"
|
||||
|
||||
webpack-dev-middleware@^1.0.11:
|
||||
version "1.10.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.1.tgz#c6b4cf428139cf1aefbe06a0c00fdb4f8da2f893"
|
||||
|
@ -3965,6 +4124,13 @@ ws@1.1.2, ws@^1.0.1:
|
|||
options ">=0.0.5"
|
||||
ultron "1.0.x"
|
||||
|
||||
ws@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-2.3.1.tgz#6b94b3e447cb6a363f785eaf94af6359e8e81c80"
|
||||
dependencies:
|
||||
safe-buffer "~5.0.1"
|
||||
ultron "~1.1.0"
|
||||
|
||||
wtf-8@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a"
|
||||
|
|
Reference in a new issue