Browse Source

Merge branch 'next' of github.com:Squidex/squidex into next

pull/372/head
Sebastian Stehle 7 years ago
parent
commit
31a666dea1
  1. 36
      src/Squidex/.vscode/settings.json
  2. 25
      src/Squidex/app-config/helpers.js
  3. 3
      src/Squidex/app-config/karma-test-shim.js
  4. 6
      src/Squidex/app-config/karma.conf.js
  5. 6
      src/Squidex/app-config/karma.coverage.conf.js
  6. 446
      src/Squidex/app-config/webpack.config.js
  7. 35
      src/Squidex/app-config/webpack.run.base.js
  8. 68
      src/Squidex/app-config/webpack.run.dev.js
  9. 137
      src/Squidex/app-config/webpack.run.prod.js
  10. 37
      src/Squidex/app-config/webpack.test.coverage.js
  11. 16
      src/Squidex/app-config/webpack.test.js
  12. 18
      src/Squidex/app/app.routes.ts
  13. 2
      src/Squidex/app/features/api/pages/graphql/graphql-page.component.ts
  14. 2
      src/Squidex/app/features/apps/pages/apps-page.component.scss
  15. 2
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  16. 2
      src/Squidex/app/features/content/pages/contents/contents-page.component.ts
  17. 4
      src/Squidex/app/features/content/pages/schemas/schemas-page.component.html
  18. 10
      src/Squidex/app/features/content/pages/schemas/schemas-page.component.ts
  19. 8
      src/Squidex/app/features/rules/pages/rules/rule-element.component.scss
  20. 2
      src/Squidex/app/features/schemas/pages/schema/field-wizard.component.ts
  21. 5
      src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.html
  22. 5
      src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts
  23. 2
      src/Squidex/app/features/settings/pages/roles/role.component.ts
  24. 4
      src/Squidex/app/framework/angular/forms/autocomplete.component.ts
  25. 2
      src/Squidex/app/framework/angular/forms/code-editor.component.ts
  26. 2
      src/Squidex/app/framework/angular/forms/date-time-editor.component.ts
  27. 2
      src/Squidex/app/framework/angular/forms/iframe-editor.component.ts
  28. 2
      src/Squidex/app/framework/angular/forms/json-editor.component.ts
  29. 4
      src/Squidex/app/framework/angular/forms/tag-editor.component.ts
  30. 4
      src/Squidex/app/framework/angular/modals/modal-dialog.component.ts
  31. 2
      src/Squidex/app/framework/angular/modals/root-view.component.ts
  32. 2
      src/Squidex/app/framework/angular/panel.component.ts
  33. 4
      src/Squidex/app/shared/components/geolocation-editor.component.ts
  34. 6
      src/Squidex/app/shared/components/markdown-editor.component.ts
  35. 2
      src/Squidex/app/shared/components/rich-editor.component.ts
  36. 24
      src/Squidex/app/shared/components/schema-category.component.html
  37. 68
      src/Squidex/app/shared/components/schema-category.component.ts
  38. 61
      src/Squidex/app/shared/state/schemas.state.spec.ts
  39. 73
      src/Squidex/app/shared/state/schemas.state.ts
  40. 2
      src/Squidex/app/shell/pages/internal/internal-area.component.scss
  41. 103
      src/Squidex/app/shims.ts
  42. 2
      src/Squidex/app/theme/_bootstrap.scss
  43. 2897
      src/Squidex/package-lock.json
  44. 81
      src/Squidex/package.json
  45. 1
      src/Squidex/tsconfig.json

36
src/Squidex/.vscode/settings.json

@ -1,36 +0,0 @@
{
// When opening a file, `editor.tabSize` and `editor.insertSpaces` will be detected based on the file contents.
"editor.detectIndentation": false,
// Typescript version from local package to be consistent
"typescript.tsdk": "node_modules/typescript/lib",
// Configure glob patterns for excluding files and folders.
"files.exclude": {
"**/node_modules": true,
"**/Assets": true,
"**/artifacts": true,
"**/build": true,
"**/logs": true,
"**/out": true,
"**/obj": true,
"**/bin": true,
"**/*.lock.json": true,
"**/*.bat": true,
"**/*.sln": true,
"**/*.sln.DotSettings": true,
"**/*.user": true,
"**/*.xproj": true,
"**/*.gitattributes": true,
"appsetttings.Development.json": true,
"appsetttings.Production.json": true,
".awcache": true,
".vs:": true,
".vscode:": true
},
"coverage-gutters.coverageFileNames": [
"_test-output/coverage/lcov.info"
],
"coverage-gutters.showLineCoverage": true
}

25
src/Squidex/app-config/helpers.js

@ -1,25 +0,0 @@
var path = require('path');
var appRoot = path.resolve(__dirname, '..');
exports.root = function () {
var newArgs = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [appRoot].concat(newArgs));
};
exports.removeLoaders = function (config, extensions) {
var rules = config.module.rules;
for (var i = 0; i < rules.length; i += 1) {
var rule = rules[i];
for (var j = 0; j < extensions.length; j += 1) {
if (rule.test.source.indexOf(extensions[j]) >= 0) {
rules.splice(i, 1);
i--;
break;
}
}
}
}

3
src/Squidex/app-config/karma-test-shim.js

@ -1,7 +1,6 @@
Error.stackTraceLimit = Infinity;
require('core-js/es6');
require('core-js/es7/reflect');
require('core-js/proposals/reflect-metadata');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');

6
src/Squidex/app-config/karma.conf.js

