Browse Source

Migration/webpack5 (#701)

* Migrate to webpack5

* Update

* Fix patch.

* Dockerfix
pull/705/head
Sebastian Stehle 5 years ago
committed by GitHub
parent
commit
621d53322f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      Dockerfile
  2. 6
      frontend/app-config/karma-test-shim.js
  3. 33
      frontend/app-config/karma.conf.js
  4. 49
      frontend/app-config/karma.coverage.conf.js
  5. 234
      frontend/app-config/webpack.config.js
  6. 4
      frontend/app/features/administration/state/event-consumers.state.spec.ts
  7. 4
      frontend/app/features/administration/state/users.state.spec.ts
  8. 8
      frontend/app/framework/angular/forms/confirm-click.directive.ts
  9. 2
      frontend/app/framework/angular/forms/editors/code-editor.component.ts
  10. 2
      frontend/app/framework/angular/forms/editors/date-time-editor.component.ts
  11. 2
      frontend/app/framework/angular/forms/editors/tag-editor.component.ts
  12. 8
      frontend/app/framework/angular/forms/validators.ts
  13. 2
      frontend/app/framework/angular/http/caching.interceptor.ts
  14. 2
      frontend/app/framework/angular/http/http-extensions.ts
  15. 6
      frontend/app/framework/angular/routers/router-2-state.ts
  16. 2
      frontend/app/framework/angular/shortcut.component.ts
  17. 2
      frontend/app/framework/services/dialog.service.ts
  18. 2
      frontend/app/framework/services/resize.service.ts
  19. 5
      frontend/app/framework/utils/date-time.ts
  20. 2
      frontend/app/framework/utils/error.spec.ts
  21. 15
      frontend/app/framework/utils/rxjs-extensions.ts
  22. 4
      frontend/app/shared/interceptors/auth.interceptor.ts
  23. 4
      frontend/app/shared/services/apps.service.ts
  24. 8
      frontend/app/shared/services/assets.service.ts
  25. 4
      frontend/app/shared/services/auth.service.ts
  26. 2
      frontend/app/shared/services/backups.service.ts
  27. 2
      frontend/app/shared/services/schemas.service.spec.ts
  28. 2
      frontend/app/shared/services/schemas.types.ts
  29. 2
      frontend/app/shared/services/users-provider.service.spec.ts
  30. 2
      frontend/app/shared/state/apps.state.spec.ts
  31. 4
      frontend/app/shared/state/asset-uploader.state.spec.ts
  32. 8
      frontend/app/shared/state/assets.state.spec.ts
  33. 6
      frontend/app/shared/state/assets.state.ts
  34. 6
      frontend/app/shared/state/backups.state.spec.ts
  35. 2
      frontend/app/shared/state/clients.state.spec.ts
  36. 2
      frontend/app/shared/state/contents.forms.visitors.ts
  37. 6
      frontend/app/shared/state/contributors.state.spec.ts
  38. 4
      frontend/app/shared/state/contributors.state.ts
  39. 2
      frontend/app/shared/state/languages.state.spec.ts
  40. 2
      frontend/app/shared/state/plans.state.spec.ts
  41. 2
      frontend/app/shared/state/roles.state.spec.ts
  42. 2
      frontend/app/shared/state/rule-events.state.spec.ts
  43. 2
      frontend/app/shared/state/rule-simulator.state.spec.ts
  44. 2
      frontend/app/shared/state/rules.state.spec.ts
  45. 2
      frontend/app/shared/state/schemas.state.spec.ts
  46. 2
      frontend/app/shared/state/workflows.state.spec.ts
  47. 7
      frontend/app/shims.ts
  48. 7633
      frontend/package-lock.json
  49. 122
      frontend/package.json
  50. 19
      frontend/patches/resize-observer-polyfill+1.5.1.patch
  51. 6
      frontend/postcss.config.js
  52. 5
      frontend/tsconfig.spec.json
  53. 151
      frontend/tslint.json

15
Dockerfile

@ -36,15 +36,22 @@ RUN dotnet publish --no-restore src/Squidex/Squidex.csproj --output /build/ --co
#
# Stage 2, Build Frontend
#
FROM buildkite/puppeteer:5.2.1 as frontend
FROM buildkite/puppeteer:8.0.0 as frontend
WORKDIR /src
ENV CONTINUOUS_INTEGRATION=1
# Copy Node project files.
COPY frontend/package*.json /tmp/
# Copy patches for broken npm packages
COPY frontend/patches /tmp/patches
RUN cd /tmp/patches && dir
# Install Node packages
RUN cd /tmp && npm install --loglevel=error
RUN cd /tmp && npm set unsafe-perm true && npm install --loglevel=error
COPY frontend .
@ -68,8 +75,10 @@ RUN apt-get update \
# Default AspNetCore directory
WORKDIR /app
# Copy from build stages
# Copy from backend build stages
COPY --from=backend /build/ .
# Copy from backend build stages to webserver folder
COPY --from=frontend /build/ wwwroot/build/
EXPOSE 80

6
frontend/app-config/karma-test-shim.js

@ -1,6 +1,4 @@
/* eslint-disable */
Error.stackTraceLimit = Infinity;
Error.stackTraceLimit = Infinity;
require('core-js/proposals/reflect-metadata');
@ -12,7 +10,7 @@ const browser = require('@angular/platform-browser-dynamic/testing');
testing.getTestBed().initTestEnvironment(
browser.BrowserDynamicTestingModule,
browser.platformBrowserDynamicTesting()
browser.platformBrowserDynamicTesting(),
);
// Then we find all the tests.

33
frontend/app-config/karma.conf.js

@ -1,55 +1,52 @@
/* eslint-disable */
const webpackConfig = require('./webpack.config');
const webpackConfig = require('./webpack.config');
module.exports = function (config) {
var _config = {
/**
module.exports = function calculateConfig(config) {
const _config = {
/*
* Base path that will be used to resolve all patterns (e.g. files, exclude).
*/
basePath: '',
frameworks: ['jasmine'],
frameworks: ['jasmine', 'webpack'],
/**
/*
* Load additional test shim to setup angular for testing.
*/
files: [
{ pattern: './app-config/karma-test-shim.js', watched: false }
{ pattern: './app-config/karma-test-shim.js', watched: false },
],
preprocessors: {
'./app-config/karma-test-shim.js': ['webpack', 'sourcemap']
'./app-config/karma-test-shim.js': ['webpack', 'sourcemap'],
},
/**
/*
* Load the files with webpack and use test configuration for it.
*/
webpack: webpackConfig({ target: 'tests', jit: true }),
webpackMiddleware: {
stats: 'errors-only'
stats: 'errors-only',
},
/**
/*
* Leave Jasmine Spec Runner output visible in browser.
*/
client: {
clearContext: false
clearContext: false,
},
/**
/*
* Use a mocha style console reporter and html reporter.
*/
reporters: ['kjhtml', 'mocha'],
/**
/*
* Run with chrome to enable debugging.
*
* available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
*/
browsers: ['Chrome']
browsers: ['Chrome'],
};
config.set(_config);

49
frontend/app-config/karma.coverage.conf.js

@ -1,86 +1,85 @@
/* eslint-disable */
const webpackConfig = require('./webpack.config');
const webpackConfig = require('./webpack.config');
module.exports = function (config) {
var _config = {
/**
module.exports = function calculateConfig(config) {
const _config = {
/*
* Base path that will be used to resolve all patterns (e.g. files, exclude).
*/
basePath: '',
frameworks: ['jasmine'],
frameworks: ['jasmine', 'webpack'],
/**
/*
* Load additional test shim to setup angular for testing.
*/
files: [
{ pattern: './app-config/karma-test-shim.js', watched: false }
{ pattern: './app-config/karma-test-shim.js', watched: false },
],
preprocessors: {
'./app-config/karma-test-shim.js': ['webpack', 'sourcemap']
'./app-config/karma-test-shim.js': ['webpack', 'sourcemap'],
},
/**
/*
* Load the files with webpack and use test configuration for it.
*/
webpack: webpackConfig({ target: 'tests', coverage: true, jit: true }),
webpackMiddleware: {
stats: 'errors-only'
stats: 'errors-only',
},
/**
/*
* Use a mocha style console reporter, html reporter and the code coverage reporter.
*/
reporters: ['kjhtml', 'mocha', 'coverage-istanbul'],
htmlReporter: {
useCompactStyle: true,
/**
/*
* Use the same folder like the html report for coverage reports.
*/
outputFile: '_test-output/tests.html',
/**
/*
* Group the output by test suite (describe), equivalent to mocha reporter.
*/
groupSuites: true
groupSuites: true,
},
coverageIstanbulReporter: {
// eslint-disable-next-line global-require
dir: require('path').join(__dirname, '../_test-output/coverage'),
reports: [
'html',
'lcovonly'
'lcovonly',
],
fixWebpackSourcePaths: true
fixWebpackSourcePaths: true,
},
/**
/*
* Disable continuous Integration mode, run only one time.
*/
singleRun: true,
customLaunchers: {
ChromeCustom: {
base: 'ChromeHeadless',
/**
base: 'ChromeHeadless',
/*
* We must disable the Chrome sandbox (Chrome's sandbox needs more permissions than Docker allows by default).
*/
flags: ['--no-sandbox']
}
flags: ['--no-sandbox'],
},
},
/**
/*
* Run with chrome because phantom js does not provide all types.
*
* Available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
*/
browsers: ['ChromeCustom']
browsers: ['ChromeCustom'],
};
config.set(_config);

234
frontend/app-config/webpack.config.js

@ -1,12 +1,16 @@
/* eslint-disable */
/* eslint-disable no-useless-escape */
/* eslint-disable global-require */
const webpack = require('webpack'), path = require('path');
const webpack = require('webpack');
const path = require('path');
const appRoot = path.resolve(__dirname, '..');
function root() {
var newArgs = Array.prototype.slice.call(arguments, 0);
// eslint-disable-next-line prefer-rest-params
const newArgs = Array.prototype.slice.call(arguments, 0);
// eslint-disable-next-line prefer-spread
return path.join.apply(path, [appRoot].concat(newArgs));
}
@ -24,7 +28,7 @@ const plugins = {
// https://www.npmjs.com/package/@ngtools/webpack
NgToolsWebpack: require('@ngtools/webpack'),
// https://github.com/NMFR/optimize-css-assets-webpack-plugin
OptimizeCSSAssetsPlugin: require("optimize-css-assets-webpack-plugin"),
OptimizeCSSAssetsPlugin: require('optimize-css-assets-webpack-plugin'),
// https://webpack.js.org/plugins/eslint-webpack-plugin/
ESLintPlugin: require('eslint-webpack-plugin'),
// https://www.npmjs.com/package/sass-lint-webpack
@ -34,10 +38,12 @@ const plugins = {
// https://www.npmjs.com/package/@angular-devkit/build-optimizer
BuildOptimizerWebpackPlugin: require('@angular-devkit/build-optimizer').BuildOptimizerWebpackPlugin,
// https://webpack.js.org/plugins/copy-webpack-plugin/
CopyPlugin: require('copy-webpack-plugin')
CopyPlugin: require('copy-webpack-plugin'),
// https://www.npmjs.com/package/webpack-filter-warnings-plugin
FilterWarningsPlugin: require('webpack-filter-warnings-plugin'),
};
module.exports = function (env) {
module.exports = function calculateConfig(env) {
const isDevServer = path.basename(require.main.filename) === 'webpack-dev-server.js';
const isProduction = env && env.production;
const isTests = env && env.target === 'tests';
@ -47,23 +53,26 @@ module.exports = function (env) {
const configFile = isTests ? 'tsconfig.spec.json' : 'tsconfig.app.json';
// eslint-disable-next-line no-console
console.log(`Use ${configFile}`);
const config = {
mode: isProduction ? 'production' : 'development',
/**
/*
* Source map for Karma from the help of karma-sourcemap-loader & karma-webpack.
*
* See: https://webpack.js.org/configuration/devtool/
*/
devtool: isProduction ? false : 'inline-source-map',
/**
/*
* Options affecting the resolving of modules.
*
* See: https://webpack.js.org/configuration/resolve/
*/
resolve: {
/**
/*
* An array of extensions that should be used to resolve modules.
*
* See: https://webpack.js.org/configuration/resolve/#resolve-extensions
@ -72,88 +81,89 @@ module.exports = function (env) {
modules: [
root('app'),
root('app', 'theme'),
root('node_modules')
root('node_modules'),
],
plugins: [
new plugins.TsconfigPathsPlugin({
configFile
})
]
configFile,
}),
],
},
/**
/*
* Options affecting the normal modules.
*
* See: https://webpack.js.org/configuration/module/
*/
module: {
/**
/*
* An array of Rules which are matched to requests when modules are created.
*
* See: https://webpack.js.org/configuration/module/#module-rules
*/
rules: [{
test: /\.mjs$/,
type: "javascript/auto",
include: [/node_modules/]
type: 'javascript/auto',
include: [/node_modules/],
}, {
// Mark files inside `@angular/core` as using SystemJS style dynamic imports.
test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
include: [/node_modules/]
include: [/node_modules/],
}, {
test: /\.js\.flow$/,
use: [{
loader: 'ignore-loader'
loader: 'ignore-loader',
}],
include: [/node_modules/]
include: [/node_modules/],
}, {
test: /\.map$/,
use: [{
loader: 'ignore-loader'
loader: 'ignore-loader',
}],
include: [/node_modules/]
include: [/node_modules/],
}, {
test: /\.d\.ts$/,
use: [{
loader: 'ignore-loader'
loader: 'ignore-loader',
}],
include: [/node_modules/]
include: [/node_modules/],
}, {
test: /\.(woff|woff2|ttf|eot)(\?.*$|$)/,
use: [{
loader: 'file-loader?name=[name].[hash].[ext]',
loader: 'file-loader?name=[name].[fullhash].[ext]',
options: {
outputPath: 'assets',
/*
* Use custom public path as ./ is not supported by fonts.
*/
publicPath: isDevServer ? undefined : 'assets'
}
}]
publicPath: isDevServer ? undefined : 'assets',
},
}],
}, {
test: /\.(png|jpe?g|gif|svg|ico)(\?.*$|$)/,
use: [{
loader: 'file-loader?name=[name].[hash].[ext]',
loader: 'file-loader?name=[name].[fullhash].[ext]',
options: {
outputPath: 'assets'
}
}]
outputPath: 'assets',
},
}],
}, {
test: /\.css$/,
use: [
plugins.MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
loader: 'css-loader',
}, {
loader: 'postcss-loader'
}]
loader: 'postcss-loader',
}],
}, {
test: /\.scss$/,
use: [{
loader: 'raw-loader'
loader: 'raw-loader',
}, {
loader: 'postcss-loader'
loader: 'postcss-loader',
}, {
loader: 'sass-loader',
options: {
@ -162,43 +172,54 @@ module.exports = function (env) {
@import '_mixins';
`,
sassOptions: {
includePaths: [root('app', 'theme')]
}
}
includePaths: [root('app', 'theme')],
},
},
}],
exclude: root('app', 'theme')
}]
exclude: root('app', 'theme'),
}],
},
plugins: [
new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)fesm5/, root('./app'), {}),
new plugins.FilterWarningsPlugin({
exclude: /System.import/,
}),
/*
* Always replace the context for the System.import in angular/core to prevent warnings.
*/
new webpack.ContextReplacementPlugin(
/\@angular(\\|\/)core(\\|\/)/,
root('./app', '$_lazy_route_resources'),
{},
),
/**
/*
* Puts each bundle into a file and appends the hash of the file to the path.
*
* See: https://github.com/webpack-contrib/mini-css-extract-plugin
*/
new plugins.MiniCssExtractPlugin({
filename: '[name].css'
filename: '[name].css',
}),
new webpack.LoaderOptionsPlugin({
options: {
htmlLoader: {
/**
/*
* Define the root for images, so that we can use absolute urls.
*
* See: https://github.com/webpack/html-loader#Advanced_Options
*/
root: root('app', 'images')
root: root('app', 'images'),
},
context: '/'
}
context: '/',
},
}),
new plugins.SassLintPlugin(),
/**
/*
* Detect circular dependencies in app.
*
* See: https://github.com/aackerman/circular-dependency-plugin
@ -206,8 +227,12 @@ module.exports = function (env) {
new plugins.CircularDependencyPlugin({
exclude: /([\\\/]node_modules[\\\/])|(ngfactory\.js$)/,
// Add errors to webpack instead of warnings
failOnError: true
failOnError: true,
}),
/*
* Copy lazy loaded libraries to output.
*/
new plugins.CopyPlugin({
patterns: [
{ from: './node_modules/simplemde/dist', to: 'dependencies/simplemde' },
@ -225,11 +250,11 @@ module.exports = function (env) {
{ from: './node_modules/tinymce/tinymce.min.js', to: 'dependencies/tinymce' },
{ from: './node_modules/ace-builds/src-min/ace.js', to: 'dependencies/ace/ace.js' },
{ from: './node_modules/ace-builds/src-min/ext-language_tools.js', to: 'dependencies/ace/ext/language_tools.js' },
{ from: './node_modules/ace-builds/src-min/ext-modelist.js', to: 'dependencies/ace/ext/modelist.js' },
{ from: './node_modules/ace-builds/src-min/mode-*.js', to: 'dependencies/ace/[name].[ext]' },
{ from: './node_modules/ace-builds/src-min/worker-*.js', to: 'dependencies/ace/[name].[ext]' },
{ from: './node_modules/ace-builds/src-min/snippets', to: 'dependencies/ace/snippets' },
{ from: './node_modules/ace-builds/src-min/ext-modelist.js', to: 'dependencies/ace/ext/modelist.js' },
{ from: './node_modules/ace-builds/src-min/ext-language_tools.js', to: 'dependencies/ace/ext/language_tools.js' },
{ from: './node_modules/ace-builds/src-min/worker-*.js', to: 'dependencies/ace/[name].[ext]' },
{ from: './node_modules/video.js/dist/video.min.js', to: 'dependencies/videojs' },
{ from: './node_modules/video.js/dist/video-js.min.css', to: 'dependencies/videojs' },
@ -244,27 +269,27 @@ module.exports = function (env) {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*'
'Access-Control-Allow-Origin': '*',
},
historyApiFallback: true,
}
},
};
if (!isTests) {
/**
/*
* The entry point for the bundle. Our Angular app.
*
* See: https://webpack.js.org/configuration/entry-context/
*/
config.entry = {
'shims': './app/shims.ts',
'style': './app/style.js',
'app': './app/app.ts'
shims: './app/shims.ts',
style: './app/style.js',
app: './app/app.ts',
};
if (isProduction) {
config.output = {
/**
/*
* The output directory as absolute path (required).
*
* See: https://webpack.js.org/configuration/output/#output-path
@ -273,38 +298,39 @@ module.exports = function (env) {
publicPath: './build/',
/**
/*
* Specifies the name of each output file on disk.
*
* See: https://webpack.js.org/configuration/output/#output-filename
*/
filename: '[name].js',
/**
/*
* The filename of non-entry chunks as relative path inside the output.path directory.
*
* See: https://webpack.js.org/configuration/output/#output-chunkfilename
*/
chunkFilename: '[id].[hash].chunk.js'
chunkFilename: '[id].[fullhash].chunk.js',
};
} else {
config.output = {
filename: '[name].js',
/**
/*
* Set the public path, because we are running the website from another port (5000).
*/
publicPath: 'https://localhost:3000/'
publicPath: 'https://localhost:3000/',
};
}
config.plugins.push(
new plugins.HtmlWebpackPlugin({
filename: 'index.html',
hash: true,
chunks: ['shims', 'app'],
chunksSortMode: 'manual',
template: 'app/index.html'
})
template: root('app', 'index.html'),
}),
);
config.plugins.push(
@ -313,30 +339,28 @@ module.exports = function (env) {
hash: true,
chunks: ['style'],
chunksSortMode: 'none',
template: 'app/_theme.html'
})
template: root('app', '_theme.html'),
}),
);
if (isProduction) {
config.plugins.push(
new plugins.ESLintPlugin({
files: [
'./app/**/*.ts'
]
})
'./app/**/*.ts',
],
}),
);
}
}
if (!isTestCoverage) {
config.plugins.push(
new plugins.NgToolsWebpack.AngularCompilerPlugin({
new plugins.NgToolsWebpack.AngularWebpackPlugin({
directTemplateLoading: true,
entryModule: 'app/app.module#AppModule',
skipCodeGeneration: !isAot,
sourceMap: !isProduction,
tsConfigPath: configFile
})
jitMode: !isAot,
tsconfig: configFile,
}),
);
}
@ -349,19 +373,19 @@ module.exports = function (env) {
ecma: 5,
mangle: true,
output: {
comments: false
comments: false,
},
safari10: true
safari10: true,
},
extractComments: true
extractComments: true,
}),
new plugins.OptimizeCSSAssetsPlugin({})
]
new plugins.OptimizeCSSAssetsPlugin({}),
],
};
config.performance = {
hints: false
hints: false,
};
config.plugins.push(new plugins.BuildOptimizerWebpackPlugin());
@ -371,9 +395,9 @@ module.exports = function (env) {
use: [{
loader: '@angular-devkit/build-optimizer/webpack-loader',
options: {
sourceMap: false
}
}]
sourceMap: false,
},
}],
});
}
@ -382,7 +406,7 @@ module.exports = function (env) {
config.module.rules.push({
test: /\.ts$/,
use: [{
loader: 'ts-loader'
loader: 'ts-loader',
}],
include: [/\.(e2e|spec)\.ts$/],
});
@ -391,19 +415,19 @@ module.exports = function (env) {
config.module.rules.push({
test: /\.ts$/,
use: [{
loader: 'istanbul-instrumenter-loader?esModules=true'
loader: 'istanbul-instrumenter-loader?esModules=true',
}, {
loader: 'ts-loader'
loader: 'ts-loader',
}],
exclude: [/\.(e2e|spec)\.ts$/]
exclude: [/\.(e2e|spec)\.ts$/],
});
} else {
config.module.rules.push({
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
test: /\.[jt]sx?$/,
use: [{
loader: plugins.NgToolsWebpack.NgToolsLoader
}]
})
loader: '@ngtools/webpack',
}],
});
}
if (isProduction) {
@ -417,11 +441,11 @@ module.exports = function (env) {
use: [
plugins.MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
loader: 'css-loader',
}, {
loader: 'postcss-loader'
loader: 'postcss-loader',
}, {
loader: 'sass-loader'
loader: 'sass-loader',
}],
/*
* Do not include component styles.
@ -432,21 +456,21 @@ module.exports = function (env) {
config.module.rules.push({
test: /\.scss$/,
use: [{
loader: 'style-loader'
loader: 'style-loader',
}, {
loader: 'css-loader'
loader: 'css-loader',
}, {
loader: 'postcss-loader'
loader: 'postcss-loader',
}, {
loader: 'sass-loader',
options: {
sourceMap: true
}
sourceMap: true,
},
}],
/*
* Do not include component styles.
*/
include: root('app', 'theme')
include: root('app', 'theme'),
});
}

4
frontend/app/features/administration/state/event-consumers.state.spec.ts

@ -48,7 +48,7 @@ describe('EventConsumersState', () => {
it('should reset loading state if loading failed', () => {
eventConsumersService.setup(x => x.getEventConsumers())
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
eventConsumersState.load().pipe(onErrorResumeNext()).subscribe();
@ -68,7 +68,7 @@ describe('EventConsumersState', () => {
it('should show notification on load error if silent is false', () => {
eventConsumersService.setup(x => x.getEventConsumers())
.returns(() => throwError('Service Error')).verifiable();
.returns(() => throwError(() => 'Service Error')).verifiable();
eventConsumersState.load(true, false).pipe(onErrorResumeNext()).subscribe();

4
frontend/app/features/administration/state/users.state.spec.ts

@ -53,7 +53,7 @@ describe('UsersState', () => {
it('should reset loading state if loading failed', () => {
usersService.setup(x => x.getUsers(10, 0, undefined))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
usersState.load().pipe(onErrorResumeNext()).subscribe();
@ -136,7 +136,7 @@ describe('UsersState', () => {
it('should return null on select if user is not found', () => {
usersService.setup(x => x.getUser('unknown'))
.returns(() => throwError('Service Error')).verifiable();
.returns(() => throwError(() => 'Service Error')).verifiable();
let userSelected: UserDto;

8
frontend/app/framework/angular/forms/confirm-click.directive.ts

@ -6,7 +6,7 @@
*/
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
import { DialogService } from '@app/framework/internal';
import { DialogService, Types } from '@app/framework/internal';
import { Subscriber } from 'rxjs';
import { take } from 'rxjs/operators';
@ -54,8 +54,10 @@ export class ConfirmClickDirective {
for (const observer of observers) {
const subscriber = observer as Subscriber<any>;
if (subscriber['destination'] && subscriber['destination'].next) {
subscriber['destination'].next(true);
const internal = (subscriber as any).destination;
if (Types.isFunction(internal.next)) {
internal.next(true);
}
}
}

2
frontend/app/framework/angular/forms/editors/code-editor.component.ts

@ -182,7 +182,7 @@ export class CodeEditorComponent extends StatefulControlComponent<{}, string> im
});
this.aceEditor.on('change', () => {
this.valueChanged.next();
this.valueChanged.next(true);
});
this.detach();

2
frontend/app/framework/angular/forms/editors/date-time-editor.component.ts

@ -125,7 +125,7 @@ export class DateTimeEditorComponent extends StatefulControlComponent<State, str
}
public callTouched() {
this.blur.next();
this.blur.next(true);
super.callTouched();
}

2
frontend/app/framework/angular/forms/editors/tag-editor.component.ts

@ -371,7 +371,7 @@ export class TagEditorComponent extends StatefulControlComponent<State, Readonly
}
public callTouched() {
this.blur.next();
this.blur.next(true);
super.callTouched();
}

8
frontend/app/framework/angular/forms/validators.ts

@ -89,10 +89,10 @@ export module ValidatorsEx {
const value = parseFloat(control.value);
if (min === max) {
if (Number.isNaN(value) || value !== min) {
if (!Types.isNumber(value) || Number.isNaN(value) || value !== min) {
return { exactly: { expected: min, actual: value } };
}
} else if (Number.isNaN(value) || value < min || value > max) {
} else if (!Types.isNumber(value) || Number.isNaN(value) || value < min || value > max) {
return { between: { min, max, actual: value } };
}
@ -119,10 +119,10 @@ export module ValidatorsEx {
const length: number = control.value?.length || 0;
if (minLength === maxLength) {
if (Number.isNaN(length) || length !== minLength) {
if (!Types.isNumber(length) || Number.isNaN(length) || length !== minLength) {
return { exactlylength: { expected: minLength, actual: length } };
}
} else if (Number.isNaN(length) || length < minLength || length > maxLength) {
} else if (!Types.isNumber(length) || Number.isNaN(length) || length < minLength || length > maxLength) {
return { betweenlength: { minlength: minLength, maxlength: maxLength, actual: length } };
}

2
frontend/app/framework/angular/http/caching.interceptor.ts

@ -35,7 +35,7 @@ export class CachingInterceptor implements HttpInterceptor {
if (Types.is(error, HttpErrorResponse) && error.status === 304 && cacheEntry) {
return of(cacheEntry);
} else {
return throwError(error);
return throwError(() => error);
}
}));
} else {

2
frontend/app/framework/angular/http/http-extensions.ts

@ -84,7 +84,7 @@ export const pretifyError = (message: string) => <T>(source: Observable<T>) =>
source.pipe(catchError((response: HttpErrorResponse) => {
const error = parseError(response, message);
return throwError(error);
return throwError(() => error);
}));
export function parseError(response: HttpErrorResponse, fallback: string) {

6
frontend/app/framework/angular/routers/router-2-state.ts

@ -40,17 +40,17 @@ export class PagingSynchronizer implements RouteSynchronizer {
pageSize = parseInt(pageSizeValue, 10);
}
if (pageSize <= 0 || pageSize > 100 || Number.isNaN(pageSize)) {
if (pageSize <= 0 || pageSize > 100 || !Types.isNumber(pageSize) || Number.isNaN(pageSize)) {
pageSize = this.localStore.getInt(`${this.storeName}.pageSize`, this.defaultSize);
}
if (pageSize <= 0 || pageSize > 100 || Number.isNaN(pageSize)) {
if (pageSize <= 0 || pageSize > 100 || !Types.isNumber(pageSize) || Number.isNaN(pageSize)) {
pageSize = this.defaultSize;
}
let page = parseInt(query['page'], 10);
if (page <= 0 || Number.isNaN(page)) {
if (page <= 0 || !Types.isNumber(page) || Number.isNaN(page)) {
page = 0;
}

2
frontend/app/framework/angular/shortcut.component.ts

@ -47,7 +47,7 @@ export class ShortcutComponent extends StatefulComponent implements OnDestroy, O
this.shortcutService.on(this.lastKeys, () => {
if (!this.disabled) {
this.zone.run(() => {
this.trigger.next();
this.trigger.next(true);
});
}

2
frontend/app/framework/services/dialog.service.ts

@ -112,7 +112,7 @@ export class DialogService {
this.notify(Notification.error(error));
}
return throwError(error);
return throwError(() => error);
}
public notifyInfo(text: string) {

2
frontend/app/framework/services/resize.service.ts

@ -25,7 +25,7 @@ export class ResizeService implements OnDestroy {
public listen(target: Element, listener: ResizeListener) {
if (!this.observer) {
this.observer = new ResizeObserver(entries => {
this.observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
for (const entry of entries) {
if (this.listeners.has(entry.target)) {
const component = this.listeners.get(entry.target);

5
frontend/app/framework/utils/date-time.ts

@ -7,6 +7,7 @@
import { addDays, addHours, addMilliseconds, addMinutes, addMonths, addSeconds, addYears, format, formatDistanceToNow, formatISO, parse, parseISO, startOfDay, startOfMonth, startOfTomorrow, startOfWeek, startOfYesterday } from 'date-fns';
import { DateHelper } from './date-helper';
import { Types } from './types';
const DATE_FORMAT = 'yyyy-MM-dd';
@ -98,7 +99,9 @@ export class DateTime {
date = parseISO(value);
}
if (Number.isNaN(date.getTime())) {
const time = date.getTime();
if (Number.isNaN(time) || !Types.isNumber(time)) {
return null;
}

2
frontend/app/framework/utils/error.spec.ts

@ -50,7 +50,7 @@ describe('ErrorDto', () => {
expect(result).toBe('error.\n\n * detail.\n');
});
it('should ccreate html list if detail has one item', () => {
it('should create html list if detail has one item', () => {
const error = new ErrorDto(500, 'i18n:error.', null, ['i18n:detail.']);
const result = error.translate(localizer.object);

15
frontend/app/framework/utils/rxjs-extensions.ts

@ -5,8 +5,8 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { EMPTY, Observable, throwError } from 'rxjs';
import { catchError, distinctUntilChanged, filter, map, onErrorResumeNext, publishReplay, refCount, switchMap } from 'rxjs/operators';
import { EMPTY, Observable, ReplaySubject, throwError } from 'rxjs';
import { catchError, distinctUntilChanged, filter, map, onErrorResumeNext, share, switchMap } from 'rxjs/operators';
import { DialogService } from './../services/dialog.service';
import { Version, versioned, Versioned } from './version';
@ -26,7 +26,12 @@ export function shareSubscribed<T>(dialogs: DialogService, options?: Options) {
export function shareMapSubscribed<T, R = T>(dialogs: DialogService, project: (value: T) => R, options?: Options) {
return function mapOperation(source: Observable<T>) {
const shared = source.pipe(publishReplay(), refCount());
const shared = source.pipe(share({
connector: () => new ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: false,
}));
shared.pipe(
catchError(error => {
@ -35,7 +40,7 @@ export function shareMapSubscribed<T, R = T>(dialogs: DialogService, project: (v
}
if (options?.throw) {
return throwError(error);
return throwError(() => error);
}
return EMPTY;
@ -54,7 +59,7 @@ export function defined<T>() {
export function switchSafe<T, R>(project: (source: T) => Observable<R>) {
return function mapOperation(source: Observable<T>) {
return source.pipe(switchMap(project), onErrorResumeNext<R, R>());
return source.pipe(switchMap(project), onErrorResumeNext());
};
}

4
frontend/app/shared/interceptors/auth.interceptor.ts

@ -65,11 +65,11 @@ export class AuthInterceptor implements HttpInterceptor {
return EMPTY;
} else {
return throwError(new ErrorDto(403, 'i18n:common.errorNoPermission'));
return throwError(() => new ErrorDto(403, 'i18n:common.errorNoPermission'));
}
}
return throwError(error);
return throwError(() => error);
}));
}
}

4
frontend/app/shared/services/apps.service.ts

@ -229,9 +229,9 @@ export class AppsService {
}),
catchError(error => {
if (Types.is(error, HttpErrorResponse) && error.status === 413) {
return throwError(new ErrorDto(413, 'i18n:apps.uploadImageTooBig'));
return throwError(() => new ErrorDto(413, 'i18n:apps.uploadImageTooBig'));
} else {
return throwError(error);
return throwError(() => error);
}
}),
tap(value => {

8
frontend/app/shared/services/assets.service.ts

@ -296,9 +296,9 @@ export class AssetsService {
}),
catchError((error: any) => {
if (Types.is(error, HttpErrorResponse) && error.status === 413) {
return throwError(new ErrorDto(413, 'i18n:assets.fileTooBig'));
return throwError(() => new ErrorDto(413, 'i18n:assets.fileTooBig'));
} else {
return throwError(error);
return throwError(() => error);
}
}),
tap(value => {
@ -331,9 +331,9 @@ export class AssetsService {
}),
catchError(error => {
if (Types.is(error, HttpErrorResponse) && error.status === 413) {
return throwError(new ErrorDto(413, 'i18n:assets.fileTooBig'));
return throwError(() => new ErrorDto(413, 'i18n:assets.fileTooBig'));
} else {
return throwError(error);
return throwError(() => error);
}
}),
tap(value => {

4
frontend/app/shared/services/auth.service.ts

@ -168,10 +168,10 @@ export class AuthService {
retryWhen(errors =>
concat(
errors.pipe(
mergeMap(e => (Types.is(e, TimeoutError) ? of(e) : throwError(e))),
mergeMap(e => (Types.is(e, TimeoutError) ? of(e) : throwError(() => e))),
delay(500),
take(5)),
throwError(new Error('Retry limit exceeded.')),
throwError(() => new Error('Retry limit exceeded.')),
),
),
);

2
frontend/app/shared/services/backups.service.ts

@ -95,7 +95,7 @@ export class BackupsService {
if (Types.is(error, HttpErrorResponse) && error.status === 404) {
return of(null);
} else {
return throwError(error);
return throwError(() => error);
}
}),
pretifyError('i18n:backups.loadFailed'));

2
frontend/app/shared/services/schemas.service.spec.ts

@ -32,7 +32,7 @@ describe('SchemasService', () => {
it('should throw if creating invalid property type', () => {
const type: any = 'invalid';
expect(() => createProperties(type)).toThrow('Invalid properties type');
expect(() => createProperties(type)).toThrowError();
});
it('should make get request to get schemas',

2
frontend/app/shared/services/schemas.types.ts

@ -108,6 +108,8 @@ export function createProperties(fieldType: FieldType, values?: any): FieldPrope
case 'UI':
properties = new UIFieldPropertiesDto();
break;
default:
throw new Error(`Unknown field type ${fieldType}.`);
}
if (values) {

2
frontend/app/shared/services/users-provider.service.spec.ts

@ -82,7 +82,7 @@ describe('UsersProviderService', () => {
.returns(() => new Profile(<any>{ profile: { sub: '123' } }));
usersService.setup(x => x.getUser('123'))
.returns(() => throwError('Service Error')).verifiable(Times.once());
.returns(() => throwError(() => 'Service Error')).verifiable(Times.once());
let resultingUser: UserDto;

2
frontend/app/shared/state/apps.state.spec.ts

@ -108,7 +108,7 @@ describe('AppsState', () => {
let appSelected: AppDto;
appsService.setup(x => x.getApp('unknown'))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
appsState.select('unknown').pipe(onErrorResumeNext()).subscribe(x => {
appSelected = x!;

4
frontend/app/shared/state/asset-uploader.state.spec.ts

@ -83,7 +83,7 @@ describe('AssetUploaderState', () => {
const file: File = <any>{ name: 'my-file' };
assetsService.setup(x => x.postAssetFile(app, file, undefined))
.returns(() => throwError('Service Error')).verifiable();
.returns(() => throwError(() => 'Service Error')).verifiable();
assetUploader.uploadFile(file).pipe(onErrorResumeNext()).subscribe();
@ -148,7 +148,7 @@ describe('AssetUploaderState', () => {
const file: File = <any>{ name: 'my-file' };
assetsService.setup(x => x.putAssetFile(app, asset, file, asset.version))
.returns(() => throwError('Service Error')).verifiable();
.returns(() => throwError(() => 'Service Error')).verifiable();
assetUploader.uploadAsset(asset, file).pipe(onErrorResumeNext()).subscribe();

8
frontend/app/shared/state/assets.state.spec.ts

@ -279,7 +279,7 @@ describe('AssetsState', () => {
const request = { parentId: 'newParent' };
assetsService.setup(x => x.putAssetItemParent(app, asset1, It.isValue(request), asset1.version))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
assetsState.moveAsset(asset1, request.parentId).pipe(onErrorResumeNext()).subscribe();
@ -318,7 +318,7 @@ describe('AssetsState', () => {
const request = { parentId: 'newParent' };
assetsService.setup(x => x.putAssetItemParent(app, assetFolder1, It.isValue(request), assetFolder1.version))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
assetsState.moveAssetFolder(assetFolder1, request.parentId).pipe(onErrorResumeNext()).subscribe();
@ -338,7 +338,7 @@ describe('AssetsState', () => {
it('should remove asset from snapshot if when referenced and not confirmed', () => {
assetsService.setup(x => x.deleteAssetItem(app, asset1, false, asset1.version))
.returns(() => throwError(new ErrorDto(404, 'Referenced', 'OBJECT_REFERENCED')));
.returns(() => throwError(() => new ErrorDto(404, 'Referenced', 'OBJECT_REFERENCED')));
assetsService.setup(x => x.deleteAssetItem(app, asset1, true, asset1.version))
.returns(() => of(versioned(newVersion)));
@ -355,7 +355,7 @@ describe('AssetsState', () => {
it('should not remove asset if referenced and not confirmed', () => {
assetsService.setup(x => x.deleteAssetItem(app, asset1, true, asset1.version))
.returns(() => throwError(new ErrorDto(404, 'Referenced', 'OBJECT_REFERENCED')));
.returns(() => throwError(() => new ErrorDto(404, 'Referenced', 'OBJECT_REFERENCED')));
dialogs.setup(x => x.confirm(It.isAnyString(), It.isAnyString(), It.isAnyString()))
.returns(() => of(false));

6
frontend/app/shared/state/assets.state.ts

@ -254,7 +254,7 @@ export abstract class AssetsStateBase extends State<Snapshot> {
return { ...s, assets };
}, 'Asset Moving Failed');
return throwError(error);
return throwError(() => error);
}),
shareSubscribed(this.dialogs));
}
@ -278,7 +278,7 @@ export abstract class AssetsStateBase extends State<Snapshot> {
return { ...s, folders };
}, 'Folder Moving Done');
return throwError(error);
return throwError(() => error);
}),
shareSubscribed(this.dialogs));
}
@ -301,7 +301,7 @@ export abstract class AssetsStateBase extends State<Snapshot> {
}),
);
} else {
return throwError(error);
return throwError(() => error);
}
}),
tap(() => {

6
frontend/app/shared/state/backups.state.spec.ts

@ -52,7 +52,7 @@ describe('BackupsState', () => {
it('should reset loading state if loading failed', () => {
backupsService.setup(x => x.getBackups(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
backupsState.load().pipe(onErrorResumeNext()).subscribe();
@ -72,7 +72,7 @@ describe('BackupsState', () => {
it('should show notification on load error if silent is false', () => {
backupsService.setup(x => x.getBackups(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
backupsState.load(true, false).pipe(onErrorResumeNext()).subscribe();
@ -83,7 +83,7 @@ describe('BackupsState', () => {
it('should not show notification on load error if silent is true', () => {
backupsService.setup(x => x.getBackups(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
backupsState.load(true, true).pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/clients.state.spec.ts

@ -54,7 +54,7 @@ describe('ClientsState', () => {
it('should reset loading state if loading failed', () => {
clientsService.setup(x => x.getClients(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
clientsState.load().pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/contents.forms.visitors.ts

@ -128,7 +128,7 @@ export class FieldFormatter implements FieldPropertiesVisitor<FieldValue> {
}
public visitComponents(_: ComponentsFieldPropertiesDto): string {
return this.formatArray('Component', 'Component');
return this.formatArray('Component', 'Components');
}
public visitDateTime(properties: DateTimeFieldPropertiesDto): FieldValue {

6
frontend/app/shared/state/contributors.state.spec.ts

@ -63,7 +63,7 @@ describe('ContributorsState', () => {
it('should reset loading state if loading failed', () => {
contributorsService.setup(x => x.getContributors(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
contributorsState.load().pipe(onErrorResumeNext()).subscribe();
@ -152,7 +152,7 @@ describe('ContributorsState', () => {
const request = { contributorId: 'mail2stehle@gmail.com', role: 'Developer' };
contributorsService.setup(x => x.postContributor(app, request, version))
.returns(() => throwError(new ErrorDto(404, '404')));
.returns(() => throwError(() => new ErrorDto(404, '404')));
let error: ErrorDto;
@ -171,7 +171,7 @@ describe('ContributorsState', () => {
const request = { contributorId: 'mail2stehle@gmail.com', role: 'Developer' };
contributorsService.setup(x => x.postContributor(app, request, version))
.returns(() => throwError(new ErrorDto(500, '500')));
.returns(() => throwError(() => new ErrorDto(500, '500')));
let error: ErrorDto;

4
frontend/app/shared/state/contributors.state.ts

@ -127,9 +127,9 @@ export class ContributorsState extends State<Snapshot> {
return this.contributorsService.postContributor(this.appName, request, this.version).pipe(
catchError(error => {
if (Types.is(error, ErrorDto) && error.statusCode === 404) {
return throwError(new ErrorDto(404, 'i18n:contributors.userNotFound'));
return throwError(() => new ErrorDto(404, 'i18n:contributors.userNotFound'));
} else {
return throwError(error);
return throwError(() => error);
}
}),
tap(({ version, payload }) => {

2
frontend/app/shared/state/languages.state.spec.ts

@ -77,7 +77,7 @@ describe('LanguagesState', () => {
it('should reset loading state if loading failed', () => {
languagesService.setup(x => x.getLanguages(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
languagesState.load().pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/plans.state.spec.ts

@ -86,7 +86,7 @@ describe('PlansState', () => {
it('should reset loading state if loading failed', () => {
plansService.setup(x => x.getPlans(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
plansState.load().pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/roles.state.spec.ts

@ -50,7 +50,7 @@ describe('RolesState', () => {
it('should reset loading state if loading failed', () => {
rolesService.setup(x => x.getRoles(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
rolesState.load().pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/rule-events.state.spec.ts

@ -49,7 +49,7 @@ describe('RuleEventsState', () => {
it('should reset loading state if loading failed', () => {
rulesService.setup(x => x.getEvents(app, 30, 0, undefined))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
ruleEventsState.load().pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/rule-simulator.state.spec.ts

@ -54,7 +54,7 @@ describe('RuleSimulatorState', () => {
it('should reset loading state if loading failed', () => {
rulesService.setup(x => x.getSimulatedEvents(app, '12'))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
ruleSimulatorState.selectRule('12');
ruleSimulatorState.load().pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/rules.state.spec.ts

@ -66,7 +66,7 @@ describe('RulesState', () => {
it('should reset loading state if loading failed', () => {
rulesService.setup(x => x.getRules(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
rulesState.load().pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/schemas.state.spec.ts

@ -96,7 +96,7 @@ describe('SchemasState', () => {
it('should reset loading state if loading failed', () => {
schemasService.setup(x => x.getSchemas(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
schemasState.load().pipe(onErrorResumeNext()).subscribe();

2
frontend/app/shared/state/workflows.state.spec.ts

@ -54,7 +54,7 @@ describe('WorkflowsState', () => {
it('should reset loading state if loading failed', () => {
workflowsService.setup(x => x.getWorkflows(app))
.returns(() => throwError('Service Error'));
.returns(() => throwError(() => 'Service Error'));
workflowsState.load().pipe(onErrorResumeNext()).subscribe();

7
frontend/app/shims.ts

@ -9,6 +9,7 @@ import 'core-js/es/date';
import 'core-js/es/math';
import 'core-js/es/number';
import 'core-js/es/regexp';
// ES2015 array capabilities
import 'core-js/modules/es.array.copy-within';
import 'core-js/modules/es.array.every';
@ -30,11 +31,13 @@ import 'core-js/modules/es.array.reduce-right';
import 'core-js/modules/es.array.slice';
import 'core-js/modules/es.array.some';
import 'core-js/modules/es.array.sort';
// ES2015 function capabilities
import 'core-js/modules/es.function.bind';
import 'core-js/modules/es.function.has-instance';
import 'core-js/modules/es.function.name';
import 'core-js/modules/es.map';
// ES2015 object capabilities
import 'core-js/modules/es.object.assign';
import 'core-js/modules/es.object.create';
@ -57,6 +60,7 @@ import 'core-js/modules/es.parse-float';
import 'core-js/modules/es.parse-int';
import 'core-js/modules/es.promise';
import 'core-js/modules/es.set';
// ES2015 string capabilities
import 'core-js/modules/es.string.anchor';
import 'core-js/modules/es.string.big';
@ -80,9 +84,12 @@ import 'core-js/modules/es.string.strike';
import 'core-js/modules/es.string.sub';
import 'core-js/modules/es.string.sup';
import 'core-js/modules/es.string.trim';
// ES2015 symbol capabilities
import 'core-js/modules/es.symbol';
import 'core-js/modules/es.weak-map';
import 'core-js/modules/web.dom-collections.iterator';
import 'reflect-metadata';
import 'zone.js/dist/zone';

7633
frontend/package-lock.json

File diff suppressed because it is too large

122
frontend/package.json

@ -5,42 +5,42 @@
"license": "MIT",
"repository": "https://github.com/SebastianStehle/Squidex",
"scripts": {
"start": "webpack-dev-server --config app-config/webpack.config.js --inline --port 3000 --hot --https --pfx ../dev/squidex-dev.pfx --pfx-passphrase password",
"start": "webpack serve --config app-config/webpack.config.js --inline --port 3000 --hot --https --pfx ../dev/squidex-dev.pfx --pfx-passphrase password",
"test": "karma start",
"test:coverage": "karma start karma.coverage.conf.js",
"test:clean": "rimraf _test-output",
"tslint": "tslint -c tslint.json -p tsconfig.json app/**/*.ts",
"tslint-fix": "tslint -c tslint.json -p tsconfig.json app/**/*.ts -t verbose --fix",
"build": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js --config app-config/webpack.config.js --env.production",
"build": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js --config app-config/webpack.config.js --env production",
"build:clean": "rimraf wwwroot/build",
"build:analyze": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js --config app-config/webpack.config.js --env.production --env.analyze",
"postinstall": "ngcc --properties esm5 browser module main --first-only --create-ivy-entry-points"
"build:analyze": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js --config app-config/webpack.config.js --env production --env analyze",
"postinstall": "npx patch-package && ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points"
},
"dependencies": {
"@angular/animations": "11.2.10",
"@angular/cdk": "11.2.9",
"@angular/common": "11.2.10",
"@angular/core": "11.2.10",
"@angular/forms": "11.2.10",
"@angular/localize": "11.2.10",
"@angular/platform-browser": "11.2.10",
"@angular/platform-browser-dynamic": "11.2.10",
"@angular/platform-server": "11.2.10",
"@angular/router": "11.2.10",
"@angular/animations": "12.0.0",
"@angular/cdk": "12.0.0",
"@angular/common": "12.0.0",
"@angular/core": "12.0.0",
"@angular/forms": "12.0.0",
"@angular/localize": "12.0.0",
"@angular/platform-browser": "12.0.0",
"@angular/platform-browser-dynamic": "12.0.0",
"@angular/platform-server": "12.0.0",
"@angular/router": "12.0.0",
"@egjs/hammerjs": "2.0.17",
"ace-builds": "1.4.12",
"angular-gridster2": "11.1.5",
"angular-gridster2": "11.2.0",
"angular-mentions": "1.3.0",
"angular2-chartjs": "0.5.1",
"babel-polyfill": "6.26.0",
"bootstrap": "4.6.0",
"codemirror-graphql": "0.12.3",
"core-js": "3.10.1",
"codemirror-graphql": "1.0.1",
"core-js": "3.12.1",
"cropperjs": "2.0.0-alpha.1",
"date-fns": "2.21.1",
"date-fns": "2.21.3",
"font-awesome": "4.7.0",
"graphiql": "1.0.6",
"graphql": "15.4.0",
"graphiql": "1.4.1",
"graphql": "15.5.0",
"image-focus": "1.2.0",
"keycharm": "0.4.0",
"marked": "2.0.3",
@ -54,11 +54,11 @@
"prop-types": "15.7.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"rxjs": "6.6.7",
"rxjs": "7.0.1",
"sass": "^1.32.13",
"simplemde": "1.11.2",
"slugify": "1.5.0",
"tinymce": "5.7.1",
"slugify": "1.5.3",
"tinymce": "5.8.0",
"tslib": "2.2.0",
"video.js": "7.11.8",
"vis-data": "7.1.2",
@ -67,78 +67,78 @@
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-devkit/build-optimizer": "0.1102.9",
"@angular/compiler": "11.2.10",
"@angular/compiler-cli": "11.2.10",
"@ngtools/webpack": "11.2.9",
"@angular-devkit/build-optimizer": "0.1200.0",
"@angular/compiler": "12.0.0",
"@angular/compiler-cli": "12.0.0",
"@ngtools/webpack": "12.0.0",
"@types/codemirror": "0.0.108",
"@types/core-js": "2.5.4",
"@types/jasmine": "3.6.9",
"@types/jasmine": "3.7.4",
"@types/marked": "2.0.2",
"@types/mersenne-twister": "1.1.2",
"@types/mousetrap": "1.6.6",
"@types/node": "14.14.40",
"@types/react": "17.0.3",
"@types/react-dom": "17.0.3",
"@types/mousetrap": "1.6.8",
"@types/node": "15.3.0",
"@types/react": "17.0.5",
"@types/react-dom": "17.0.5",
"@types/simplemde": "1.11.7",
"@types/tapable": "1.0.6",
"@types/tinymce": "4.6.0",
"@types/tapable": "2.2.2",
"@types/tinymce": "4.6.1",
"@types/ws": "^7.4.4",
"@typescript-eslint/eslint-plugin": "^4.23.0",
"@typescript-eslint/parser": "^4.23.0",
"@types/ws": "^7.4.1",
"browserslist": "4.16.4",
"caniuse-lite": "1.0.30001208",
"browserslist": "4.16.6",
"caniuse-lite": "1.0.30001228",
"circular-dependency-plugin": "5.2.2",
"codelyzer": "6.0.1",
"copy-webpack-plugin": "6.3.1",
"css-loader": "5.2.1",
"cssnano": "5.0.1",
"codelyzer": "6.0.2",
"copy-webpack-plugin": "8.1.1",
"css-loader": "5.2.4",
"cssnano": "5.0.2",
"entities": "2.2.0",
"eslint": "^7.26.0",
"eslint-config-airbnb-typescript": "^12.3.1",
"eslint-plugin-import": "^2.23.0",
"eslint-plugin-import": "^2.23.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-webpack-plugin": "^2.5.4",
"file-loader": "6.2.0",
"html-loader": "1.3.2",
"html-webpack-plugin": "4.5.0",
"html-loader": "2.1.2",
"html-webpack-plugin": "5.3.1",
"ignore-loader": "0.1.2",
"istanbul-instrumenter-loader": "3.0.1",
"jasmine-core": "3.6.0",
"karma": "5.2.3",
"jasmine-core": "3.7.1",
"karma": "6.3.2",
"karma-chrome-launcher": "3.1.0",
"karma-cli": "2.0.0",
"karma-coverage-istanbul-reporter": "3.0.3",
"karma-htmlfile-reporter": "0.3.8",
"karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.5.4",
"karma-jasmine-html-reporter": "1.6.0",
"karma-mocha-reporter": "2.2.5",
"karma-sourcemap-loader": "0.3.8",
"karma-webpack": "4.0.2",
"mini-css-extract-plugin": "1.3.1",
"karma-webpack": "5.0.0",
"mini-css-extract-plugin": "1.6.0",
"optimize-css-assets-webpack-plugin": "5.0.4",
"postcss-import": "14.0.1",
"postcss-loader": "4.0.4",
"postcss-import": "14.0.2",
"postcss-loader": "5.3.0",
"postcss-preset-env": "6.7.0",
"raw-loader": "4.0.2",
"resize-observer-polyfill": "1.5.1",
"rimraf": "3.0.2",
"rxjs-tslint": "0.1.8",
"sass-lint": "1.13.1",
"sass-lint-webpack": "1.0.3",
"sass-loader": "10.1.0",
"sass-loader": "11.1.1",
"style-loader": "2.0.0",
"sugarss": "3.0.3",
"terser": "^5.6.1",
"terser-webpack-plugin": "4.2.3",
"ts-loader": "8.0.13",
"terser": "^5.7.0",
"terser-webpack-plugin": "5.1.2",
"ts-loader": "9.1.2",
"tsconfig-paths-webpack-plugin": "3.5.1",
"typemoq": "2.1.0",
"typescript": "4.0",
"typescript": "4.2.2",
"underscore": "1.13.1",
"webpack": "4.44.2",
"webpack-bundle-analyzer": "3.9.0",
"webpack-cli": "3.3.12",
"webpack-dev-server": "3.11.2"
"webpack": "5.37.0",
"webpack-bundle-analyzer": "4.4.1",
"webpack-cli": "4.7.0",
"webpack-dev-server": "3.11.2",
"webpack-filter-warnings-plugin": "^1.2.1"
}
}

19
frontend/patches/resize-observer-polyfill+1.5.1.patch

@ -0,0 +1,19 @@
diff --git a/node_modules/resize-observer-polyfill/src/index.d.ts b/node_modules/resize-observer-polyfill/src/index.d.ts
index 74aacc0..1b236d2 100644
--- a/node_modules/resize-observer-polyfill/src/index.d.ts
+++ b/node_modules/resize-observer-polyfill/src/index.d.ts
@@ -1,14 +1,3 @@
-interface DOMRectReadOnly {
- readonly x: number;
- readonly y: number;
- readonly width: number;
- readonly height: number;
- readonly top: number;
- readonly right: number;
- readonly bottom: number;
- readonly left: number;
-}
-
declare global {
interface ResizeObserverCallback {
(entries: ResizeObserverEntry[], observer: ResizeObserver): void

6
frontend/postcss.config.js

@ -1,5 +1,5 @@
module.exports = {
plugins: {
'postcss-preset-env': {}
}
}
'postcss-preset-env': {},
},
};

5
frontend/tsconfig.spec.json

@ -1,7 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"types": ["node", "jasmine"]
"types": [
"node",
"jasmine"
]
},
"include": [
"app/**/*.d.ts",

151
frontend/tslint.json

@ -1,151 +0,0 @@
{
"extends": ["tslint-immutable"],
"rulesDirectory": [
"node_modules/codelyzer",
"node_modules/rxjs-tslint"
],
"rules": {
"angular-whitespace": false,
"arrow-return-shorthand": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"component-class-suffix": true,
"component-selector": [
true,
"element",
"sqx",
"kebab-case"
],
"curly": true,
"directive-class-suffix": true,
"directive-selector": [
true,
"attribute",
"sqx",
"camelCase"
],
"eofline": false,
"forin": true,
"indent": [
true,
"spaces"
],
"label-position": true,
"max-line-length": [
true,
240
],
"member-access": [
true,
"check-accessor"
],
"no-access-missing-member": false,
"no-arg": true,
"no-bitwise": true,
"no-consecutive-blank-lines": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-forward-ref": false,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-input-rename": false,
"no-output-rename": false,
"no-pipe-impure": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-callback-wrapper": true,
"no-unused-expression": true,
"no-use-before-declare": false,
"no-var-keyword": true,
"object-literal-shorthand": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"only-arrow-functions": [
true,
"allow-declarations"
],
"ordered-imports": [
true
],
"pipe-prefix": [
true,
"sqx"
],
"prefer-const": true,
"prefer-for-of": true,
"prefer-template": true,
"quotemark": [
true,
"single"
],
"radix": true,
"readonly-array": [
true,
"ignore-local"
],
"rxjs-collapse-imports": true,
"rxjs-proper-imports": true,
"semicolon": [
true,
"always"
],
"template-no-negated-async": true,
"template-use-track-by-function": false,
"trailing-comma": [
true,
{
"multiline": "never",
"singleline": "never"
}
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
]
}
}
Loading…
Cancel
Save