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. 37
      frontend/app-config/karma.conf.js
  4. 53
      frontend/app-config/karma.coverage.conf.js
  5. 244
      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. 2
      frontend/karma.conf.js
  49. 2
      frontend/karma.coverage.conf.js
  50. 7633
      frontend/package-lock.json
  51. 122
      frontend/package.json
  52. 19
      frontend/patches/resize-observer-polyfill+1.5.1.patch
  53. 6
      frontend/postcss.config.js
  54. 5
      frontend/tsconfig.spec.json
  55. 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 # Stage 2, Build Frontend
# #
FROM buildkite/puppeteer:5.2.1 as frontend FROM buildkite/puppeteer:8.0.0 as frontend
WORKDIR /src WORKDIR /src
ENV CONTINUOUS_INTEGRATION=1
# Copy Node project files. # Copy Node project files.
COPY frontend/package*.json /tmp/ COPY frontend/package*.json /tmp/
# Copy patches for broken npm packages
COPY frontend/patches /tmp/patches
RUN cd /tmp/patches && dir
# Install Node packages # Install Node packages
RUN cd /tmp && npm install --loglevel=error RUN cd /tmp && npm set unsafe-perm true && npm install --loglevel=error
COPY frontend . COPY frontend .
@ -68,8 +75,10 @@ RUN apt-get update \
# Default AspNetCore directory # Default AspNetCore directory
WORKDIR /app WORKDIR /app
# Copy from build stages # Copy from backend build stages
COPY --from=backend /build/ . COPY --from=backend /build/ .
# Copy from backend build stages to webserver folder
COPY --from=frontend /build/ wwwroot/build/ COPY --from=frontend /build/ wwwroot/build/
EXPOSE 80 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'); require('core-js/proposals/reflect-metadata');
@ -12,7 +10,7 @@ const browser = require('@angular/platform-browser-dynamic/testing');
testing.getTestBed().initTestEnvironment( testing.getTestBed().initTestEnvironment(
browser.BrowserDynamicTestingModule, browser.BrowserDynamicTestingModule,
browser.platformBrowserDynamicTesting() browser.platformBrowserDynamicTesting(),
); );
// Then we find all the tests. // Then we find all the tests.

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

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

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

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

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

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', () => { it('should reset loading state if loading failed', () => {
eventConsumersService.setup(x => x.getEventConsumers()) eventConsumersService.setup(x => x.getEventConsumers())
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
eventConsumersState.load().pipe(onErrorResumeNext()).subscribe(); eventConsumersState.load().pipe(onErrorResumeNext()).subscribe();
@ -68,7 +68,7 @@ describe('EventConsumersState', () => {
it('should show notification on load error if silent is false', () => { it('should show notification on load error if silent is false', () => {
eventConsumersService.setup(x => x.getEventConsumers()) eventConsumersService.setup(x => x.getEventConsumers())
.returns(() => throwError('Service Error')).verifiable(); .returns(() => throwError(() => 'Service Error')).verifiable();
eventConsumersState.load(true, false).pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
usersService.setup(x => x.getUsers(10, 0, undefined)) usersService.setup(x => x.getUsers(10, 0, undefined))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
usersState.load().pipe(onErrorResumeNext()).subscribe(); usersState.load().pipe(onErrorResumeNext()).subscribe();
@ -136,7 +136,7 @@ describe('UsersState', () => {
it('should return null on select if user is not found', () => { it('should return null on select if user is not found', () => {
usersService.setup(x => x.getUser('unknown')) usersService.setup(x => x.getUser('unknown'))
.returns(() => throwError('Service Error')).verifiable(); .returns(() => throwError(() => 'Service Error')).verifiable();
let userSelected: UserDto; 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 { 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 { Subscriber } from 'rxjs';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
@ -54,8 +54,10 @@ export class ConfirmClickDirective {
for (const observer of observers) { for (const observer of observers) {
const subscriber = observer as Subscriber<any>; const subscriber = observer as Subscriber<any>;
if (subscriber['destination'] && subscriber['destination'].next) { const internal = (subscriber as any).destination;
subscriber['destination'].next(true);
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.aceEditor.on('change', () => {
this.valueChanged.next(); this.valueChanged.next(true);
}); });
this.detach(); 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() { public callTouched() {
this.blur.next(); this.blur.next(true);
super.callTouched(); 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() { public callTouched() {
this.blur.next(); this.blur.next(true);
super.callTouched(); super.callTouched();
} }

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

@ -89,10 +89,10 @@ export module ValidatorsEx {
const value = parseFloat(control.value); const value = parseFloat(control.value);
if (min === max) { if (min === max) {
if (Number.isNaN(value) || value !== min) { if (!Types.isNumber(value) || Number.isNaN(value) || value !== min) {
return { exactly: { expected: min, actual: value } }; 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 } }; return { between: { min, max, actual: value } };
} }
@ -119,10 +119,10 @@ export module ValidatorsEx {
const length: number = control.value?.length || 0; const length: number = control.value?.length || 0;
if (minLength === maxLength) { if (minLength === maxLength) {
if (Number.isNaN(length) || length !== minLength) { if (!Types.isNumber(length) || Number.isNaN(length) || length !== minLength) {
return { exactlylength: { expected: minLength, actual: length } }; 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 } }; 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) { if (Types.is(error, HttpErrorResponse) && error.status === 304 && cacheEntry) {
return of(cacheEntry); return of(cacheEntry);
} else { } else {
return throwError(error); return throwError(() => error);
} }
})); }));
} else { } 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) => { source.pipe(catchError((response: HttpErrorResponse) => {
const error = parseError(response, message); const error = parseError(response, message);
return throwError(error); return throwError(() => error);
})); }));
export function parseError(response: HttpErrorResponse, fallback: string) { 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); 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); 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; pageSize = this.defaultSize;
} }
let page = parseInt(query['page'], 10); let page = parseInt(query['page'], 10);
if (page <= 0 || Number.isNaN(page)) { if (page <= 0 || !Types.isNumber(page) || Number.isNaN(page)) {
page = 0; 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, () => { this.shortcutService.on(this.lastKeys, () => {
if (!this.disabled) { if (!this.disabled) {
this.zone.run(() => { 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)); this.notify(Notification.error(error));
} }
return throwError(error); return throwError(() => error);
} }
public notifyInfo(text: string) { 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) { public listen(target: Element, listener: ResizeListener) {
if (!this.observer) { if (!this.observer) {
this.observer = new ResizeObserver(entries => { this.observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
for (const entry of entries) { for (const entry of entries) {
if (this.listeners.has(entry.target)) { if (this.listeners.has(entry.target)) {
const component = this.listeners.get(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 { 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 { DateHelper } from './date-helper';
import { Types } from './types';
const DATE_FORMAT = 'yyyy-MM-dd'; const DATE_FORMAT = 'yyyy-MM-dd';
@ -98,7 +99,9 @@ export class DateTime {
date = parseISO(value); date = parseISO(value);
} }
if (Number.isNaN(date.getTime())) { const time = date.getTime();
if (Number.isNaN(time) || !Types.isNumber(time)) {
return null; return null;
} }

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

@ -50,7 +50,7 @@ describe('ErrorDto', () => {
expect(result).toBe('error.\n\n * detail.\n'); 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 error = new ErrorDto(500, 'i18n:error.', null, ['i18n:detail.']);
const result = error.translate(localizer.object); 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. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { EMPTY, Observable, throwError } from 'rxjs'; import { EMPTY, Observable, ReplaySubject, throwError } from 'rxjs';
import { catchError, distinctUntilChanged, filter, map, onErrorResumeNext, publishReplay, refCount, switchMap } from 'rxjs/operators'; import { catchError, distinctUntilChanged, filter, map, onErrorResumeNext, share, switchMap } from 'rxjs/operators';
import { DialogService } from './../services/dialog.service'; import { DialogService } from './../services/dialog.service';
import { Version, versioned, Versioned } from './version'; 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) { export function shareMapSubscribed<T, R = T>(dialogs: DialogService, project: (value: T) => R, options?: Options) {
return function mapOperation(source: Observable<T>) { 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( shared.pipe(
catchError(error => { catchError(error => {
@ -35,7 +40,7 @@ export function shareMapSubscribed<T, R = T>(dialogs: DialogService, project: (v
} }
if (options?.throw) { if (options?.throw) {
return throwError(error); return throwError(() => error);
} }
return EMPTY; return EMPTY;
@ -54,7 +59,7 @@ export function defined<T>() {
export function switchSafe<T, R>(project: (source: T) => Observable<R>) { export function switchSafe<T, R>(project: (source: T) => Observable<R>) {
return function mapOperation(source: Observable<T>) { 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; return EMPTY;
} else { } 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 => { catchError(error => {
if (Types.is(error, HttpErrorResponse) && error.status === 413) { 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 { } else {
return throwError(error); return throwError(() => error);
} }
}), }),
tap(value => { tap(value => {

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

@ -296,9 +296,9 @@ export class AssetsService {
}), }),
catchError((error: any) => { catchError((error: any) => {
if (Types.is(error, HttpErrorResponse) && error.status === 413) { 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 { } else {
return throwError(error); return throwError(() => error);
} }
}), }),
tap(value => { tap(value => {
@ -331,9 +331,9 @@ export class AssetsService {
}), }),
catchError(error => { catchError(error => {
if (Types.is(error, HttpErrorResponse) && error.status === 413) { 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 { } else {
return throwError(error); return throwError(() => error);
} }
}), }),
tap(value => { tap(value => {

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

@ -168,10 +168,10 @@ export class AuthService {
retryWhen(errors => retryWhen(errors =>
concat( concat(
errors.pipe( errors.pipe(
mergeMap(e => (Types.is(e, TimeoutError) ? of(e) : throwError(e))), mergeMap(e => (Types.is(e, TimeoutError) ? of(e) : throwError(() => e))),
delay(500), delay(500),
take(5)), 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) { if (Types.is(error, HttpErrorResponse) && error.status === 404) {
return of(null); return of(null);
} else { } else {
return throwError(error); return throwError(() => error);
} }
}), }),
pretifyError('i18n:backups.loadFailed')); 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', () => { it('should throw if creating invalid property type', () => {
const type: any = 'invalid'; const type: any = 'invalid';
expect(() => createProperties(type)).toThrow('Invalid properties type'); expect(() => createProperties(type)).toThrowError();
}); });
it('should make get request to get schemas', 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': case 'UI':
properties = new UIFieldPropertiesDto(); properties = new UIFieldPropertiesDto();
break; break;
default:
throw new Error(`Unknown field type ${fieldType}.`);
} }
if (values) { 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' } })); .returns(() => new Profile(<any>{ profile: { sub: '123' } }));
usersService.setup(x => x.getUser('123')) usersService.setup(x => x.getUser('123'))
.returns(() => throwError('Service Error')).verifiable(Times.once()); .returns(() => throwError(() => 'Service Error')).verifiable(Times.once());
let resultingUser: UserDto; let resultingUser: UserDto;

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

@ -108,7 +108,7 @@ describe('AppsState', () => {
let appSelected: AppDto; let appSelected: AppDto;
appsService.setup(x => x.getApp('unknown')) appsService.setup(x => x.getApp('unknown'))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
appsState.select('unknown').pipe(onErrorResumeNext()).subscribe(x => { appsState.select('unknown').pipe(onErrorResumeNext()).subscribe(x => {
appSelected = 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' }; const file: File = <any>{ name: 'my-file' };
assetsService.setup(x => x.postAssetFile(app, file, undefined)) assetsService.setup(x => x.postAssetFile(app, file, undefined))
.returns(() => throwError('Service Error')).verifiable(); .returns(() => throwError(() => 'Service Error')).verifiable();
assetUploader.uploadFile(file).pipe(onErrorResumeNext()).subscribe(); assetUploader.uploadFile(file).pipe(onErrorResumeNext()).subscribe();
@ -148,7 +148,7 @@ describe('AssetUploaderState', () => {
const file: File = <any>{ name: 'my-file' }; const file: File = <any>{ name: 'my-file' };
assetsService.setup(x => x.putAssetFile(app, asset, file, asset.version)) 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(); 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' }; const request = { parentId: 'newParent' };
assetsService.setup(x => x.putAssetItemParent(app, asset1, It.isValue(request), asset1.version)) 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(); assetsState.moveAsset(asset1, request.parentId).pipe(onErrorResumeNext()).subscribe();
@ -318,7 +318,7 @@ describe('AssetsState', () => {
const request = { parentId: 'newParent' }; const request = { parentId: 'newParent' };
assetsService.setup(x => x.putAssetItemParent(app, assetFolder1, It.isValue(request), assetFolder1.version)) 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(); 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', () => { it('should remove asset from snapshot if when referenced and not confirmed', () => {
assetsService.setup(x => x.deleteAssetItem(app, asset1, false, asset1.version)) 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)) assetsService.setup(x => x.deleteAssetItem(app, asset1, true, asset1.version))
.returns(() => of(versioned(newVersion))); .returns(() => of(versioned(newVersion)));
@ -355,7 +355,7 @@ describe('AssetsState', () => {
it('should not remove asset if referenced and not confirmed', () => { it('should not remove asset if referenced and not confirmed', () => {
assetsService.setup(x => x.deleteAssetItem(app, asset1, true, asset1.version)) 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())) dialogs.setup(x => x.confirm(It.isAnyString(), It.isAnyString(), It.isAnyString()))
.returns(() => of(false)); .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 }; return { ...s, assets };
}, 'Asset Moving Failed'); }, 'Asset Moving Failed');
return throwError(error); return throwError(() => error);
}), }),
shareSubscribed(this.dialogs)); shareSubscribed(this.dialogs));
} }
@ -278,7 +278,7 @@ export abstract class AssetsStateBase extends State<Snapshot> {
return { ...s, folders }; return { ...s, folders };
}, 'Folder Moving Done'); }, 'Folder Moving Done');
return throwError(error); return throwError(() => error);
}), }),
shareSubscribed(this.dialogs)); shareSubscribed(this.dialogs));
} }
@ -301,7 +301,7 @@ export abstract class AssetsStateBase extends State<Snapshot> {
}), }),
); );
} else { } else {
return throwError(error); return throwError(() => error);
} }
}), }),
tap(() => { tap(() => {

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

@ -52,7 +52,7 @@ describe('BackupsState', () => {
it('should reset loading state if loading failed', () => { it('should reset loading state if loading failed', () => {
backupsService.setup(x => x.getBackups(app)) backupsService.setup(x => x.getBackups(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
backupsState.load().pipe(onErrorResumeNext()).subscribe(); backupsState.load().pipe(onErrorResumeNext()).subscribe();
@ -72,7 +72,7 @@ describe('BackupsState', () => {
it('should show notification on load error if silent is false', () => { it('should show notification on load error if silent is false', () => {
backupsService.setup(x => x.getBackups(app)) backupsService.setup(x => x.getBackups(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
backupsState.load(true, false).pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should not show notification on load error if silent is true', () => {
backupsService.setup(x => x.getBackups(app)) backupsService.setup(x => x.getBackups(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
backupsState.load(true, true).pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
clientsService.setup(x => x.getClients(app)) clientsService.setup(x => x.getClients(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
clientsState.load().pipe(onErrorResumeNext()).subscribe(); 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 { public visitComponents(_: ComponentsFieldPropertiesDto): string {
return this.formatArray('Component', 'Component'); return this.formatArray('Component', 'Components');
} }
public visitDateTime(properties: DateTimeFieldPropertiesDto): FieldValue { 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', () => { it('should reset loading state if loading failed', () => {
contributorsService.setup(x => x.getContributors(app)) contributorsService.setup(x => x.getContributors(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
contributorsState.load().pipe(onErrorResumeNext()).subscribe(); contributorsState.load().pipe(onErrorResumeNext()).subscribe();
@ -152,7 +152,7 @@ describe('ContributorsState', () => {
const request = { contributorId: 'mail2stehle@gmail.com', role: 'Developer' }; const request = { contributorId: 'mail2stehle@gmail.com', role: 'Developer' };
contributorsService.setup(x => x.postContributor(app, request, version)) contributorsService.setup(x => x.postContributor(app, request, version))
.returns(() => throwError(new ErrorDto(404, '404'))); .returns(() => throwError(() => new ErrorDto(404, '404')));
let error: ErrorDto; let error: ErrorDto;
@ -171,7 +171,7 @@ describe('ContributorsState', () => {
const request = { contributorId: 'mail2stehle@gmail.com', role: 'Developer' }; const request = { contributorId: 'mail2stehle@gmail.com', role: 'Developer' };
contributorsService.setup(x => x.postContributor(app, request, version)) contributorsService.setup(x => x.postContributor(app, request, version))
.returns(() => throwError(new ErrorDto(500, '500'))); .returns(() => throwError(() => new ErrorDto(500, '500')));
let error: ErrorDto; 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( return this.contributorsService.postContributor(this.appName, request, this.version).pipe(
catchError(error => { catchError(error => {
if (Types.is(error, ErrorDto) && error.statusCode === 404) { 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 { } else {
return throwError(error); return throwError(() => error);
} }
}), }),
tap(({ version, payload }) => { 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', () => { it('should reset loading state if loading failed', () => {
languagesService.setup(x => x.getLanguages(app)) languagesService.setup(x => x.getLanguages(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
languagesState.load().pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
plansService.setup(x => x.getPlans(app)) plansService.setup(x => x.getPlans(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
plansState.load().pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
rolesService.setup(x => x.getRoles(app)) rolesService.setup(x => x.getRoles(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
rolesState.load().pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
rulesService.setup(x => x.getEvents(app, 30, 0, undefined)) rulesService.setup(x => x.getEvents(app, 30, 0, undefined))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
ruleEventsState.load().pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
rulesService.setup(x => x.getSimulatedEvents(app, '12')) rulesService.setup(x => x.getSimulatedEvents(app, '12'))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
ruleSimulatorState.selectRule('12'); ruleSimulatorState.selectRule('12');
ruleSimulatorState.load().pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
rulesService.setup(x => x.getRules(app)) rulesService.setup(x => x.getRules(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
rulesState.load().pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
schemasService.setup(x => x.getSchemas(app)) schemasService.setup(x => x.getSchemas(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
schemasState.load().pipe(onErrorResumeNext()).subscribe(); 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', () => { it('should reset loading state if loading failed', () => {
workflowsService.setup(x => x.getWorkflows(app)) workflowsService.setup(x => x.getWorkflows(app))
.returns(() => throwError('Service Error')); .returns(() => throwError(() => 'Service Error'));
workflowsState.load().pipe(onErrorResumeNext()).subscribe(); 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/math';
import 'core-js/es/number'; import 'core-js/es/number';
import 'core-js/es/regexp'; import 'core-js/es/regexp';
// ES2015 array capabilities // ES2015 array capabilities
import 'core-js/modules/es.array.copy-within'; import 'core-js/modules/es.array.copy-within';
import 'core-js/modules/es.array.every'; 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.slice';
import 'core-js/modules/es.array.some'; import 'core-js/modules/es.array.some';
import 'core-js/modules/es.array.sort'; import 'core-js/modules/es.array.sort';
// ES2015 function capabilities // ES2015 function capabilities
import 'core-js/modules/es.function.bind'; import 'core-js/modules/es.function.bind';
import 'core-js/modules/es.function.has-instance'; import 'core-js/modules/es.function.has-instance';
import 'core-js/modules/es.function.name'; import 'core-js/modules/es.function.name';
import 'core-js/modules/es.map'; import 'core-js/modules/es.map';
// ES2015 object capabilities // ES2015 object capabilities
import 'core-js/modules/es.object.assign'; import 'core-js/modules/es.object.assign';
import 'core-js/modules/es.object.create'; 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.parse-int';
import 'core-js/modules/es.promise'; import 'core-js/modules/es.promise';
import 'core-js/modules/es.set'; import 'core-js/modules/es.set';
// ES2015 string capabilities // ES2015 string capabilities
import 'core-js/modules/es.string.anchor'; import 'core-js/modules/es.string.anchor';
import 'core-js/modules/es.string.big'; 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.sub';
import 'core-js/modules/es.string.sup'; import 'core-js/modules/es.string.sup';
import 'core-js/modules/es.string.trim'; import 'core-js/modules/es.string.trim';
// ES2015 symbol capabilities // ES2015 symbol capabilities
import 'core-js/modules/es.symbol'; import 'core-js/modules/es.symbol';
import 'core-js/modules/es.weak-map'; import 'core-js/modules/es.weak-map';
import 'core-js/modules/web.dom-collections.iterator'; import 'core-js/modules/web.dom-collections.iterator';
import 'reflect-metadata'; import 'reflect-metadata';
import 'zone.js/dist/zone'; import 'zone.js/dist/zone';

2
frontend/karma.conf.js

@ -1 +1 @@
module.exports = require('./app-config/karma.conf.js'); module.exports = require('./app-config/karma.conf.js');

2
frontend/karma.coverage.conf.js

@ -1 +1 @@
module.exports = require('./app-config/karma.coverage.conf.js'); module.exports = require('./app-config/karma.coverage.conf.js');

7633
frontend/package-lock.json

File diff suppressed because it is too large

122
frontend/package.json

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

5
frontend/tsconfig.spec.json

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