@ -1,4 +1,4 @@
var webpackConfig = require('./webpack.test');
const webpackConfig = require('./webpack.config');
module.exports = function (config) {
var _config = {
@ -10,7 +10,7 @@ module.exports = function (config) {
frameworks: ['jasmine'],
/**
* Load additional test shim to setup angular2 for testing.
* Load additional test shim to setup angular for testing.
*/
files: [
{ pattern: './app-config/karma-test-shim.js', watched: false }
@ -23,7 +23,7 @@ module.exports = function (config) {
/**
* Load the files with webpack and use test configuration for it.
*/
webpack: webpackConfig,
webpack: webpackConfig({ target: 'tests', jit: true }),
webpackMiddleware: {
stats: 'errors-only'

6
src/Squidex/app-config/karma.coverage.conf.js

@ -1,4 +1,4 @@
var webpackConfig = require('./webpack.test.coverage');
const webpackConfig = require('./webpack.config');
module.exports = function (config) {
var _config = {
@ -10,7 +10,7 @@ module.exports = function (config) {
frameworks: ['jasmine'],
/**
* Load additional test shim to setup angular2 for testing.
* Load additional test shim to setup angular for testing.
*/
files: [
{ pattern: './app-config/karma-test-shim.js', watched: false }
@ -23,7 +23,7 @@ module.exports = function (config) {
/**
* Load the files with webpack and use test configuration for it.
*/
webpack: webpackConfig,
webpack: webpackConfig({ target: 'tests', coverage: true, jit: true }),
webpackMiddleware: {
stats: 'errors-only'

446
src/Squidex/app-config/webpack.config.js

@ -1,6 +1,13 @@
const webpack = require('webpack'),
path = require('path'),
helpers = require('./helpers');
path = require('path');
const appRoot = path.resolve(__dirname, '..');
function root() {
var newArgs = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [appRoot].concat(newArgs));
};
const plugins = {
// https://github.com/webpack-contrib/mini-css-extract-plugin
@ -8,147 +15,356 @@ const plugins = {
// https://github.com/dividab/tsconfig-paths-webpack-plugin
TsconfigPathsPlugin: require('tsconfig-paths-webpack-plugin'),
// https://github.com/aackerman/circular-dependency-plugin
CircularDependencyPlugin: require('circular-dependency-plugin')
CircularDependencyPlugin: require('circular-dependency-plugin'),
// https://github.com/jantimon/html-webpack-plugin
HtmlWebpackPlugin: require('html-webpack-plugin'),
// https://github.com/mishoo/UglifyJS2/tree/harmony
UglifyJsPlugin: require('uglifyjs-webpack-plugin'),
// 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"),
// https://github.com/jrparish/tslint-webpack-plugin
TsLintPlugin: require('tslint-webpack-plugin')
};
const isDevServer = path.basename(require.main.filename) === 'webpack-dev-server.js';
module.exports = function(env) {
const isDevServer = path.basename(require.main.filename) === 'webpack-dev-server.js';
const isProduction = env && env.production;
const isTesting = env && env.target === 'tests';
const isCoverage = env && env.coverage;
const isJit = env && env.jit;
const config = {
mode: isProduction ? 'production' : 'development',
module.exports = {
/**
* 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.
* Source map for Karma from the help of karma-sourcemap-loader & karma-webpack.
*
* See: https://webpack.js.org/configuration/resolve/#resolve-extensions
* See: https://webpack.js.org/configuration/devtool/
*/
extensions: ['.js', '.mjs', '.ts', '.css', '.scss'],
modules: [
helpers.root('app'),
helpers.root('app', 'theme'),
helpers.root('node_modules')
],
devtool: isProduction ? undefined : (isTesting ? 'inline-source-map' : '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
*/
extensions: ['.js', '.mjs', '.ts', '.css', '.scss'],
modules: [
root('app'),
root('app', 'theme'),
root('node_modules')
],
plugins: [
new plugins.TsconfigPathsPlugin()
]
},
/**
* 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/]
}, {
test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
include: [/node_modules/]
}, {
test: /\.js\.flow$/,
use: [{
loader: 'ignore-loader'
}],
include: [/node_modules/]
}, {
test: /\.html$/,
use: [{
loader: 'raw-loader'
}]
}, {
test: /\.(woff|woff2|ttf|eot)(\?.*$|$)/,
use: [{
loader: 'file-loader?name=[name].[hash].[ext]',
options: {
outputPath: 'assets',
/*
* Use custom public path as ./ is not supported by fonts.
*/
publicPath: isDevServer ? undefined : 'assets'
}
}]
}, {
test: /\.(png|jpe?g|gif|svg|ico)(\?.*$|$)/,
use: [{
loader: 'file-loader?name=[name].[hash].[ext]',
options: {
outputPath: 'assets'
}
}]
}, {
test: /\.css$/,
use: [
plugins.MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
}]
}, {
test: /\.scss$/,
use: [{
loader: 'raw-loader'
}, {
loader: 'sass-loader', options: { includePaths: [root('app', 'theme')] }
}],
exclude: root('app', 'theme')
}]
},
plugins: [
new plugins.TsconfigPathsPlugin()
]
},
/**
* Options affecting the normal modules.
*
* See: https://webpack.js.org/configuration/module/
*/
module: {
new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)fesm5/, root('./app'), {}),
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/),
/**
* 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('[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')
},
context: '/'
}
}),
/**
* Detect circular dependencies in app.
*
* See: https://github.com/aackerman/circular-dependency-plugin
*/
new plugins.CircularDependencyPlugin({
exclude: /([\\\/]node_modules[\\\/])|(ngfactory\.js$)/,
// Add errors to webpack instead of warnings
failOnError: true
}),
],
devServer: {
headers: {
'Access-Control-Allow-Origin': '*'
},
historyApiFallback: true
}
};
if (!isTesting) {
/**
* An array of Rules which are matched to requests when modules are created.
* The entry point for the bundle. Our Angular app.
*
* See: https://webpack.js.org/configuration/module/#module-rules
* See: https://webpack.js.org/configuration/entry-context/
*/
rules: [{
test: /\.mjs$/,
type: "javascript/auto",
include: [/node_modules/]
}, {
test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
include: [/node_modules/]
}, {
config.entry = {
'shims': './app/shims.ts',
'app': './app/app.ts'
};
if (isProduction) {
config.output = {
/**
* The output directory as absolute path (required).
*
* See: https://webpack.js.org/configuration/output/#output-path
*/
path: root('wwwroot/build/'),
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'
};
} else {
config.output = {
filename: '[name].js',
/**
* Set the public path, because we are running the website from another port (5000).
*/
publicPath: 'http://localhost:3000/'
};
}
config.plugins.push(
new plugins.HtmlWebpackPlugin({
hash: true,
chunks: ['shims', 'app'],
chunksSortMode: 'manual',
template: 'wwwroot/index.html'
})
);
config.plugins.push(
new plugins.HtmlWebpackPlugin({
template: 'wwwroot/_theme.html', hash: true, chunksSortMode: 'none', filename: 'theme.html'
})
);
config.plugins.push(
new plugins.TsLintPlugin({
files: ['./app/**/*.ts'],
/**
* Path to a configuration file.
*/
config: root('tslint.json'),
/**
* Wait for linting and fail the build when linting error occur.
*/
waitForLinting: isProduction
})
);
}
if (isProduction) {
config.optimization = {
minimizer: [
new plugins.UglifyJsPlugin({
uglifyOptions: {
compress: false,
ecma: 6,
mangle: true,
output: {
comments: false
}
},
extractComments: true
}),
new plugins.OptimizeCSSAssetsPlugin({})
]
};
config.performance = {
hints: false
};
}
if (!isCoverage) {
config.module.rules.push({
test: /\.ts$/,
use: [{
loader: 'awesome-typescript-loader'
}, {
loader: 'angular-router-loader'
}, {
loader: 'angular2-template-loader'
}],
exclude: [/node_modules/]
}, {
})
} else {
config.module.rules.push({
test: /\.ts$/,
use: [{
loader: 'awesome-typescript-loader'
loader: 'ts-loader'
}],
include: [/node_modules/]
}, {
test: /\.js\.flow$/,
include: [/\.(e2e|spec)\.ts$/],
});
// Use instrument loader for all normal builds.
config.module.rules.push({
test: /\.ts$/,
use: [{
loader: 'ignore-loader'
loader: 'istanbul-instrumenter-loader'
}, {
loader: 'ts-loader'
}],
include: [/node_modules/]
}, {
test: /\.html$/,
use: [{
loader: 'raw-loader'
}]
}, {
test: /\.(woff|woff2|ttf|eot)(\?.*$|$)/,
use: [{
loader: 'file-loader?name=[name].[hash].[ext]',
options: {
outputPath: 'assets',
/*
* Use custom public path as ./ is not supported by fonts.
*/
publicPath: isDevServer ? undefined : 'assets'
}
}]
}, {
test: /\.(png|jpe?g|gif|svg|ico)(\?.*$|$)/,
use: [{
loader: 'file-loader?name=[name].[hash].[ext]',
options: {
outputPath: 'assets'
}
}]
}, {
test: /\.css$/,
exclude: [/\.(e2e|spec)\.ts$/]
});
}
if (isProduction) {
config.module.rules.push({
test: /\.scss$/,
/*
* Extract the content from a bundle to a file.
*
* See: https://github.com/webpack-contrib/extract-text-webpack-plugin
*/
use: [
plugins.MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
}]
}, {
}, {
loader: 'sass-loader'
}],
/*
* Do not include component styles.
*/
include: root('app', 'theme'),
});
} else {
config.module.rules.push({
test: /\.scss$/,
use: [{
loader: 'raw-loader'
loader: 'style-loader'
}, {
loader: 'sass-loader', options: { includePaths: [helpers.root('app', 'theme')] }
loader: 'css-loader'
}, {
loader: 'sass-loader?sourceMap'
}],
exclude: helpers.root('app', 'theme')
}]
},
/*
* Do not include component styles.
*/
include: root('app', 'theme')
});
}
plugins: [
/**
* 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('[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: helpers.root('app', 'images')
},
context: '/'
}
}),
new plugins.CircularDependencyPlugin({
exclude: /([\\\/]node_modules[\\\/])|(ngfactory\.js$)/,
// Add errors to webpack instead of warnings
failOnError: true
}),
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/)
]
if (!isJit) {
config.module.rules.push({
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: [{
loader: '@ngtools/webpack'
}]
});
config.plugins.push(
new plugins.NgToolsWebpack.AngularCompilerPlugin({
entryModule: 'app/app.module#AppModule',
sourceMap: !isProduction,
skipSourceGeneration: false,
tsConfigPath: './tsconfig.json'
})
);
}
return config;
};

35
src/Squidex/app-config/webpack.run.base.js

@ -1,35 +0,0 @@
const webpack = require('webpack'),
webpackMerge = require('webpack-merge'),
path = require('path'),
helpers = require('./helpers'),
commonConfig = require('./webpack.config.js');
const plugins = {
// https://github.com/jantimon/html-webpack-plugin
HtmlWebpackPlugin: require('html-webpack-plugin')
};
module.exports = webpackMerge(commonConfig, {
/**
* The entry point for the bundle. Our Angular app.
*
* See: https://webpack.js.org/configuration/entry-context/
*/
entry: {
'shims': './app/shims.ts',
'app': './app/app.ts'
},
plugins: [
new plugins.HtmlWebpackPlugin({
hash: true,
chunks: ['shims', 'app'],
chunksSortMode: 'manual',
template: 'wwwroot/index.html'
}),
new plugins.HtmlWebpackPlugin({
template: 'wwwroot/_theme.html', hash: true, chunksSortMode: 'none', filename: 'theme.html'
})
]
});

68
src/Squidex/app-config/webpack.run.dev.js

@ -1,68 +0,0 @@
const webpack = require('webpack'),
webpackMerge = require('webpack-merge'),
path = require('path'),
helpers = require('./helpers'),
runConfig = require('./webpack.run.base.js');
const plugins = {
// https://github.com/jrparish/tslint-webpack-plugin
TsLintPlugin: require('tslint-webpack-plugin')
};
module.exports = webpackMerge(runConfig, {
mode: 'development',
devtool: 'source-map',
output: {
filename: '[name].js',
/**
* Set the public path, because we are running the website from another port (5000).
*/
publicPath: 'http://localhost:3000/'
},
/*
* 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: /\.scss$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'sass-loader?sourceMap', options: { includePaths: [helpers.root('app', 'theme')] }
}],
include: helpers.root('app', 'theme')
}]
},
plugins: [
new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)fesm5/, helpers.root('./src'), {}),
new plugins.TsLintPlugin({
files: ['./app/**/*.ts'],
/**
* Path to a configuration file.
*/
config: helpers.root('tslint.json')
})
],
devServer: {
headers: {
'Access-Control-Allow-Origin': '*'
},
historyApiFallback: true
}
});

137
src/Squidex/app-config/webpack.run.prod.js

@ -1,137 +0,0 @@
const webpack = require('webpack'),
webpackMerge = require('webpack-merge'),
path = require('path'),
helpers = require('./helpers'),
runConfig = require('./webpack.run.base.js');
const plugins = {
// https://github.com/mishoo/UglifyJS2/tree/harmony
UglifyJsPlugin: require('uglifyjs-webpack-plugin'),
// https://www.npmjs.com/package/@ngtools/webpack
NgToolsWebpack: require('@ngtools/webpack'),
// https://github.com/webpack-contrib/mini-css-extract-plugin
MiniCssExtractPlugin: require('mini-css-extract-plugin'),
// https://github.com/NMFR/optimize-css-assets-webpack-plugin
OptimizeCSSAssetsPlugin: require("optimize-css-assets-webpack-plugin"),
// https://github.com/jrparish/tslint-webpack-plugin
TsLintPlugin: require('tslint-webpack-plugin')
};
helpers.removeLoaders(runConfig, ['scss', 'ts']);
module.exports = webpackMerge(runConfig, {
mode: 'production',
output: {
/**
* The output directory as absolute path (required).
*
* See: https://webpack.js.org/configuration/output/#output-path
*/
path: helpers.root('wwwroot/build/'),
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'
},
/*
* 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: /\.scss$/,
/*
* Extract the content from a bundle to a file.
*
* See: https://github.com/webpack-contrib/extract-text-webpack-plugin
*/
use: [
plugins.MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
}, {
loader: 'sass-loader'
}],
/*
* Do not include component styles.
*/
include: helpers.root('app', 'theme'),
}, {
test: /\.scss$/,
use: [{
loader: 'raw-loader'
}, {
loader: 'sass-loader', options: { includePaths: [helpers.root('app', 'theme')] }
}],
exclude: helpers.root('app', 'theme'),
}, {
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: [{
loader: '@ngtools/webpack'
}]
}]
},
plugins: [
new plugins.NgToolsWebpack.AngularCompilerPlugin({
entryModule: 'app/app.module#AppModule',
sourceMap: false,
skipSourceGeneration: false,
tsConfigPath: './tsconfig.json'
}),
new plugins.TsLintPlugin({
files: ['./app/**/*.ts'],
/**
* Path to a configuration file.
*/
config: helpers.root('tslint.json'),
/**
* Wait for linting and fail the build when linting error occur.
*/
waitForLinting: true
})
],
optimization: {
minimizer: [
new plugins.UglifyJsPlugin({
uglifyOptions: {
compress: false,
ecma: 6,
mangle: true,
output: {
comments: false
}
},
extractComments: true
}),
new plugins.OptimizeCSSAssetsPlugin({})
]
},
performance: {
hints: false
}
});

37
src/Squidex/app-config/webpack.test.coverage.js

@ -1,37 +0,0 @@
const webpack = require('webpack'),
webpackMerge = require('webpack-merge'),
path = require('path'),
helpers = require('./helpers'),
testConfig = require('./webpack.test.js');
helpers.removeLoaders(testConfig, ['ts']);
module.exports = webpackMerge(testConfig, {
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: /\.ts$/,
use: [{
loader: 'ts-loader'
}],
include: [/\.(e2e|spec)\.ts$/],
}, {
test: /\.ts$/,
use: [{
loader: 'istanbul-instrumenter-loader'
}, {
loader: 'ts-loader'
}, {
loader: 'angular-router-loader'
}, {
loader: 'angular2-template-loader'
}],
exclude: [/\.(e2e|spec)\.ts$/]
}]
}
});

16
src/Squidex/app-config/webpack.test.js

@ -1,16 +0,0 @@
const webpack = require('webpack'),
webpackMerge = require('webpack-merge'),
path = require('path'),
helpers = require('./helpers'),
commonConfig = require('./webpack.config.js');
module.exports = webpackMerge(commonConfig, {
mode: 'development',
/**
* Source map for Karma from the help of karma-sourcemap-loader & karma-webpack.
*
* See: https://webpack.js.org/configuration/devtool/
*/
devtool: 'inline-source-map'
});

18
src/Squidex/app/app.routes.ts

@ -38,12 +38,12 @@ export const routes: Routes = [
children: [
{
path: '',
loadChildren: './features/apps/module#SqxFeatureAppsModule',
loadChildren: () => import('./features/apps/module').then(m => m.SqxFeatureAppsModule),
canActivate: [UnsetAppGuard]
},
{
path: 'administration',
loadChildren: './features/administration/module#SqxFeatureAdministrationModule',
loadChildren: () => import('./features/administration/module').then(m => m.SqxFeatureAdministrationModule),
canActivate: [UnsetAppGuard]
},
{
@ -53,31 +53,31 @@ export const routes: Routes = [
children: [
{
path: '',
loadChildren: './features/dashboard/module#SqxFeatureDashboardModule'
loadChildren: () => import('./features/dashboard/module').then(m => m.SqxFeatureDashboardModule)
},
{
path: 'content',
loadChildren: './features/content/module#SqxFeatureContentModule'
loadChildren: () => import('./features/content/module').then(m => m.SqxFeatureContentModule)
},
{
path: 'schemas',
loadChildren: './features/schemas/module#SqxFeatureSchemasModule'
loadChildren: () => import('./features/schemas/module').then(m => m.SqxFeatureSchemasModule)
},
{
path: 'assets',
loadChildren: './features/assets/module#SqxFeatureAssetsModule'
loadChildren: () => import('./features/assets/module').then(m => m.SqxFeatureAssetsModule)
},
{
path: 'rules',
loadChildren: './features/rules/module#SqxFeatureRulesModule'
loadChildren: () => import('./features/rules/module').then(m => m.SqxFeatureRulesModule)
},
{
path: 'settings',
loadChildren: './features/settings/module#SqxFeatureSettingsModule'
loadChildren: () => import('./features/settings/module').then(m => m.SqxFeatureSettingsModule)
},
{
path: 'api',
loadChildren: './features/api/module#SqxFeatureApiModule'
loadChildren: () => import('./features/api/module').then(m => m.SqxFeatureApiModule)
}
]
}

2
src/Squidex/app/features/api/pages/graphql/graphql-page.component.ts

@ -22,7 +22,7 @@ import { AppsState, GraphQlService } from '@app/shared';
templateUrl: './graphql-page.component.html'
})
export class GraphQLPageComponent implements AfterViewInit {
@ViewChild('graphiQLContainer')
@ViewChild('graphiQLContainer', { static: false })
public graphiQLContainer: ElementRef;
constructor(

2
src/Squidex/app/features/apps/pages/apps-page.component.scss

@ -66,7 +66,7 @@
}
&:hover {
@include box-shadow(0, 3px, 16px, .2px);
@include box-shadow(0, 3px, 16px, .2);
}
&:focus {

2
src/Squidex/app/features/content/pages/content/content-page.component.ts

@ -59,7 +59,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
public language: AppLanguageDto;
public languages: ImmutableArray<AppLanguageDto>;
@ViewChild('dueTimeSelector')
@ViewChild('dueTimeSelector', { static: false })
public dueTimeSelector: DueTimeSelectorComponent;
constructor(apiUrl: ApiUrlConfig, authService: AuthService,

2
src/Squidex/app/features/content/pages/contents/contents-page.component.ts

@ -52,7 +52,7 @@ export class ContentsPageComponent extends ResourceOwner implements OnInit {
public isAllSelected = false;
@ViewChild('dueTimeSelector')
@ViewChild('dueTimeSelector', { static: false })
public dueTimeSelector: DueTimeSelectorComponent;
constructor(

4
src/Squidex/app/features/content/pages/schemas/schemas-page.component.html

@ -18,10 +18,8 @@
<ng-container content>
<ng-container *ngIf="schemasState.publishedSchemas | async; let schemas">
<sqx-schema-category *ngFor="let category of schemasState.categories | async; trackBy: trackByCategory"
[name]="category"
[schemas]="schemas"
[schemaCategory]="category"
[schemasFilter]="schemasFilter.valueChanges | async"
[routeSingletonToContent]="true"
[forContent]="true">
</sqx-schema-category>
</ng-container>

10
src/Squidex/app/features/content/pages/schemas/schemas-page.component.ts

@ -8,7 +8,11 @@
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { AppsState, SchemasState } from '@app/shared';
import {
AppsState,
SchemaCategory,
SchemasState
} from '@app/shared';
@Component({
selector: 'sqx-schemas-page',
@ -28,8 +32,8 @@ export class SchemasPageComponent implements OnInit {
this.schemasState.load();
}
public trackByCategory(index: number, category: string) {
return category;
public trackByCategory(index: number, category: SchemaCategory) {
return category.name;
}
}

8
src/Squidex/app/features/rules/pages/rules/rule-element.component.scss

@ -82,7 +82,9 @@
display: inline-block;
}
/deep/ svg {
fill: $color-dark-foreground;
display: block;
::ng-deep {
svg {
fill: $color-dark-foreground;
display: block;
}
}

2
src/Squidex/app/features/schemas/pages/schema/field-wizard.component.ts

@ -29,7 +29,7 @@ const DEFAULT_FIELD = { name: '', partitioning: 'invariant', properties: createP
templateUrl: './field-wizard.component.html'
})
export class FieldWizardComponent implements OnInit {
@ViewChild('nameInput')
@ViewChild('nameInput', { static: false })
public nameInput: ElementRef<HTMLElement>;
@Input()

5
src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.html

@ -27,10 +27,9 @@
<ng-container content>
<sqx-schema-category *ngFor="let category of schemasState.categories | async; trackBy: trackByCategory"
[name]="category"
[schemas]="schemasState.schemas | async"
[schemaCategory]="category"
[schemasFilter]="schemasFilter.valueChanges | async"
(remove)="removeCategory(category)">
(remove)="removeCategory(category.name)">
</sqx-schema-category>
<form [formGroup]="addCategoryForm.form" (ngSubmit)="addCategory()">

5
src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts

@ -16,6 +16,7 @@ import {
DialogModel,
MessageBus,
ResourceOwner,
SchemaCategory,
SchemaDto,
SchemasState
} from '@app/shared';
@ -94,8 +95,8 @@ export class SchemasPageComponent extends ResourceOwner implements OnInit {
this.addSchemaDialog.show();
}
public trackByCategory(index: number, category: string) {
return category;
public trackByCategory(index: number, category: SchemaCategory) {
return category.name;
}
}

2
src/Squidex/app/features/settings/pages/roles/role.component.ts

@ -33,7 +33,7 @@ export class RoleComponent implements OnChanges {
@Input()
public allPermissions: AutocompleteSource;
@ViewChild('addInput')
@ViewChild('addInput', { static: false })
public addPermissionInput: AutocompleteComponent;
public isEditing = false;

4
src/Squidex/app/framework/angular/forms/autocomplete.component.ts

@ -52,10 +52,10 @@ export class AutocompleteComponent extends StatefulControlComponent<State, any[]
@Input()
public placeholder = '';
@ContentChild(TemplateRef)
@ContentChild(TemplateRef, { static: false })
public itemTemplate: TemplateRef<any>;
@ViewChild('input')
@ViewChild('input', { static: false })
public inputControl: ElementRef<HTMLInputElement>;
public queryInput = new FormControl();

2
src/Squidex/app/framework/angular/forms/code-editor.component.ts

@ -35,7 +35,7 @@ export class CodeEditorComponent extends ExternalControlComponent<string> implem
private value: string;
private isDisabled = false;
@ViewChild('editor')
@ViewChild('editor', { static: false })
public editor: ElementRef;
@Input()

2
src/Squidex/app/framework/angular/forms/date-time-editor.component.ts

@ -41,7 +41,7 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
@Input()
public hideClear: boolean;
@ViewChild('dateInput')
@ViewChild('dateInput', { static: false })
public dateInput: ElementRef;
public timeControl = new FormControl();

2
src/Squidex/app/framework/angular/forms/iframe-editor.component.ts

@ -26,7 +26,7 @@ export class IFrameEditorComponent extends ExternalControlComponent<any> impleme
private isDisabled = false;
private isInitialized = false;
@ViewChild('iframe')
@ViewChild('iframe', { static: false })
public iframe: ElementRef<HTMLIFrameElement>;
@Input()

2
src/Squidex/app/framework/angular/forms/json-editor.component.ts

@ -32,7 +32,7 @@ export class JsonEditorComponent extends ExternalControlComponent<string> implem
private valueString: string;
private isDisabled = false;
@ViewChild('editor')
@ViewChild('editor', { static: false })
public editor: ElementRef<HTMLDivElement>;
constructor(changeDetector: ChangeDetectorRef,

4
src/Squidex/app/framework/angular/forms/tag-editor.component.ts

@ -93,10 +93,10 @@ interface State {
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TagEditorComponent extends StatefulControlComponent<State, any[]> implements AfterViewInit, OnInit {
@ViewChild('form')
@ViewChild('form', { static: false })
public formElement: ElementRef<HTMLElement>;
@ViewChild('input')
@ViewChild('input', { static: false })
public inputElement: ElementRef<HTMLInputElement>;
@Input()

4
src/Squidex/app/framework/angular/modals/modal-dialog.component.ts

@ -51,10 +51,10 @@ export class ModalDialogComponent extends StatefulComponent<State> implements Af
@Output()
public close = new EventEmitter();
@ViewChild('tabsElement')
@ViewChild('tabsElement', { static: false })
public tabsElement: ElementRef<ParentNode>;
@ViewChild('footerElement')
@ViewChild('footerElement', { static: false })
public footerElement: ElementRef<ParentNode>;
constructor(changeDetector: ChangeDetectorRef) {

2
src/Squidex/app/framework/angular/modals/root-view.component.ts

@ -14,6 +14,6 @@ import { ChangeDetectionStrategy, Component, ViewChild, ViewContainerRef } from
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RootViewComponent {
@ViewChild('element', { read: ViewContainerRef })
@ViewChild('element', { read: ViewContainerRef, static: false })
public viewContainer: ViewContainerRef;
}

2
src/Squidex/app/framework/angular/panel.component.ts

@ -64,7 +64,7 @@ export class PanelComponent implements AfterViewInit, OnDestroy, OnInit {
@Input()
public sidebarClass = '';
@ViewChild('panel')
@ViewChild('panel', { static: false })
public panel: ElementRef<HTMLElement>;
constructor(

4
src/Squidex/app/shared/components/geolocation-editor.component.ts

@ -64,10 +64,10 @@ export class GeolocationEditorComponent extends StatefulControlComponent<State,
]
});
@ViewChild('editor')
@ViewChild('editor', { static: false })
public editor: ElementRef<HTMLElement>;
@ViewChild('searchBox')
@ViewChild('searchBox', { static: false })
public searchBoxInput: ElementRef<HTMLInputElement>;
constructor(changeDetector: ChangeDetectorRef,

6
src/Squidex/app/shared/components/markdown-editor.component.ts

@ -40,13 +40,13 @@ export class MarkdownEditorComponent extends StatefulControlComponent<State, str
private value: string;
private isDisabled = false;
@ViewChild('editor')
@ViewChild('editor', { static: false })
public editor: ElementRef;
@ViewChild('container')
@ViewChild('container', { static: false })
public container: ElementRef;
@ViewChild('inner')
@ViewChild('inner', { static: false })
public inner: ElementRef;
public assetsDialog = new DialogModel();

2
src/Squidex/app/shared/components/rich-editor.component.ts

@ -46,7 +46,7 @@ export class RichEditorComponent extends StatefulControlComponent<any, string> i
private value: string;
private isDisabled = false;
@ViewChild('editor')
@ViewChild('editor', { static: false })
public editor: ElementRef;
@Output()

24
src/Squidex/app/shared/components/schema-category.component.html

@ -1,4 +1,4 @@
<div *ngIf="!forContent || snapshot.schemasFiltered.length > 0" dnd-droppable class="droppable category" [allowDrop]="allowDrop" (onDropSuccess)="changeCategory($event.dragData)">
<div *ngIf="!forContent || snapshot.filtered.length > 0" dnd-droppable class="droppable category" [allowDrop]="allowDrop" (onDropSuccess)="changeCategory($event.dragData)">
<div class="drop-indicator"></div>
<div class="header clearfix">
@ -6,18 +6,18 @@
<i [class.icon-caret-right]="!snapshot.isOpen" [class.icon-caret-down]="snapshot.isOpen"></i>
</button>
<h3>{{snapshot.displayName}} ({{snapshot.schemasFiltered.length}})</h3>
<h3>{{schemaCategory.name}} ({{snapshot.filtered.length}})</h3>
<button type="button" class="btn btn-sm btn-text-secondary float-right" *ngIf="snapshot.schemasForCategory.length === 0 && !forContent" (click)="emitRemove()">
<button type="button" class="btn btn-sm btn-text-secondary float-right" *ngIf="schemaCategory.schemas.length === 0 && !forContent" (click)="emitRemove()">
<i class="icon-bin2"></i>
</button>
</div>
<ul class="nav nav-panel nav-dark nav-dark-bordered flex-column" *ngIf="snapshot.isOpen" @fade>
<ng-container *ngFor="let schema of snapshot.schemasFiltered; trackBy: trackBySchema">
<li class="nav-item" dnd-draggable [dragEnabled]="!forContent && schema.canUpdateCategory" [dragData]="schema">
<ng-container *ngIf="!forContent; else simpleMode">
<li *ngFor="let schema of snapshot.filtered; trackBy: trackBySchema" class="nav-item" dnd-draggable [dragEnabled]="schema.canUpdateCategory" [dragData]="schema">
<a class="nav-link" [routerLink]="schemaRoute(schema)" routerLinkActive="active">
<div class="row" *ngIf="!forContent; else simpleMode">
<div class="row">
<div class="col-4">
<span class="schema-name schema-name-accent">{{schema.displayName}}</span>
</div>
@ -32,12 +32,16 @@
<span class="item-published" [class.unpublished]="!schema.isPublished"></span>
</div>
</div>
<ng-template #simpleMode>
<span class="schema-name" *ngIf="forContent">{{schema.displayName}}</span>
</ng-template>
</a>
</li>
</ng-container>
<ng-template #simpleMode>
<li *ngFor="let schema of snapshot.filtered; trackBy: trackBySchema" class="nav-item">
<a class="nav-link" [routerLink]="schemaRoute(schema)" routerLinkActive="active">
<span class="schema-name" *ngIf="forContent">{{schema.displayName}}</span>
</a>
</li>
</ng-template>
</ul>
</div>

68
src/Squidex/app/shared/components/schema-category.component.ts

@ -10,7 +10,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, In
import {
fadeAnimation,
ImmutableArray,
isSameCategory,
LocalStoreService,
SchemaCategory,
SchemaDetailsDto,
SchemaDto,
SchemasState,
@ -19,12 +21,9 @@ import {
} from '@app/shared/internal';
interface State {
displayName?: string;
filtered: ImmutableArray<SchemaDto>;
schemasFiltered: ImmutableArray<SchemaDto>;
schemasForCategory: ImmutableArray<SchemaDto>;
isOpen: boolean;
isOpen?: boolean;
}
@Component({
@ -38,36 +37,26 @@ interface State {
})
export class SchemaCategoryComponent extends StatefulComponent<State> implements OnInit, OnChanges {
@Input()
public name: string;
@Input()
public forContent: boolean;
@Input()
public routeSingletonToContent = false;
public schemaCategory: SchemaCategory;
@Input()
public schemasFilter: string;
@Input()
public schemas: ImmutableArray<SchemaDto>;
public forContent: boolean;
@Output()
public remove = new EventEmitter();
public allowDrop = (schema: any) => {
return (Types.is(schema, SchemaDto) || Types.is(schema, SchemaDetailsDto)) && !this.isSameCategory(schema);
return (Types.is(schema, SchemaDto) || Types.is(schema, SchemaDetailsDto)) && !isSameCategory(this.schemaCategory.name, schema);
}
constructor(changeDetector: ChangeDetectorRef,
private readonly localStore: LocalStoreService,
private readonly schemasState: SchemasState
) {
super(changeDetector, {
schemasFiltered: ImmutableArray.empty(),
schemasForCategory: ImmutableArray.empty(),
isOpen: true
});
super(changeDetector, { filtered: ImmutableArray.empty(), isOpen: true });
}
public ngOnInit() {
@ -81,52 +70,37 @@ export class SchemaCategoryComponent extends StatefulComponent<State> implements
}
public ngOnChanges(changes: SimpleChanges): void {
if (changes['schemas'] || changes['schemasFilter']) {
const isSameCategory = (schema: SchemaDto) => {
return (!this.name && !schema.category) || schema.category === this.name;
};
if (changes['schemaCategory'] || changes['schemasFilter']) {
let filtered = this.schemaCategory.schemas;
const query = this.schemasFilter;
const schemasForCategory = this.schemas.filter(x => isSameCategory(x));
const schemasFiltered = schemasForCategory.filter(x => !query || x.name.indexOf(query) >= 0);
if (this.forContent) {
filtered = filtered.filter(x => x.canReadContents);
}
let isOpen = false;
if (query) {
if (this.schemasFilter) {
filtered = filtered.filter(x => x.name.indexOf(this.schemasFilter) >= 0);
isOpen = true;
} else {
isOpen = !this.localStore.getBoolean(this.configKey());
}
this.next(s => ({ ...s, isOpen, schemasFiltered, schemasForCategory }));
}
if (changes['name']) {
let displayName = 'Schemas';
if (this.name && this.name.length > 0) {
displayName = this.name;
isOpen = this.localStore.get(`schema-category.${this.schemaCategory.name}`) !== 'false';
}
this.next(s => ({ ...s, displayName }));
this.next(s => ({ ...s, isOpen, filtered }));
}
}
public schemaRoute(schema: SchemaDto) {
if (schema.isSingleton && this.routeSingletonToContent) {
if (schema.isSingleton && this.forContent) {
return [schema.name, schema.id];
} else {
return [schema.name];
}
}
private isSameCategory(schema: SchemaDto): boolean {
return ((!this.name && !schema.category) || schema.category === this.name) && (!this.forContent || schema.canReadContents);
}
public changeCategory(schema: SchemaDto) {
this.schemasState.changeCategory(schema, this.name);
this.schemasState.changeCategory(schema, this.schemaCategory.name);
}
public emitRemove() {
@ -138,6 +112,6 @@ export class SchemaCategoryComponent extends StatefulComponent<State> implements
}
private configKey(): string {
return `squidex.schema.category.${this.name}.closed`;
return `squidex.schema.category.${this.schemaCategory.name}.closed`;
}
}

61
src/Squidex/app/shared/state/schemas.state.spec.ts

@ -9,11 +9,12 @@
import { of, throwError } from 'rxjs';
import { IMock, It, Mock, Times } from 'typemoq';
import { SchemasState } from './schemas.state';
import { SchemaCategory, SchemasState } from './schemas.state';
import {
DialogService,
FieldDto,
ImmutableArray,
SchemaDetailsDto,
SchemasService,
UpdateSchemaCategoryDto,
@ -70,7 +71,13 @@ describe('SchemasState', () => {
expect(schemasState.snapshot.schemas.values).toEqual(oldSchemas.items);
expect(schemasState.snapshot.isLoaded).toBeTruthy();
expect(schemasState.snapshot.categories).toEqual({ 'category1': false, 'category2': false });
const categories = getCategories(schemasState);
expect(categories!).toEqual([
{ name: 'category1', upper: 'CATEGORY1', schemas: ImmutableArray.of([schema1]) },
{ name: 'category2', upper: 'CATEGORY2', schemas: ImmutableArray.of([schema2]) }
]);
schemasService.verifyAll();
});
@ -84,7 +91,14 @@ describe('SchemasState', () => {
expect(schemasState.snapshot.schemas.values).toEqual(oldSchemas.items);
expect(schemasState.snapshot.isLoaded).toBeTruthy();
expect(schemasState.snapshot.categories).toEqual({ 'category1': false, 'category2': false, 'category3': true });
const categories = getCategories(schemasState);
expect(categories!).toEqual([
{ name: 'category1', upper: 'CATEGORY1', schemas: ImmutableArray.of([schema1]) },
{ name: 'category2', upper: 'CATEGORY2', schemas: ImmutableArray.of([schema2]) },
{ name: 'category3', upper: 'CATEGORY3', schemas: ImmutableArray.empty() }
]);
schemasService.verifyAll();
});
@ -112,13 +126,36 @@ describe('SchemasState', () => {
it('should add category', () => {
schemasState.addCategory('category3');
expect(schemasState.snapshot.categories).toEqual({ 'category1': false, 'category2': false, 'category3': true });
const categories = getCategories(schemasState);
expect(categories!).toEqual([
{ name: 'category1', upper: 'CATEGORY1', schemas: ImmutableArray.of([schema1]) },
{ name: 'category2', upper: 'CATEGORY2', schemas: ImmutableArray.of([schema2]) },
{ name: 'category3', upper: 'CATEGORY3', schemas: ImmutableArray.empty() }
]);
});
it('should not remove category with schemas', () => {
schemasState.addCategory('category1');
const categories = getCategories(schemasState);
expect(categories!).toEqual([
{ name: 'category1', upper: 'CATEGORY1', schemas: ImmutableArray.of([schema1]) },
{ name: 'category2', upper: 'CATEGORY2', schemas: ImmutableArray.of([schema2]) }
]);
});
it('should remove category', () => {
schemasState.removeCategory('category1');
schemasState.addCategory('category3');
schemasState.removeCategory('category3');
expect(schemasState.snapshot.categories).toEqual({ 'category2': false });
const categories = getCategories(schemasState);
expect(categories!).toEqual([
{ name: 'category1', upper: 'CATEGORY1', schemas: ImmutableArray.of([schema1]) },
{ name: 'category2', upper: 'CATEGORY2', schemas: ImmutableArray.of([schema2]) }
]);
});
it('should return schema on select and reload when already loaded', () => {
@ -493,4 +530,14 @@ describe('SchemasState', () => {
});
});
});
});
});
function getCategories(schemasState: SchemasState) {
let categories: SchemaCategory[];
schemasState.categories.subscribe(result => {
categories = result;
});
return categories!;
}

73
src/Squidex/app/shared/state/schemas.state.ts

@ -38,7 +38,7 @@ type AnyFieldDto = NestedFieldDto | RootFieldDto;
interface Snapshot {
// The schema categories.
categories: { [name: string]: boolean };
categories: string[];
// The current schemas.
schemas: SchemasList;
@ -54,8 +54,7 @@ interface Snapshot {
}
export type SchemasList = ImmutableArray<SchemaDto>;
export type Categories = { [name: string]: boolean };
export type SchemaCategory = { name: string; schemas: SchemasList; upper: string; };
function sameSchema(lhs: SchemaDetailsDto | null, rhs?: SchemaDetailsDto | null): boolean {
return lhs === rhs || (!!lhs && !!rhs && lhs.id === rhs.id && lhs.version === rhs.version);
@ -68,7 +67,7 @@ export class SchemasState extends State<Snapshot> {
}
public categories =
this.project2(x => x.categories, x => sortedCategoryNames(x));
this.project2(x => x, x => buildCategories(x.categories, x.schemas));
public selectedSchema =
this.project(x => x.selectedSchema, sameSchema);
@ -90,7 +89,7 @@ export class SchemasState extends State<Snapshot> {
private readonly dialogs: DialogService,
private readonly schemasService: SchemasService
) {
super({ schemas: ImmutableArray.empty(), categories: buildCategories({}) });
super({ schemas: ImmutableArray.empty(), categories: [] });
}
public select(idOrName: string | null): Observable<SchemaDetailsDto | null> {
@ -126,9 +125,7 @@ export class SchemasState extends State<Snapshot> {
return this.next(s => {
const schemas = ImmutableArray.of(items).sortByStringAsc(x => x.displayName);
const categories = buildCategories(s.categories, schemas);
return { ...s, schemas, isLoaded: true, categories, canCreate };
return { ...s, schemas, isLoaded: true, canCreate };
});
}),
shareSubscribed(this.dialogs));
@ -140,9 +137,7 @@ export class SchemasState extends State<Snapshot> {
this.next(s => {
const schemas = s.schemas.push(created).sortByStringAsc(x => x.displayName);
const categories = buildCategories(s.categories, schemas);
return { ...s, schemas, categories };
return { ...s, schemas };
});
}),
shareSubscribed(this.dialogs, { silent: true }));
@ -163,7 +158,7 @@ export class SchemasState extends State<Snapshot> {
public addCategory(name: string) {
this.next(s => {
const categories = addCategory(s.categories, name);
const categories = [...s.categories, name];
return { ...s, categories: categories };
});
@ -171,7 +166,7 @@ export class SchemasState extends State<Snapshot> {
public removeCategory(name: string) {
this.next(s => {
const categories = removeCategory(s.categories, name);
const categories = s.categories.filter(x => x !== name);
return { ...s, categories: categories };
});
@ -309,9 +304,7 @@ export class SchemasState extends State<Snapshot> {
schema :
s.selectedSchema;
const categories = buildCategories(s.categories, schemas);
return { ...s, schemas, selectedSchema, categories };
return { ...s, schemas, selectedSchema };
});
}
@ -328,46 +321,32 @@ function getField(x: SchemaDetailsDto, request: AddFieldDto, parent?: RootFieldD
}
}
function buildCategories(categories: { [name: string]: boolean }, schemas?: SchemasList) {
categories = { ...categories };
function buildCategories(categories: string[], schemas: SchemasList): SchemaCategory[] {
const uniqueCategories: { [name: string]: string } = {};
for (let category in categories) {
if (categories.hasOwnProperty(category)) {
if (!categories[category]) {
delete categories[category];
}
}
for (let category of categories) {
uniqueCategories[category] = category;
}
if (schemas) {
for (let schema of schemas.values) {
categories[schema.category || ''] = false;
}
for (let schema of schemas.values) {
uniqueCategories[schema.category || 'Schemas'] = schema.category;
}
return categories;
}
function addCategory(categories: Categories, category: string) {
categories = { ...categories };
categories[category] = true;
const result: SchemaCategory[] = [];
return categories;
}
for (let name in uniqueCategories) {
if (uniqueCategories.hasOwnProperty(name)) {
const key = uniqueCategories[name];
function removeCategory(categories: Categories, category: string) {
categories = { ...categories };
result.push({ name, upper: name.toUpperCase(), schemas: schemas.filter(x => isSameCategory(key, x))});
}
}
delete categories[category];
result.sort((a, b) => compareStringsAsc(a.upper, b.upper));
return categories;
return result;
}
function sortedCategoryNames(categories: Categories) {
const names = Object.keys(categories);
names.sort(compareStringsAsc);
return names;
export function isSameCategory(name: string, schema: SchemaDto): boolean {
return (!name && !schema.category) || schema.category === name;
}

2
src/Squidex/app/shell/pages/internal/internal-area.component.scss

@ -2,7 +2,7 @@
@import '_mixins';
.navbar {
@include box-shadow(0, 3px, 5px, .13px);
@include box-shadow(0, 3px, 5px, .13);
display: block;
}

103
src/Squidex/app/shims.ts

@ -5,20 +5,91 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import 'core-js/es6/array';
import 'core-js/es6/date';
import 'core-js/es6/function';
import 'core-js/es6/map';
import 'core-js/es6/math';
import 'core-js/es6/number';
import 'core-js/es6/object';
import 'core-js/es6/parse-float';
import 'core-js/es6/parse-int';
import 'core-js/es6/reflect';
import 'core-js/es6/regexp';
import 'core-js/es6/set';
import 'core-js/es6/string';
import 'core-js/es6/symbol';
import 'core-js/es7/reflect';
// ES2015 symbol capabilities
import 'core-js/modules/es.symbol';
// 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';
// ES2015 object capabilities
import 'core-js/modules/es.object.assign';
import 'core-js/modules/es.object.create';
import 'core-js/modules/es.object.define-properties';
import 'core-js/modules/es.object.define-property';
import 'core-js/modules/es.object.freeze';
import 'core-js/modules/es.object.get-own-property-descriptor';
import 'core-js/modules/es.object.get-own-property-names';
import 'core-js/modules/es.object.get-prototype-of';
import 'core-js/modules/es.object.is';
import 'core-js/modules/es.object.is-extensible';
import 'core-js/modules/es.object.is-frozen';
import 'core-js/modules/es.object.is-sealed';
import 'core-js/modules/es.object.keys';
import 'core-js/modules/es.object.prevent-extensions';
import 'core-js/modules/es.object.seal';
import 'core-js/modules/es.object.set-prototype-of';
import 'core-js/modules/es.object.to-string';
// ES2015 array capabilities
import 'core-js/modules/es.array.copy-within';
import 'core-js/modules/es.array.every';
import 'core-js/modules/es.array.fill';
import 'core-js/modules/es.array.filter';
import 'core-js/modules/es.array.find';
import 'core-js/modules/es.array.find-index';
import 'core-js/modules/es.array.for-each';
import 'core-js/modules/es.array.from';
import 'core-js/modules/es.array.index-of';
import 'core-js/modules/es.array.is-array';
import 'core-js/modules/es.array.iterator';
import 'core-js/modules/es.array.join';
import 'core-js/modules/es.array.last-index-of';
import 'core-js/modules/es.array.map';
import 'core-js/modules/es.array.of';
import 'core-js/modules/es.array.reduce';
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 string capabilities
import 'core-js/modules/es.string.anchor';
import 'core-js/modules/es.string.big';
import 'core-js/modules/es.string.blink';
import 'core-js/modules/es.string.bold';
import 'core-js/modules/es.string.code-point-at';
import 'core-js/modules/es.string.ends-with';
import 'core-js/modules/es.string.fixed';
import 'core-js/modules/es.string.fontcolor';
import 'core-js/modules/es.string.fontsize';
import 'core-js/modules/es.string.from-code-point';
import 'core-js/modules/es.string.includes';
import 'core-js/modules/es.string.italics';
import 'core-js/modules/es.string.iterator';
import 'core-js/modules/es.string.link';
import 'core-js/modules/es.string.raw';
import 'core-js/modules/es.string.repeat';
import 'core-js/modules/es.string.small';
import 'core-js/modules/es.string.starts-with';
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';
import 'core-js/modules/es.parse-float';
import 'core-js/modules/es.parse-int';
import 'core-js/es/date';
import 'core-js/es/math';
import 'core-js/es/number';
import 'core-js/es/regexp';
import 'core-js/modules/es.map';
import 'core-js/modules/es.promise';
import 'core-js/modules/es.set';
import 'core-js/modules/es.weak-map';
import 'core-js/modules/web.dom-collections.iterator';
import 'zone.js/dist/zone';

2
src/Squidex/app/theme/_bootstrap.scss

@ -162,7 +162,7 @@ a {
.dropdown-menu {
// White dropdown menu without border and shadow.
& {
@include box-shadow(0, 3px, 16px, .2px);
@include box-shadow(0, 3px, 16px, .2);
border: 0;
background: $panel-light-background;
}

2897
src/Squidex/package-lock.json

File diff suppressed because it is too large

81
src/Squidex/package.json

@ -6,69 +6,67 @@
"repository": "https://github.com/SebastianStehle/Squidex",
"scripts": {
"copy": "cpx node_modules/oidc-client/dist/oidc-client.min.js wwwroot/scripts/",
"start": "npm run copy && webpack-dev-server --config app-config/webpack.run.dev.js --inline --port 3000 --hot",
"start": "npm run copy && webpack-dev-server --config app-config/webpack.config.js --inline --port 3000 --hot",
"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",
"build": "npm run copy && webpack --config app-config/webpack.run.prod.js",
"build": "npm run copy && 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"
},
"dependencies": {
"@angular/animations": "7.2.14",
"@angular/common": "7.2.14",
"@angular/core": "7.2.14",
"@angular/forms": "7.2.14",
"@angular/http": "7.2.14",
"@angular/platform-browser-dynamic": "7.2.14",
"@angular/platform-browser": "7.2.14",
"@angular/platform-server": "7.2.14",
"@angular/router": "7.2.14",
"@angular/animations": "8.0.2",
"@angular/common": "8.0.2",
"@angular/core": "8.0.2",
"@angular/forms": "8.0.2",
"@angular/http": "7.2.15",
"@angular/platform-browser": "8.0.2",
"@angular/platform-browser-dynamic": "8.0.2",
"@angular/platform-server": "8.0.2",
"@angular/router": "8.0.2",
"angular2-chartjs": "0.5.1",
"babel-polyfill": "6.26.0",
"bootstrap": "4.3.1",
"core-js": "2.6.3",
"graphiql": "0.13.0",
"graphql": "14.2.1",
"core-js": "3.1.4",
"graphiql": "0.13.2",
"graphql": "14.3.1",
"marked": "0.6.2",
"moment": "2.24.0",
"mousetrap": "1.6.3",
"ng2-dnd": "5.0.2",
"ngx-color-picker": "7.5.0",
"oidc-client": "1.7.1",
"ngx-color-picker": "8.0.1",
"oidc-client": "1.8.2",
"pikaday": "1.8.0",
"progressbar.js": "1.0.1",
"react-dom": "16.8.6",
"react": "16.8.6",
"rxjs": "6.5.1",
"react-dom": "16.8.6",
"rxjs": "6.5.2",
"slugify": "1.3.4",
"sortablejs": "1.9.0",
"tslib": "1.9.3",
"tslib": "1.10.0",
"zone.js": "0.9.1"
},
"devDependencies": {
"@angular/compiler": "7.2.14",
"@angular/compiler-cli": "7.2.14",
"@ngtools/webpack": "7.3.8",
"@types/core-js": "2.5.0",
"@types/jasmine": "3.3.12",
"@angular/compiler": "8.0.2",
"@angular/compiler-cli": "8.0.2",
"@ngtools/webpack": "8.0.3",
"@types/core-js": "2.5.2",
"@types/jasmine": "3.3.13",
"@types/marked": "0.6.5",
"@types/mousetrap": "1.6",
"@types/node": "12.0.0",
"@types/react": "16.8.16",
"@types/node": "12.0.10",
"@types/react": "16.8.22",
"@types/react-dom": "16.8.4",
"@types/sortablejs": "1.7.2",
"angular-router-loader": "0.8.5",
"angular2-template-loader": "0.6.2",
"awesome-typescript-loader": "5.2.1",
"babel-core": "6.26.3",
"browserslist": "^4.6.3",
"caniuse-lite": "^1.0.30000975",
"caniuse-lite": "^1.0.30000976",
"circular-dependency-plugin": "5.0.2",
"codelyzer": "5.0.1",
"codelyzer": "5.1.0",
"cpx": "1.5.0",
"css-loader": "2.1.1",
"file-loader": "3.0.1",
"css-loader": "3.0.0",
"file-loader": "4.0.0",
"html-loader": "0.5.5",
"html-webpack-plugin": "3.2.0",
"ignore-loader": "0.1.2",
@ -83,8 +81,8 @@
"karma-jasmine-html-reporter": "1.4.2",
"karma-mocha-reporter": "2.2.5",
"karma-sourcemap-loader": "0.3.7",
"karma-webpack": "3.0.5",
"mini-css-extract-plugin": "0.6.0",
"karma-webpack": "4.0.2",
"mini-css-extract-plugin": "0.7.0",
"node-sass": "4.12.0",
"optimize-css-assets-webpack-plugin": "5.0.1",
"raw-loader": "1.0.0",
@ -93,17 +91,16 @@
"sass-lint": "1.13.1",
"sass-loader": "7.1.0",
"style-loader": "0.23.1",
"ts-loader": "5.4.5",
"ts-loader": "6.0.4",
"tsconfig-paths-webpack-plugin": "3.2.0",
"tslint": "5.16.0",
"tslint": "5.18.0",
"tslint-webpack-plugin": "2.0.4",
"typemoq": "2.1.0",
"typescript": "3.2.4",
"uglifyjs-webpack-plugin": "2.1.2",
"typescript": "3.4.3",
"uglifyjs-webpack-plugin": "2.1.3",
"underscore": "1.9.1",
"webpack": "4.30.0",
"webpack-cli": "3.3.1",
"webpack-dev-server": "3.3.1",
"webpack-merge": "4.2.1"
"webpack": "4.35.0",
"webpack-cli": "3.3.4",
"webpack-dev-server": "3.7.2"
}
}

1
src/Squidex/tsconfig.json

@ -3,6 +3,7 @@
"baseUrl": ".",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"incremental": true,
"importHelpers": true,
"lib": ["es6", "esnext", "dom"],
"moduleResolution": "node",

Loading…
Cancel
Save