Browse Source

Build fix (#699)

pull/701/head
Sebastian Stehle 5 years ago
committed by GitHub
parent
commit
e5751c8c5f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 118
      frontend/.eslintrc.js
  2. 4
      frontend/app-config/karma-test-shim.js
  3. 4
      frontend/app-config/karma.conf.js
  4. 4
      frontend/app-config/karma.coverage.conf.js
  5. 28
      frontend/app-config/webpack.config.js
  6. 6
      frontend/app/app.component.ts
  7. 15
      frontend/app/app.module.ts
  8. 42
      frontend/app/app.routes.ts
  9. 4
      frontend/app/app.ts
  10. 2
      frontend/app/declarations.d.ts
  11. 6
      frontend/app/features/administration/administration-area.component.ts
  12. 2
      frontend/app/features/administration/declarations.ts
  13. 19
      frontend/app/features/administration/guards/user-must-exist.guard.spec.ts
  14. 4
      frontend/app/features/administration/guards/user-must-exist.guard.ts
  15. 2
      frontend/app/features/administration/internal.ts
  16. 34
      frontend/app/features/administration/module.ts
  17. 4
      frontend/app/features/administration/pages/cluster/cluster-page.component.ts
  18. 8
      frontend/app/features/administration/pages/event-consumers/event-consumer.component.ts
  19. 6
      frontend/app/features/administration/pages/event-consumers/event-consumers-page.component.ts
  20. 6
      frontend/app/features/administration/pages/restore/restore-page.component.ts
  21. 6
      frontend/app/features/administration/pages/users/user-page.component.ts
  22. 8
      frontend/app/features/administration/pages/users/user.component.ts
  23. 8
      frontend/app/features/administration/pages/users/users-page.component.ts
  24. 146
      frontend/app/features/administration/services/event-consumers.service.spec.ts
  25. 6
      frontend/app/features/administration/services/event-consumers.service.ts
  26. 266
      frontend/app/features/administration/services/users.service.spec.ts
  27. 10
      frontend/app/features/administration/services/users.service.ts
  28. 2
      frontend/app/features/administration/state/event-consumers.state.spec.ts
  29. 6
      frontend/app/features/administration/state/event-consumers.state.ts
  30. 22
      frontend/app/features/administration/state/users.forms.ts
  31. 4
      frontend/app/features/administration/state/users.state.spec.ts
  32. 16
      frontend/app/features/administration/state/users.state.ts
  33. 6
      frontend/app/features/api/api-area.component.ts
  34. 2
      frontend/app/features/api/index.ts
  35. 18
      frontend/app/features/api/module.ts
  36. 10
      frontend/app/features/api/pages/graphql/graphql-page.component.ts
  37. 2
      frontend/app/features/apps/index.ts
  38. 12
      frontend/app/features/apps/module.ts
  39. 6
      frontend/app/features/apps/pages/app.component.ts
  40. 8
      frontend/app/features/apps/pages/apps-page.component.ts
  41. 4
      frontend/app/features/apps/pages/news-dialog.component.ts
  42. 6
      frontend/app/features/apps/pages/onboarding-dialog.component.ts
  43. 2
      frontend/app/features/assets/index.ts
  44. 16
      frontend/app/features/assets/module.ts
  45. 6
      frontend/app/features/assets/pages/asset-tags.component.ts
  46. 6
      frontend/app/features/assets/pages/assets-filters-page.component.ts
  47. 8
      frontend/app/features/assets/pages/assets-page.component.ts
  48. 2
      frontend/app/features/content/index.ts
  49. 50
      frontend/app/features/content/module.ts
  50. 6
      frontend/app/features/content/pages/comments/comments-page.component.ts
  51. 4
      frontend/app/features/content/pages/content/content-event.component.ts
  52. 10
      frontend/app/features/content/pages/content/content-history-page.component.ts
  53. 18
      frontend/app/features/content/pages/content/content-page.component.ts
  54. 4
      frontend/app/features/content/pages/content/editor/content-editor.component.ts
  55. 8
      frontend/app/features/content/pages/content/editor/content-field.component.ts
  56. 10
      frontend/app/features/content/pages/content/editor/content-section.component.ts
  57. 4
      frontend/app/features/content/pages/content/editor/field-languages.component.ts
  58. 8
      frontend/app/features/content/pages/content/references/content-references.component.ts
  59. 8
      frontend/app/features/content/pages/contents/contents-filters-page.component.ts
  60. 16
      frontend/app/features/content/pages/contents/contents-page.component.ts
  61. 6
      frontend/app/features/content/pages/contents/custom-view-editor.component.ts
  62. 6
      frontend/app/features/content/pages/schemas/schemas-page.component.ts
  63. 8
      frontend/app/features/content/pages/sidebar/sidebar-page.component.ts
  64. 8
      frontend/app/features/content/shared/content-extension.component.ts
  65. 4
      frontend/app/features/content/shared/content-status.component.ts
  66. 4
      frontend/app/features/content/shared/due-time-selector.component.ts
  67. 8
      frontend/app/features/content/shared/forms/array-editor.component.ts
  68. 8
      frontend/app/features/content/shared/forms/array-item.component.ts
  69. 20
      frontend/app/features/content/shared/forms/assets-editor.component.ts
  70. 4
      frontend/app/features/content/shared/forms/component-section.component.ts
  71. 8
      frontend/app/features/content/shared/forms/component.component.ts
  72. 4
      frontend/app/features/content/shared/forms/field-editor.component.ts
  73. 12
      frontend/app/features/content/shared/forms/iframe-editor.component.ts
  74. 10
      frontend/app/features/content/shared/forms/stock-photo-editor.component.ts
  75. 10
      frontend/app/features/content/shared/list/content-list-cell.directive.ts
  76. 6
      frontend/app/features/content/shared/list/content-list-field.component.ts
  77. 4
      frontend/app/features/content/shared/list/content-list-header.component.ts
  78. 4
      frontend/app/features/content/shared/list/content-value-editor.component.ts
  79. 4
      frontend/app/features/content/shared/list/content-value.component.ts
  80. 10
      frontend/app/features/content/shared/list/content.component.ts
  81. 10
      frontend/app/features/content/shared/preview-button.component.ts
  82. 8
      frontend/app/features/content/shared/references/content-creator.component.ts
  83. 4
      frontend/app/features/content/shared/references/content-selector-item.component.ts
  84. 10
      frontend/app/features/content/shared/references/content-selector.component.ts
  85. 4
      frontend/app/features/content/shared/references/reference-item.component.ts
  86. 10
      frontend/app/features/content/shared/references/references-editor.component.ts
  87. 2
      frontend/app/features/dashboard/index.ts
  88. 16
      frontend/app/features/dashboard/module.ts
  89. 12
      frontend/app/features/dashboard/pages/cards/api-calls-card.component.ts
  90. 6
      frontend/app/features/dashboard/pages/cards/api-calls-summary-card.component.ts
  91. 6
      frontend/app/features/dashboard/pages/cards/api-card.component.ts
  92. 11
      frontend/app/features/dashboard/pages/cards/api-performance-card.component.ts
  93. 11
      frontend/app/features/dashboard/pages/cards/api-traffic-card.component.ts
  94. 7
      frontend/app/features/dashboard/pages/cards/api-traffic-summary-card.component.ts
  95. 12
      frontend/app/features/dashboard/pages/cards/asset-uploads-count-card.component.ts
  96. 12
      frontend/app/features/dashboard/pages/cards/asset-uploads-size-card.component.ts
  97. 6
      frontend/app/features/dashboard/pages/cards/asset-uploads-size-summary-card.component.ts
  98. 10
      frontend/app/features/dashboard/pages/cards/content-summary-card.component.ts
  99. 6
      frontend/app/features/dashboard/pages/cards/github-card.component.ts
  100. 8
      frontend/app/features/dashboard/pages/cards/history-card.component.ts

118
frontend/.eslintrc.js

@ -0,0 +1,118 @@
/* eslint-disable */
module.exports = {
"env": {
"browser": true,
"node": true
},
"extends": [
"airbnb-typescript/base"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json"
},
"plugins": [
"eslint-plugin-import",
"@typescript-eslint",
],
"rules": {
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/indent": "off",
"@typescript-eslint/lines-between-class-members": "off",
"@typescript-eslint/member-delimiter-style": [
"error",
{
"multiline": {
"delimiter": "semi",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "variable",
"format": [
"camelCase",
"PascalCase",
"UPPER_CASE",
],
"leadingUnderscore": "allow",
"trailingUnderscore": "allow",
},
{
"selector": "typeLike",
"format": [
"PascalCase"
],
}
],
"@typescript-eslint/no-this-alias": "error",
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-shadow": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"@typescript-eslint/return-await": "off",
"@typescript-eslint/quotes": [
"error",
"single"
],
"@typescript-eslint/semi": [
"error",
"always"
],
"import/extensions": [
"error",
"never"
],
"import/extensions": "off",
"import/no-extraneous-dependencies": "off",
"import/no-useless-path-segments": "off",
"import/prefer-default-export": "off",
"arrow-body-style": "off",
"arrow-parens": "off",
"class-methods-use-this": "off",
"default-case": "off",
"function-paren-newline": "off",
"implicit-arrow-linebreak": "off",
"linebreak-style": "off",
"max-classes-per-file": "off",
"max-len": "off",
"newline-per-chained-call": "off",
"no-else-return": "off",
"no-mixed-operators": "off",
"no-nested-ternary": "off",
"no-param-reassign": "off",
"no-plusplus": "off",
"no-prototype-builtins": "off",
"no-restricted-syntax": "off",
"no-underscore-dangle": "off",
"object-curly-newline": [
"error",
{
"ObjectExpression": {
"consistent": true
},
"ObjectPattern": {
"consistent": true
},
"ImportDeclaration": "never",
"ExportDeclaration": "never"
}
],
"operator-linebreak": "off",
"prefer-destructuring": "off"
}
};

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

@ -1,4 +1,6 @@
Error.stackTraceLimit = Infinity; /* eslint-disable */
Error.stackTraceLimit = Infinity;
require('core-js/proposals/reflect-metadata'); require('core-js/proposals/reflect-metadata');

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

@ -1,4 +1,6 @@
const webpackConfig = require('./webpack.config'); /* eslint-disable */
const webpackConfig = require('./webpack.config');
module.exports = function (config) { module.exports = function (config) {
var _config = { var _config = {

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

@ -1,4 +1,6 @@
const webpackConfig = require('./webpack.config'); /* eslint-disable */
const webpackConfig = require('./webpack.config');
module.exports = function (config) { module.exports = function (config) {
var _config = { var _config = {

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

@ -1,3 +1,5 @@
/* eslint-disable */
const webpack = require('webpack'), path = require('path'); const webpack = require('webpack'), path = require('path');
const appRoot = path.resolve(__dirname, '..'); const appRoot = path.resolve(__dirname, '..');
@ -23,8 +25,8 @@ const plugins = {
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://github.com/jrparish/tslint-webpack-plugin // https://webpack.js.org/plugins/eslint-webpack-plugin/
TsLintPlugin: require('tslint-webpack-plugin'), ESLintPlugin: require('eslint-webpack-plugin'),
// https://www.npmjs.com/package/sass-lint-webpack // https://www.npmjs.com/package/sass-lint-webpack
SassLintPlugin: require('sass-lint-webpack'), SassLintPlugin: require('sass-lint-webpack'),
// https://www.npmjs.com/package/webpack-bundle-analyzer // https://www.npmjs.com/package/webpack-bundle-analyzer
@ -315,19 +317,15 @@ module.exports = function (env) {
}) })
); );
config.plugins.push( if (isProduction) {
new plugins.TsLintPlugin({ config.plugins.push(
files: ['./app/**/*.ts'], new plugins.ESLintPlugin({
/** files: [
* Path to a configuration file. './app/**/*.ts'
*/ ]
config: root('tslint.json'), })
/** );
* Wait for linting and fail the build when linting error occur. }
*/
waitForLinting: isProduction
})
);
} }
if (!isTestCoverage) { if (!isTestCoverage) {

6
frontend/app/app.component.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license
@ -10,8 +10,8 @@ import { Component } from '@angular/core';
@Component({ @Component({
selector: 'sqx-app', selector: 'sqx-app',
styleUrls: ['./app.component.scss'], styleUrls: ['./app.component.scss'],
templateUrl: './app.component.html' templateUrl: './app.component.html',
}) })
export class AppComponent { export class AppComponent {
public isLoaded?: boolean | null; public isLoaded?: boolean | null;
} }

15
frontend/app/app.module.ts

@ -1,4 +1,3 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
@ -6,6 +5,9 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
/* eslint-disable global-require */
/* eslint-disable import/no-dynamic-require */
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { ApplicationRef, NgModule } from '@angular/core'; import { ApplicationRef, NgModule } from '@angular/core';
@ -78,10 +80,10 @@ function configLocalizerService() {
SqxFrameworkModule.forRoot(), SqxFrameworkModule.forRoot(),
SqxSharedModule.forRoot(), SqxSharedModule.forRoot(),
SqxShellModule, SqxShellModule,
routing routing,
], ],
declarations: [ declarations: [
AppComponent AppComponent,
], ],
providers: [ providers: [
{ provide: ApiUrlConfig, useFactory: configApiUrl }, { provide: ApiUrlConfig, useFactory: configApiUrl },
@ -89,16 +91,17 @@ function configLocalizerService() {
{ provide: DecimalSeparatorConfig, useFactory: configDecimalSeparator }, { provide: DecimalSeparatorConfig, useFactory: configDecimalSeparator },
{ provide: LocalizerService, useFactory: configLocalizerService }, { provide: LocalizerService, useFactory: configLocalizerService },
{ provide: TitlesConfig, useFactory: configTitles }, { provide: TitlesConfig, useFactory: configTitles },
{ provide: UIOptions, useFactory: configUIOptions } { provide: UIOptions, useFactory: configUIOptions },
], ],
entryComponents: [AppComponent] entryComponents: [AppComponent],
}) })
export class AppModule { export class AppModule {
public ngDoBootstrap(appRef: ApplicationRef) { public ngDoBootstrap(appRef: ApplicationRef) {
try { try {
appRef.bootstrap(AppComponent); appRef.bootstrap(AppComponent);
} catch (e) { } catch (e) {
// eslint-disable-next-line no-console
console.log('Application element not found'); console.log('Application element not found');
} }
} }
} }

42
frontend/app/app.routes.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license
@ -14,7 +14,7 @@ const routes: Routes = [
{ {
path: '', path: '',
component: HomePageComponent, component: HomePageComponent,
canActivate: [MustBeNotAuthenticatedGuard] canActivate: [MustBeNotAuthenticatedGuard],
}, },
{ {
path: 'app', path: 'app',
@ -24,12 +24,12 @@ const routes: Routes = [
{ {
path: '', path: '',
loadChildren: () => import('./features/apps/module').then(m => m.SqxFeatureAppsModule), loadChildren: () => import('./features/apps/module').then(m => m.SqxFeatureAppsModule),
canActivate: [UnsetAppGuard] canActivate: [UnsetAppGuard],
}, },
{ {
path: 'administration', path: 'administration',
loadChildren: () => import('./features/administration/module').then(m => m.SqxFeatureAdministrationModule), loadChildren: () => import('./features/administration/module').then(m => m.SqxFeatureAdministrationModule),
canActivate: [UnsetAppGuard] canActivate: [UnsetAppGuard],
}, },
{ {
path: ':appName', path: ':appName',
@ -38,52 +38,52 @@ const routes: Routes = [
children: [ children: [
{ {
path: '', path: '',
loadChildren: () => import('./features/dashboard/module').then(m => m.SqxFeatureDashboardModule) loadChildren: () => import('./features/dashboard/module').then(m => m.SqxFeatureDashboardModule),
}, },
{ {
path: 'content', path: 'content',
loadChildren: () => import('./features/content/module').then(m => m.SqxFeatureContentModule) loadChildren: () => import('./features/content/module').then(m => m.SqxFeatureContentModule),
}, },
{ {
path: 'schemas', path: 'schemas',
loadChildren: () => import('./features/schemas/module').then(m => m.SqxFeatureSchemasModule) loadChildren: () => import('./features/schemas/module').then(m => m.SqxFeatureSchemasModule),
}, },
{ {
path: 'assets', path: 'assets',
loadChildren: () => import('./features/assets/module').then(m => m.SqxFeatureAssetsModule) loadChildren: () => import('./features/assets/module').then(m => m.SqxFeatureAssetsModule),
}, },
{ {
path: 'rules', path: 'rules',
loadChildren: () => import('./features/rules/module').then(m => m.SqxFeatureRulesModule) loadChildren: () => import('./features/rules/module').then(m => m.SqxFeatureRulesModule),
}, },
{ {
path: 'settings', path: 'settings',
loadChildren: () => import('./features/settings/module').then(m => m.SqxFeatureSettingsModule) loadChildren: () => import('./features/settings/module').then(m => m.SqxFeatureSettingsModule),
}, },
{ {
path: 'api', path: 'api',
loadChildren: () => import('./features/api/module').then(m => m.SqxFeatureApiModule) loadChildren: () => import('./features/api/module').then(m => m.SqxFeatureApiModule),
} },
] ],
} },
] ],
}, },
{ {
path: 'logout', path: 'logout',
component: LogoutPageComponent component: LogoutPageComponent,
}, },
{ {
path: 'login', path: 'login',
component: LoginPageComponent component: LoginPageComponent,
}, },
{ {
path: 'forbidden', path: 'forbidden',
component: ForbiddenPageComponent component: ForbiddenPageComponent,
}, },
{ {
path: '**', path: '**',
component: NotFoundPageComponent component: NotFoundPageComponent,
} },
]; ];
export const routing: ModuleWithProviders<RouterModule> = RouterModule.forRoot(routes, { useHash: false }); export const routing: ModuleWithProviders<RouterModule> = RouterModule.forRoot(routes, { useHash: false });

4
frontend/app/app.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license
@ -14,4 +14,4 @@ if (process.env.NODE_ENV === 'production') {
enableProdMode(); enableProdMode();
} }
platformBrowserDynamic().bootstrapModule(AppModule); platformBrowserDynamic().bootstrapModule(AppModule);

2
frontend/app/declarations.d.ts

@ -17,4 +17,4 @@ declare module 'sortablejs' {
} }
export function create(element: any, options: any): Ref; export function create(element: any, options: any): Ref;
} }

6
frontend/app/features/administration/administration-area.component.ts

@ -11,11 +11,11 @@ import { UIState } from '@app/shared';
@Component({ @Component({
selector: 'sqx-administration-area', selector: 'sqx-administration-area',
styleUrls: ['./administration-area.component.scss'], styleUrls: ['./administration-area.component.scss'],
templateUrl: './administration-area.component.html' templateUrl: './administration-area.component.html',
}) })
export class AdministrationAreaComponent { export class AdministrationAreaComponent {
constructor( constructor(
public readonly uiState: UIState public readonly uiState: UIState,
) { ) {
} }
} }

2
frontend/app/features/administration/declarations.ts

@ -14,4 +14,4 @@ export * from './pages/event-consumers/event-consumers-page.component';
export * from './pages/restore/restore-page.component'; export * from './pages/restore/restore-page.component';
export * from './pages/users/user-page.component'; export * from './pages/users/user-page.component';
export * from './pages/users/user.component'; export * from './pages/users/user.component';
export * from './pages/users/users-page.component'; export * from './pages/users/users-page.component';

19
frontend/app/features/administration/guards/user-must-exist.guard.spec.ts

@ -12,7 +12,6 @@ import { IMock, Mock, Times } from 'typemoq';
import { UserMustExistGuard } from './user-must-exist.guard'; import { UserMustExistGuard } from './user-must-exist.guard';
describe('UserMustExistGuard', () => { describe('UserMustExistGuard', () => {
let usersState: IMock<UsersState>; let usersState: IMock<UsersState>;
let router: IMock<Router>; let router: IMock<Router>;
let userGuard: UserMustExistGuard; let userGuard: UserMustExistGuard;
@ -31,8 +30,8 @@ describe('UserMustExistGuard', () => {
const route: any = { const route: any = {
params: { params: {
userId: '123' userId: '123',
} },
}; };
userGuard.canActivate(route).subscribe(x => { userGuard.canActivate(route).subscribe(x => {
@ -52,8 +51,8 @@ describe('UserMustExistGuard', () => {
const route: any = { const route: any = {
params: { params: {
userId: '123' userId: '123',
} },
}; };
userGuard.canActivate(route).subscribe(x => { userGuard.canActivate(route).subscribe(x => {
@ -73,8 +72,8 @@ describe('UserMustExistGuard', () => {
const route: any = { const route: any = {
params: { params: {
userId: undefined userId: undefined,
} },
}; };
userGuard.canActivate(route).subscribe(x => { userGuard.canActivate(route).subscribe(x => {
@ -94,8 +93,8 @@ describe('UserMustExistGuard', () => {
const route: any = { const route: any = {
params: { params: {
userId: 'new' userId: 'new',
} },
}; };
userGuard.canActivate(route).subscribe(x => { userGuard.canActivate(route).subscribe(x => {
@ -106,4 +105,4 @@ describe('UserMustExistGuard', () => {
usersState.verify(x => x.select(null), Times.once()); usersState.verify(x => x.select(null), Times.once());
}); });
}); });

4
frontend/app/features/administration/guards/user-must-exist.guard.ts

@ -16,7 +16,7 @@ import { map, tap } from 'rxjs/operators';
export class UserMustExistGuard implements CanActivate { export class UserMustExistGuard implements CanActivate {
constructor( constructor(
private readonly usersState: UsersState, private readonly usersState: UsersState,
private readonly router: Router private readonly router: Router,
) { ) {
} }
@ -38,4 +38,4 @@ export class UserMustExistGuard implements CanActivate {
return result; return result;
} }
} }

2
frontend/app/features/administration/internal.ts

@ -9,4 +9,4 @@ export * from './services/event-consumers.service';
export * from './services/users.service'; export * from './services/users.service';
export * from './state/event-consumers.state'; export * from './state/event-consumers.state';
export * from './state/users.forms'; export * from './state/users.forms';
export * from './state/users.state'; export * from './state/users.state';

34
frontend/app/features/administration/module.ts

@ -5,8 +5,6 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: max-line-length
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { SqxFrameworkModule, SqxSharedModule } from '@app/shared'; import { SqxFrameworkModule, SqxSharedModule } from '@app/shared';
@ -22,15 +20,15 @@ const routes: Routes = [
children: [ children: [
{ {
path: 'event-consumers', path: 'event-consumers',
component: EventConsumersPageComponent component: EventConsumersPageComponent,
}, },
{ {
path: 'cluster', path: 'cluster',
component: ClusterPageComponent component: ClusterPageComponent,
}, },
{ {
path: 'restore', path: 'restore',
component: RestorePageComponent component: RestorePageComponent,
}, },
{ {
path: 'users', path: 'users',
@ -39,21 +37,21 @@ const routes: Routes = [
{ {
path: ':userId', path: ':userId',
component: UserPageComponent, component: UserPageComponent,
canActivate: [UserMustExistGuard] canActivate: [UserMustExistGuard],
} },
] ],
} },
] ],
} },
] ],
} },
]; ];
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild(routes), RouterModule.forChild(routes),
SqxFrameworkModule, SqxFrameworkModule,
SqxSharedModule SqxSharedModule,
], ],
declarations: [ declarations: [
AdministrationAreaComponent, AdministrationAreaComponent,
@ -63,14 +61,14 @@ const routes: Routes = [
RestorePageComponent, RestorePageComponent,
UserComponent, UserComponent,
UserPageComponent, UserPageComponent,
UsersPageComponent UsersPageComponent,
], ],
providers: [ providers: [
EventConsumersService, EventConsumersService,
EventConsumersState, EventConsumersState,
UserMustExistGuard, UserMustExistGuard,
UsersService, UsersService,
UsersState UsersState,
] ],
}) })
export class SqxFeatureAdministrationModule {} export class SqxFeatureAdministrationModule {}

4
frontend/app/features/administration/pages/cluster/cluster-page.component.ts

@ -10,7 +10,7 @@ import { Component } from '@angular/core';
@Component({ @Component({
selector: 'sqx-cluster-area', selector: 'sqx-cluster-area',
styleUrls: ['./cluster-page.component.scss'], styleUrls: ['./cluster-page.component.scss'],
templateUrl: './cluster-page.component.html' templateUrl: './cluster-page.component.html',
}) })
export class ClusterPageComponent { export class ClusterPageComponent {
} }

8
frontend/app/features/administration/pages/event-consumers/event-consumer.component.ts

@ -5,8 +5,6 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: component-selector
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { EventConsumerDto, EventConsumersState } from '@app/features/administration/internal'; import { EventConsumerDto, EventConsumersState } from '@app/features/administration/internal';
@ -14,7 +12,7 @@ import { EventConsumerDto, EventConsumersState } from '@app/features/administrat
selector: '[sqxEventConsumer]', selector: '[sqxEventConsumer]',
styleUrls: ['./event-consumer.component.scss'], styleUrls: ['./event-consumer.component.scss'],
templateUrl: './event-consumer.component.html', templateUrl: './event-consumer.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class EventConsumerComponent { export class EventConsumerComponent {
@Output() @Output()
@ -24,7 +22,7 @@ export class EventConsumerComponent {
public eventConsumer: EventConsumerDto; public eventConsumer: EventConsumerDto;
constructor( constructor(
private readonly eventConsumersState: EventConsumersState private readonly eventConsumersState: EventConsumersState,
) { ) {
} }
@ -39,4 +37,4 @@ export class EventConsumerComponent {
public reset() { public reset() {
this.eventConsumersState.reset(this.eventConsumer); this.eventConsumersState.reset(this.eventConsumer);
} }
} }

6
frontend/app/features/administration/pages/event-consumers/event-consumers-page.component.ts

@ -14,14 +14,14 @@ import { switchMap } from 'rxjs/operators';
@Component({ @Component({
selector: 'sqx-event-consumers-page', selector: 'sqx-event-consumers-page',
styleUrls: ['./event-consumers-page.component.scss'], styleUrls: ['./event-consumers-page.component.scss'],
templateUrl: './event-consumers-page.component.html' templateUrl: './event-consumers-page.component.html',
}) })
export class EventConsumersPageComponent extends ResourceOwner implements OnInit { export class EventConsumersPageComponent extends ResourceOwner implements OnInit {
public eventConsumerErrorDialog = new DialogModel(); public eventConsumerErrorDialog = new DialogModel();
public eventConsumerError?: string; public eventConsumerError?: string;
constructor( constructor(
public readonly eventConsumersState: EventConsumersState public readonly eventConsumersState: EventConsumersState,
) { ) {
super(); super();
} }
@ -44,4 +44,4 @@ export class EventConsumersPageComponent extends ResourceOwner implements OnInit
this.eventConsumerError = eventConsumer.error; this.eventConsumerError = eventConsumer.error;
this.eventConsumerErrorDialog.show(); this.eventConsumerErrorDialog.show();
} }
} }

6
frontend/app/features/administration/pages/restore/restore-page.component.ts

@ -13,7 +13,7 @@ import { timer } from 'rxjs';
@Component({ @Component({
selector: 'sqx-restore-page', selector: 'sqx-restore-page',
styleUrls: ['./restore-page.component.scss'], styleUrls: ['./restore-page.component.scss'],
templateUrl: './restore-page.component.html' templateUrl: './restore-page.component.html',
}) })
export class RestorePageComponent { export class RestorePageComponent {
public restoreForm = new RestoreForm(this.formBuilder); public restoreForm = new RestoreForm(this.formBuilder);
@ -25,7 +25,7 @@ export class RestorePageComponent {
public readonly authState: AuthService, public readonly authState: AuthService,
private readonly backupsService: BackupsService, private readonly backupsService: BackupsService,
private readonly dialogs: DialogService, private readonly dialogs: DialogService,
private readonly formBuilder: FormBuilder private readonly formBuilder: FormBuilder,
) { ) {
} }
@ -43,4 +43,4 @@ export class RestorePageComponent {
}); });
} }
} }
} }

6
frontend/app/features/administration/pages/users/user-page.component.ts

@ -14,7 +14,7 @@ import { ResourceOwner } from '@app/shared';
@Component({ @Component({
selector: 'sqx-user-page', selector: 'sqx-user-page',
styleUrls: ['./user-page.component.scss'], styleUrls: ['./user-page.component.scss'],
templateUrl: './user-page.component.html' templateUrl: './user-page.component.html',
}) })
export class UserPageComponent extends ResourceOwner implements OnInit { export class UserPageComponent extends ResourceOwner implements OnInit {
public isEditable = false; public isEditable = false;
@ -26,7 +26,7 @@ export class UserPageComponent extends ResourceOwner implements OnInit {
public readonly usersState: UsersState, public readonly usersState: UsersState,
private readonly formBuilder: FormBuilder, private readonly formBuilder: FormBuilder,
private readonly route: ActivatedRoute, private readonly route: ActivatedRoute,
private readonly router: Router private readonly router: Router,
) { ) {
super(); super();
} }
@ -41,7 +41,7 @@ export class UserPageComponent extends ResourceOwner implements OnInit {
const permissions: string[] = []; const permissions: string[] = [];
this.userForm.load(user || { permissions } ); this.userForm.load(user || { permissions });
this.userForm.setEnabled(this.isEditable); this.userForm.setEnabled(this.isEditable);
})); }));
} }

8
frontend/app/features/administration/pages/users/user.component.ts

@ -5,8 +5,6 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: component-selector
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { UserDto, UsersState } from '@app/features/administration/internal'; import { UserDto, UsersState } from '@app/features/administration/internal';
@ -14,14 +12,14 @@ import { UserDto, UsersState } from '@app/features/administration/internal';
selector: '[sqxUser]', selector: '[sqxUser]',
styleUrls: ['./user.component.scss'], styleUrls: ['./user.component.scss'],
templateUrl: './user.component.html', templateUrl: './user.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class UserComponent { export class UserComponent {
@Input('sqxUser') @Input('sqxUser')
public user: UserDto; public user: UserDto;
constructor( constructor(
private readonly usersState: UsersState private readonly usersState: UsersState,
) { ) {
} }
@ -36,4 +34,4 @@ export class UserComponent {
public delete() { public delete() {
this.usersState.delete(this.user); this.usersState.delete(this.user);
} }
} }

8
frontend/app/features/administration/pages/users/users-page.component.ts

@ -15,15 +15,15 @@ import { ResourceOwner, Router2State } from '@app/framework';
styleUrls: ['./users-page.component.scss'], styleUrls: ['./users-page.component.scss'],
templateUrl: './users-page.component.html', templateUrl: './users-page.component.html',
providers: [ providers: [
Router2State Router2State,
] ],
}) })
export class UsersPageComponent extends ResourceOwner implements OnInit { export class UsersPageComponent extends ResourceOwner implements OnInit {
public usersFilter = new FormControl(); public usersFilter = new FormControl();
constructor( constructor(
public readonly usersRoute: Router2State, public readonly usersRoute: Router2State,
public readonly usersState: UsersState public readonly usersState: UsersState,
) { ) {
super(); super();
@ -54,4 +54,4 @@ export class UsersPageComponent extends ResourceOwner implements OnInit {
public trackByUser(_index: number, user: UserDto) { public trackByUser(_index: number, user: UserDto) {
return user.id; return user.id;
} }
} }

146
frontend/app/features/administration/services/event-consumers.service.spec.ts

@ -14,12 +14,12 @@ describe('EventConsumersService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
HttpClientTestingModule HttpClientTestingModule,
], ],
providers: [ providers: [
EventConsumersService, EventConsumersService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
] ],
}); });
}); });
@ -29,106 +29,102 @@ describe('EventConsumersService', () => {
it('should make get request to get event consumers', it('should make get request to get event consumers',
inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => { inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => {
let eventConsumers: EventConsumersDto;
let eventConsumers: EventConsumersDto; eventConsumersService.getEventConsumers().subscribe(result => {
eventConsumers = result;
});
eventConsumersService.getEventConsumers().subscribe(result => { const req = httpMock.expectOne('http://service/p/api/event-consumers');
eventConsumers = result;
});
const req = httpMock.expectOne('http://service/p/api/event-consumers'); expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();
expect(req.request.method).toEqual('GET'); req.flush({
expect(req.request.headers.get('If-Match')).toBeNull(); items: [
eventConsumerResponse(12),
eventConsumerResponse(13),
],
});
req.flush({ expect(eventConsumers!).toEqual(
items: [ new EventConsumersDto([
eventConsumerResponse(12), createEventConsumer(12),
eventConsumerResponse(13) createEventConsumer(13),
] ]));
}); }));
expect(eventConsumers!).toEqual(
new EventConsumersDto([
createEventConsumer(12),
createEventConsumer(13)
]));
}));
it('should make put request to start event consumer', it('should make put request to start event consumer',
inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => { inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => {
const resource: Resource = {
_links: {
start: { method: 'PUT', href: 'api/event-consumers/event-consumer123/start' },
},
};
const resource: Resource = { let eventConsumer: EventConsumerDto;
_links: {
start: { method: 'PUT', href: 'api/event-consumers/event-consumer123/start' }
}
};
let eventConsumer: EventConsumerDto; eventConsumersService.putStart(resource).subscribe(response => {
eventConsumer = response;
});
eventConsumersService.putStart(resource).subscribe(response => { const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer123/start');
eventConsumer = response;
});
const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer123/start'); expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toBeNull();
expect(req.request.method).toEqual('PUT'); req.flush(eventConsumerResponse(123));
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(eventConsumerResponse(123)); expect(eventConsumer!).toEqual(createEventConsumer(123));
}));
expect(eventConsumer!).toEqual(createEventConsumer(123));
}));
it('should make put request to stop event consumer', it('should make put request to stop event consumer',
inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => { inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => {
const resource: Resource = {
_links: {
stop: { method: 'PUT', href: 'api/event-consumers/event-consumer123/stop' },
},
};
const resource: Resource = { let eventConsumer: EventConsumerDto;
_links: {
stop: { method: 'PUT', href: 'api/event-consumers/event-consumer123/stop' }
}
};
let eventConsumer: EventConsumerDto; eventConsumersService.putStop(resource).subscribe(response => {
eventConsumer = response;
});
eventConsumersService.putStop(resource).subscribe(response => { const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer123/stop');
eventConsumer = response;
});
const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer123/stop'); expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toBeNull();
expect(req.request.method).toEqual('PUT'); req.flush(eventConsumerResponse(12));
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(eventConsumerResponse(12)); expect(eventConsumer!).toEqual(createEventConsumer(12));
}));
expect(eventConsumer!).toEqual(createEventConsumer(12));
}));
it('should make put request to reset event consumer', it('should make put request to reset event consumer',
inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => { inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => {
const resource: Resource = {
_links: {
reset: { method: 'PUT', href: 'api/event-consumers/event-consumer123/reset' },
},
};
const resource: Resource = { let eventConsumer: EventConsumerDto;
_links: {
reset: { method: 'PUT', href: 'api/event-consumers/event-consumer123/reset' }
}
};
let eventConsumer: EventConsumerDto; eventConsumersService.putReset(resource).subscribe(response => {
eventConsumer = response;
});
eventConsumersService.putReset(resource).subscribe(response => { const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer123/reset');
eventConsumer = response;
});
const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer123/reset'); expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toBeNull();
expect(req.request.method).toEqual('PUT'); req.flush(eventConsumerResponse(12));
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(eventConsumerResponse(12)); expect(eventConsumer!).toEqual(createEventConsumer(12));
}));
expect(eventConsumer!).toEqual(createEventConsumer(12));
}));
function eventConsumerResponse(id: number, suffix = '') { function eventConsumerResponse(id: number, suffix = '') {
const key = `${id}${suffix}`; const key = `${id}${suffix}`;
@ -141,15 +137,15 @@ describe('EventConsumersService', () => {
isResetting: true, isResetting: true,
error: `failure${key}`, error: `failure${key}`,
_links: { _links: {
reset: { method: 'PUT', href: `/event-consumers/${id}/reset` } reset: { method: 'PUT', href: `/event-consumers/${id}/reset` },
} },
}; };
} }
}); });
export function createEventConsumer(id: number, suffix = '') { export function createEventConsumer(id: number, suffix = '') {
const links: ResourceLinks = { const links: ResourceLinks = {
reset: { method: 'PUT', href: `/event-consumers/${id}/reset` } reset: { method: 'PUT', href: `/event-consumers/${id}/reset` },
}; };
const key = `${id}${suffix}`; const key = `${id}${suffix}`;
@ -161,4 +157,4 @@ export function createEventConsumer(id: number, suffix = '') {
true, true,
`failure${key}`, `failure${key}`,
`position${key}`); `position${key}`);
} }

6
frontend/app/features/administration/services/event-consumers.service.ts

@ -15,7 +15,7 @@ export class EventConsumersDto {
public readonly _links: ResourceLinks; public readonly _links: ResourceLinks;
constructor( constructor(
public readonly items: ReadonlyArray<EventConsumerDto>, links?: ResourceLinks public readonly items: ReadonlyArray<EventConsumerDto>, links?: ResourceLinks,
) { ) {
this._links = links || {}; this._links = links || {};
} }
@ -34,7 +34,7 @@ export class EventConsumerDto {
public readonly isStopped?: boolean, public readonly isStopped?: boolean,
public readonly isResetting?: boolean, public readonly isResetting?: boolean,
public readonly error?: string, public readonly error?: string,
public readonly position?: string public readonly position?: string,
) { ) {
this._links = links; this._links = links;
@ -48,7 +48,7 @@ export class EventConsumerDto {
export class EventConsumersService { export class EventConsumersService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig private readonly apiUrl: ApiUrlConfig,
) { ) {
} }

266
frontend/app/features/administration/services/users.service.spec.ts

@ -11,15 +11,15 @@ import { ApiUrlConfig, Resource, ResourceLinks } from '@app/framework';
import { UserDto, UsersDto, UsersService } from './users.service'; import { UserDto, UsersDto, UsersService } from './users.service';
describe('UsersService', () => { describe('UsersService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
HttpClientTestingModule HttpClientTestingModule,
], ],
providers: [ providers: [
UsersService, UsersService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
] ],
}); });
}); });
@ -29,197 +29,189 @@ describe('UsersService', () => {
it('should make get request to get many users', it('should make get request to get many users',
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => {
let users: UsersDto;
let users: UsersDto; userManagementService.getUsers(20, 30).subscribe(result => {
users = result;
});
userManagementService.getUsers(20, 30).subscribe(result => { const req = httpMock.expectOne('http://service/p/api/user-management?take=20&skip=30&query=');
users = result;
});
const req = httpMock.expectOne('http://service/p/api/user-management?take=20&skip=30&query='); expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();
expect(req.request.method).toEqual('GET'); req.flush({
expect(req.request.headers.get('If-Match')).toBeNull(); total: 100,
items: [
userResponse(12),
userResponse(13),
],
});
req.flush({ expect(users!).toEqual(
total: 100, new UsersDto(100, [
items: [ createUser(12),
userResponse(12), createUser(13),
userResponse(13) ]));
] }));
});
expect(users!).toEqual(
new UsersDto(100, [
createUser(12),
createUser(13)
]));
}));
it('should make get request with query to get many users', it('should make get request with query to get many users',
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => {
let users: UsersDto;
let users: UsersDto; userManagementService.getUsers(20, 30, 'my-query').subscribe(result => {
users = result;
});
userManagementService.getUsers(20, 30, 'my-query').subscribe(result => { const req = httpMock.expectOne('http://service/p/api/user-management?take=20&skip=30&query=my-query');
users = result;
});
const req = httpMock.expectOne('http://service/p/api/user-management?take=20&skip=30&query=my-query');
expect(req.request.method).toEqual('GET'); expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull(); expect(req.request.headers.get('If-Match')).toBeNull();
req.flush({ req.flush({
total: 100, total: 100,
items: [ items: [
userResponse(12), userResponse(12),
userResponse(13) userResponse(13),
] ],
}); });
expect(users!).toEqual( expect(users!).toEqual(
new UsersDto(100, [ new UsersDto(100, [
createUser(12), createUser(12),
createUser(13) createUser(13),
])); ]));
})); }));
it('should make get request to get single user', it('should make get request to get single user',
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => {
let user: UserDto;
let user: UserDto; userManagementService.getUser('123').subscribe(result => {
user = result;
});
userManagementService.getUser('123').subscribe(result => { const req = httpMock.expectOne('http://service/p/api/user-management/123');
user = result;
});
const req = httpMock.expectOne('http://service/p/api/user-management/123');
expect(req.request.method).toEqual('GET'); expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull(); expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(userResponse(12)); req.flush(userResponse(12));
expect(user!).toEqual(createUser(12)); expect(user!).toEqual(createUser(12));
})); }));
it('should make post request to create user', it('should make post request to create user',
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => {
const dto = { email: 'mail@squidex.io', displayName: 'Squidex User', permissions: ['Permission1'], password: 'password' };
const dto = { email: 'mail@squidex.io', displayName: 'Squidex User', permissions: ['Permission1'], password: 'password' }; let user: UserDto;
let user: UserDto;
userManagementService.postUser(dto).subscribe(result => { userManagementService.postUser(dto).subscribe(result => {
user = result; user = result;
}); });
const req = httpMock.expectOne('http://service/p/api/user-management'); const req = httpMock.expectOne('http://service/p/api/user-management');
expect(req.request.method).toEqual('POST'); expect(req.request.method).toEqual('POST');
expect(req.request.headers.get('If-Match')).toBeNull(); expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(userResponse(12)); req.flush(userResponse(12));
expect(user!).toEqual(createUser(12)); expect(user!).toEqual(createUser(12));
})); }));
it('should make put request to update user', it('should make put request to update user',
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => {
const dto = { email: 'mail@squidex.io', displayName: 'Squidex User', permissions: ['Permission1'], password: 'password' };
const dto = { email: 'mail@squidex.io', displayName: 'Squidex User', permissions: ['Permission1'], password: 'password' }; const resource: Resource = {
_links: {
const resource: Resource = { update: { method: 'PUT', href: 'api/user-management/123' },
_links: { },
update: { method: 'PUT', href: 'api/user-management/123' } };
}
};
let user: UserDto; let user: UserDto;
userManagementService.putUser(resource, dto).subscribe(result => { userManagementService.putUser(resource, dto).subscribe(result => {
user = result; user = result;
}); });
const req = httpMock.expectOne('http://service/p/api/user-management/123'); const req = httpMock.expectOne('http://service/p/api/user-management/123');
expect(req.request.method).toEqual('PUT'); expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toBeNull(); expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(userResponse(12)); req.flush(userResponse(12));
expect(user!).toEqual(createUser(12)); expect(user!).toEqual(createUser(12));
})); }));
it('should make put request to lock user', it('should make put request to lock user',
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => {
const resource: Resource = {
_links: {
lock: { method: 'PUT', href: 'api/user-management/123/lock' },
},
};
const resource: Resource = { let user: UserDto;
_links: {
lock: { method: 'PUT', href: 'api/user-management/123/lock' }
}
};
let user: UserDto; userManagementService.lockUser(resource).subscribe(result => {
user = result;
});
userManagementService.lockUser(resource).subscribe(result => { const req = httpMock.expectOne('http://service/p/api/user-management/123/lock');
user = result;
});
const req = httpMock.expectOne('http://service/p/api/user-management/123/lock');
expect(req.request.method).toEqual('PUT'); expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toBeNull(); expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(userResponse(12)); req.flush(userResponse(12));
expect(user!).toEqual(createUser(12)); expect(user!).toEqual(createUser(12));
})); }));
it('should make put request to unlock user', it('should make put request to unlock user',
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => {
const resource: Resource = {
_links: {
unlock: { method: 'PUT', href: 'api/user-management/123/unlock' },
},
};
const resource: Resource = { let user: UserDto;
_links: {
unlock: { method: 'PUT', href: 'api/user-management/123/unlock' }
}
};
let user: UserDto;
userManagementService.unlockUser(resource).subscribe(result => { userManagementService.unlockUser(resource).subscribe(result => {
user = result; user = result;
}); });
const req = httpMock.expectOne('http://service/p/api/user-management/123/unlock'); const req = httpMock.expectOne('http://service/p/api/user-management/123/unlock');
expect(req.request.method).toEqual('PUT'); expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toBeNull(); expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(userResponse(12)); req.flush(userResponse(12));
expect(user!).toEqual(createUser(12)); expect(user!).toEqual(createUser(12));
})); }));
it('should make delete request to delete user', it('should make delete request to delete user',
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => {
const resource: Resource = {
_links: {
delete: { method: 'DELETE', href: 'api/user-management/123' },
},
};
const resource: Resource = { userManagementService.deleteUser(resource).subscribe();
_links: {
delete: { method: 'DELETE', href: 'api/user-management/123' }
}
};
userManagementService.deleteUser(resource).subscribe(); const req = httpMock.expectOne('http://service/p/api/user-management/123');
const req = httpMock.expectOne('http://service/p/api/user-management/123'); expect(req.request.method).toEqual('DELETE');
expect(req.request.headers.get('If-Match')).toBeNull();
expect(req.request.method).toEqual('DELETE'); req.flush({});
expect(req.request.headers.get('If-Match')).toBeNull(); }));
req.flush({});
}));
function userResponse(id: number, suffix = '') { function userResponse(id: number, suffix = '') {
const key = `${id}${suffix}`; const key = `${id}${suffix}`;
@ -229,21 +221,21 @@ describe('UsersService', () => {
email: `user${key}@domain.com`, email: `user${key}@domain.com`,
displayName: `user${key}`, displayName: `user${key}`,
permissions: [ permissions: [
`Permission${key}` `Permission${key}`,
], ],
isLocked: true, isLocked: true,
_links: { _links: {
update: { update: {
method: 'PUT', href: `/users/${id}` method: 'PUT', href: `/users/${id}`,
} },
} },
}; };
} }
}); });
export function createUser(id: number, suffix = '') { export function createUser(id: number, suffix = '') {
const links: ResourceLinks = { const links: ResourceLinks = {
update: { method: 'PUT', href: `/users/${id}` } update: { method: 'PUT', href: `/users/${id}` },
}; };
const key = `${id}${suffix}`; const key = `${id}${suffix}`;
@ -253,7 +245,7 @@ export function createUser(id: number, suffix = '') {
`user${key}@domain.com`, `user${key}@domain.com`,
`user${key}`, `user${key}`,
[ [
`Permission${key}` `Permission${key}`,
], ],
true); true);
} }

10
frontend/app/features/administration/services/users.service.ts

@ -30,7 +30,7 @@ export class UserDto {
public readonly email: string, public readonly email: string,
public readonly displayName: string, public readonly displayName: string,
public readonly permissions: ReadonlyArray<string> = [], public readonly permissions: ReadonlyArray<string> = [],
public readonly isLocked?: boolean public readonly isLocked?: boolean,
) { ) {
this._links = links; this._links = links;
@ -44,7 +44,7 @@ export class UserDto {
type Permissions = readonly string[]; type Permissions = readonly string[];
export type CreateUserDto = export type CreateUserDto =
Readonly<{ email: string, displayName: string, permissions: Permissions, password: string }>; Readonly<{ email: string; displayName: string; permissions: Permissions; password: string }>;
export type UpdateUserDto = export type UpdateUserDto =
Partial<CreateUserDto>; Partial<CreateUserDto>;
@ -53,14 +53,14 @@ export type UpdateUserDto =
export class UsersService { export class UsersService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig private readonly apiUrl: ApiUrlConfig,
) { ) {
} }
public getUsers(take: number, skip: number, query?: string): Observable<UsersDto> { public getUsers(take: number, skip: number, query?: string): Observable<UsersDto> {
const url = this.apiUrl.buildUrl(`api/user-management?take=${take}&skip=${skip}&query=${query || ''}`); const url = this.apiUrl.buildUrl(`api/user-management?take=${take}&skip=${skip}&query=${query || ''}`);
return this.http.get<{ total: number, items: any[] } & Resource>(url).pipe( return this.http.get<{ total: number; items: any[] } & Resource>(url).pipe(
map(({ total, items, _links }) => { map(({ total, items, _links }) => {
const users = items.map(parseUser); const users = items.map(parseUser);
@ -143,4 +143,4 @@ function parseUser(response: any) {
response.displayName, response.displayName,
response.permissions, response.permissions,
response.isLocked); response.isLocked);
} }

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

@ -119,4 +119,4 @@ describe('EventConsumersState', () => {
expect(eventConsumersState.snapshot.eventConsumers).toEqual([eventConsumer1, updated]); expect(eventConsumersState.snapshot.eventConsumers).toEqual([eventConsumer1, updated]);
}); });
}); });
}); });

6
frontend/app/features/administration/state/event-consumers.state.ts

@ -37,7 +37,7 @@ export class EventConsumersState extends State<Snapshot> {
constructor( constructor(
private readonly dialogs: DialogService, private readonly dialogs: DialogService,
private readonly eventConsumersService: EventConsumersService private readonly eventConsumersService: EventConsumersService,
) { ) {
super({ eventConsumers: [] }, 'EventConsumers'); super({ eventConsumers: [] }, 'EventConsumers');
} }
@ -64,7 +64,7 @@ export class EventConsumersState extends State<Snapshot> {
this.next({ this.next({
eventConsumers, eventConsumers,
isLoaded: true, isLoaded: true,
isLoading: false isLoading: false,
}, 'Loading Success'); }, 'Loading Success');
}), }),
finalize(() => { finalize(() => {
@ -104,4 +104,4 @@ export class EventConsumersState extends State<Snapshot> {
return { ...s, eventConsumers }; return { ...s, eventConsumers };
}, 'Updated'); }, 'Updated');
} }
} }

22
frontend/app/features/administration/state/users.forms.ts

@ -11,33 +11,33 @@ import { UpdateUserDto, UserDto } from './../services/users.service';
export class UserForm extends Form<FormGroup, UpdateUserDto, UserDto> { export class UserForm extends Form<FormGroup, UpdateUserDto, UserDto> {
constructor( constructor(
formBuilder: FormBuilder formBuilder: FormBuilder,
) { ) {
super(formBuilder.group({ super(formBuilder.group({
email: ['', email: ['',
[ [
Validators.email, Validators.email,
Validators.required, Validators.required,
Validators.maxLength(100) Validators.maxLength(100),
] ],
], ],
displayName: ['', displayName: ['',
[ [
Validators.required, Validators.required,
Validators.maxLength(100) Validators.maxLength(100),
] ],
], ],
password: ['', password: ['',
[ [
Validators.required Validators.required,
] ],
], ],
passwordConfirm: ['', passwordConfirm: ['',
[ [
ValidatorsEx.match('password', 'i18n:users.passwordConfirmValidationMessage') ValidatorsEx.match('password', 'i18n:users.passwordConfirmValidationMessage'),
] ],
], ],
permissions: [''] permissions: [''],
})); }));
} }
@ -62,4 +62,4 @@ export class UserForm extends Form<FormGroup, UpdateUserDto, UserDto> {
return { ...value, permissions }; return { ...value, permissions };
} }
} }

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

@ -234,7 +234,7 @@ describe('UsersState', () => {
it('should update selected user if reloaded', () => { it('should update selected user if reloaded', () => {
const newUsers = [ const newUsers = [
createUser(1, '_new'), createUser(1, '_new'),
createUser(2, '_new') createUser(2, '_new'),
]; ];
usersService.setup(x => x.getUsers(10, 0, undefined)) usersService.setup(x => x.getUsers(10, 0, undefined))
@ -267,4 +267,4 @@ describe('UsersState', () => {
expect(usersState.snapshot.selectedUser).toBeNull(); expect(usersState.snapshot.selectedUser).toBeNull();
}); });
}); });
}); });

16
frontend/app/features/administration/state/users.state.ts

@ -5,6 +5,8 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
/* eslint-disable object-curly-newline */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import '@app/framework/utils/rxjs-extensions'; import '@app/framework/utils/rxjs-extensions';
import { DialogService, getPagingInfo, ListState, shareSubscribed, State } from '@app/shared'; import { DialogService, getPagingInfo, ListState, shareSubscribed, State } from '@app/shared';
@ -24,7 +26,7 @@ interface Snapshot extends ListState<string> {
} }
export type UsersList = ReadonlyArray<UserDto>; export type UsersList = ReadonlyArray<UserDto>;
export type UsersResult = { total: number, users: UsersList }; export type UsersResult = { total: number; users: UsersList };
@Injectable() @Injectable()
export class UsersState extends State<Snapshot> { export class UsersState extends State<Snapshot> {
@ -51,13 +53,13 @@ export class UsersState extends State<Snapshot> {
constructor( constructor(
private readonly dialogs: DialogService, private readonly dialogs: DialogService,
private readonly usersService: UsersService private readonly usersService: UsersService,
) { ) {
super({ super({
users: [], users: [],
page: 0, page: 0,
pageSize: 10, pageSize: 10,
total: 0 total: 0,
}, 'Users'); }, 'Users');
} }
@ -119,7 +121,7 @@ export class UsersState extends State<Snapshot> {
isLoaded: true, isLoaded: true,
isLoading: false, isLoading: false,
selectedUser, selectedUser,
total total,
}; };
}, 'Loading Success'); }, 'Loading Success');
}), }),
@ -190,7 +192,7 @@ export class UsersState extends State<Snapshot> {
return this.loadInternal(false); return this.loadInternal(false);
} }
public page(paging: { page: number, pageSize: number }) { public page(paging: { page: number; pageSize: number }) {
if (!this.next(paging, 'Loading Paged')) { if (!this.next(paging, 'Loading Paged')) {
return EMPTY; return EMPTY;
} }
@ -200,7 +202,7 @@ export class UsersState extends State<Snapshot> {
private replaceUser(user: UserDto) { private replaceUser(user: UserDto) {
return this.next(s => { return this.next(s => {
const users = s.users.map(u => u.id === user.id ? user : u); const users = s.users.map(u => (u.id === user.id ? user : u));
const selectedUser = const selectedUser =
s.selectedUser?.id !== user.id ? s.selectedUser?.id !== user.id ?
@ -210,4 +212,4 @@ export class UsersState extends State<Snapshot> {
return { ...s, users, selectedUser }; return { ...s, users, selectedUser };
}, 'Updated'); }, 'Updated');
} }
} }

6
frontend/app/features/api/api-area.component.ts

@ -11,11 +11,11 @@ import { AppsState } from '@app/shared';
@Component({ @Component({
selector: 'sqx-api-area', selector: 'sqx-api-area',
styleUrls: ['./api-area.component.scss'], styleUrls: ['./api-area.component.scss'],
templateUrl: './api-area.component.html' templateUrl: './api-area.component.html',
}) })
export class ApiAreaComponent { export class ApiAreaComponent {
constructor( constructor(
public readonly appsState: AppsState public readonly appsState: AppsState,
) { ) {
} }
} }

2
frontend/app/features/api/index.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license

18
frontend/app/features/api/module.ts

@ -16,25 +16,25 @@ const routes: Routes = [
component: ApiAreaComponent, component: ApiAreaComponent,
children: [ children: [
{ {
path: '' path: '',
}, },
{ {
path: 'graphql', path: 'graphql',
component: GraphQLPageComponent component: GraphQLPageComponent,
} },
] ],
} },
]; ];
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild(routes), RouterModule.forChild(routes),
SqxFrameworkModule, SqxFrameworkModule,
SqxSharedModule SqxSharedModule,
], ],
declarations: [ declarations: [
ApiAreaComponent, ApiAreaComponent,
GraphQLPageComponent GraphQLPageComponent,
] ],
}) })
export class SqxFeatureApiModule {} export class SqxFeatureApiModule {}

10
frontend/app/features/api/pages/graphql/graphql-page.component.ts

@ -16,7 +16,7 @@ import { catchError } from 'rxjs/operators';
@Component({ @Component({
selector: 'sqx-graphql-page', selector: 'sqx-graphql-page',
styleUrls: ['./graphql-page.component.scss'], styleUrls: ['./graphql-page.component.scss'],
templateUrl: './graphql-page.component.html' templateUrl: './graphql-page.component.html',
}) })
export class GraphQLPageComponent implements AfterViewInit { export class GraphQLPageComponent implements AfterViewInit {
@ViewChild('graphiQLContainer', { static: false }) @ViewChild('graphiQLContainer', { static: false })
@ -24,7 +24,7 @@ export class GraphQLPageComponent implements AfterViewInit {
constructor( constructor(
private readonly appsState: AppsState, private readonly appsState: AppsState,
private readonly graphQlService: GraphQlService private readonly graphQlService: GraphQlService,
) { ) {
} }
@ -33,9 +33,9 @@ export class GraphQLPageComponent implements AfterViewInit {
React.createElement(GraphiQL, { React.createElement(GraphiQL, {
fetcher: (params: any) => { fetcher: (params: any) => {
return this.request(params); return this.request(params);
} },
}), }),
this.graphiQLContainer.nativeElement this.graphiQLContainer.nativeElement,
); );
} }
@ -44,4 +44,4 @@ export class GraphQLPageComponent implements AfterViewInit {
catchError(response => of(response.error))) catchError(response => of(response.error)))
.toPromise(); .toPromise();
} }
} }

2
frontend/app/features/apps/index.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license

12
frontend/app/features/apps/module.ts

@ -13,21 +13,21 @@ import { AppComponent, AppsPageComponent, NewsDialogComponent, OnboardingDialogC
const routes: Routes = [ const routes: Routes = [
{ {
path: '', path: '',
component: AppsPageComponent component: AppsPageComponent,
} },
]; ];
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild(routes), RouterModule.forChild(routes),
SqxFrameworkModule, SqxFrameworkModule,
SqxSharedModule SqxSharedModule,
], ],
declarations: [ declarations: [
AppComponent, AppComponent,
AppsPageComponent, AppsPageComponent,
NewsDialogComponent, NewsDialogComponent,
OnboardingDialogComponent OnboardingDialogComponent,
] ],
}) })
export class SqxFeatureAppsModule {} export class SqxFeatureAppsModule {}

6
frontend/app/features/apps/pages/app.component.ts

@ -13,9 +13,9 @@ import { AppDto, fadeAnimation, ModalModel } from '@app/shared';
styleUrls: ['./app.component.scss'], styleUrls: ['./app.component.scss'],
templateUrl: './app.component.html', templateUrl: './app.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AppComponent { export class AppComponent {
@Input() @Input()
@ -25,4 +25,4 @@ export class AppComponent {
public leave = new EventEmitter<AppDto>(); public leave = new EventEmitter<AppDto>();
public dropdown = new ModalModel(); public dropdown = new ModalModel();
} }

8
frontend/app/features/apps/pages/apps-page.component.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license
@ -13,7 +13,7 @@ import { take } from 'rxjs/operators';
@Component({ @Component({
selector: 'sqx-apps-page', selector: 'sqx-apps-page',
styleUrls: ['./apps-page.component.scss'], styleUrls: ['./apps-page.component.scss'],
templateUrl: './apps-page.component.html' templateUrl: './apps-page.component.html',
}) })
export class AppsPageComponent implements OnInit { export class AppsPageComponent implements OnInit {
public addAppDialog = new DialogModel(); public addAppDialog = new DialogModel();
@ -33,7 +33,7 @@ export class AppsPageComponent implements OnInit {
private readonly localStore: LocalStoreService, private readonly localStore: LocalStoreService,
private readonly newsService: NewsService, private readonly newsService: NewsService,
private readonly onboardingService: OnboardingService, private readonly onboardingService: OnboardingService,
private readonly uiOptions: UIOptions private readonly uiOptions: UIOptions,
) { ) {
if (uiOptions.get('showInfo')) { if (uiOptions.get('showInfo')) {
this.info = uiOptions.get('more.info'); this.info = uiOptions.get('more.info');
@ -78,4 +78,4 @@ export class AppsPageComponent implements OnInit {
public trackByApp(_index: number, app: AppDto) { public trackByApp(_index: number, app: AppDto) {
return app.id; return app.id;
} }
} }

4
frontend/app/features/apps/pages/news-dialog.component.ts

@ -11,7 +11,7 @@ import { FeatureDto } from '@app/shared';
@Component({ @Component({
selector: 'sqx-news-dialog', selector: 'sqx-news-dialog',
styleUrls: ['./news-dialog.component.scss'], styleUrls: ['./news-dialog.component.scss'],
templateUrl: './news-dialog.component.html' templateUrl: './news-dialog.component.html',
}) })
export class NewsDialogComponent { export class NewsDialogComponent {
@Output() @Output()
@ -23,4 +23,4 @@ export class NewsDialogComponent {
public trackByFeature(_index: number, feature: FeatureDto) { public trackByFeature(_index: number, feature: FeatureDto) {
return feature; return feature;
} }
} }

6
frontend/app/features/apps/pages/onboarding-dialog.component.ts

@ -13,8 +13,8 @@ import { fadeAnimation, slideAnimation } from '@app/framework';
styleUrls: ['./onboarding-dialog.component.scss'], styleUrls: ['./onboarding-dialog.component.scss'],
templateUrl: './onboarding-dialog.component.html', templateUrl: './onboarding-dialog.component.html',
animations: [ animations: [
fadeAnimation, slideAnimation fadeAnimation, slideAnimation,
] ],
}) })
export class OnboardingDialogComponent { export class OnboardingDialogComponent {
public step = 0; public step = 0;
@ -25,4 +25,4 @@ export class OnboardingDialogComponent {
public next() { public next() {
this.step += 1; this.step += 1;
} }
} }

2
frontend/app/features/assets/index.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license

16
frontend/app/features/assets/module.ts

@ -17,22 +17,22 @@ const routes: Routes = [
children: [ children: [
{ {
path: 'filters', path: 'filters',
component: AssetsFiltersPageComponent component: AssetsFiltersPageComponent,
} },
] ],
} },
]; ];
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild(routes), RouterModule.forChild(routes),
SqxFrameworkModule, SqxFrameworkModule,
SqxSharedModule SqxSharedModule,
], ],
declarations: [ declarations: [
AssetsFiltersPageComponent, AssetsFiltersPageComponent,
AssetsPageComponent, AssetsPageComponent,
AssetTagsComponent AssetTagsComponent,
] ],
}) })
export class SqxFeatureAssetsModule {} export class SqxFeatureAssetsModule {}

6
frontend/app/features/assets/pages/asset-tags.component.ts

@ -5,6 +5,8 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { TagItem, TagsSelected } from '@app/shared'; import { TagItem, TagsSelected } from '@app/shared';
@ -12,7 +14,7 @@ import { TagItem, TagsSelected } from '@app/shared';
selector: 'sqx-asset-tags', selector: 'sqx-asset-tags',
styleUrls: ['./asset-tags.component.scss'], styleUrls: ['./asset-tags.component.scss'],
templateUrl: './asset-tags.component.html', templateUrl: './asset-tags.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AssetTagsComponent { export class AssetTagsComponent {
@Output() @Output()
@ -38,4 +40,4 @@ export class AssetTagsComponent {
public trackByTag(_index: number, tag: TagItem) { public trackByTag(_index: number, tag: TagItem) {
return tag.name; return tag.name;
} }
} }

6
frontend/app/features/assets/pages/assets-filters-page.component.ts

@ -11,13 +11,13 @@ import { AssetsState, Queries, Query, UIState } from '@app/shared';
@Component({ @Component({
selector: 'sqx-assets-filters-page', selector: 'sqx-assets-filters-page',
styleUrls: ['./assets-filters-page.component.scss'], styleUrls: ['./assets-filters-page.component.scss'],
templateUrl: './assets-filters-page.component.html' templateUrl: './assets-filters-page.component.html',
}) })
export class AssetsFiltersPageComponent { export class AssetsFiltersPageComponent {
public assetsQueries: Queries; public assetsQueries: Queries;
constructor(uiState: UIState, constructor(uiState: UIState,
public readonly assetsState: AssetsState public readonly assetsState: AssetsState,
) { ) {
this.assetsQueries = new Queries(uiState, 'assets'); this.assetsQueries = new Queries(uiState, 'assets');
} }
@ -41,4 +41,4 @@ export class AssetsFiltersPageComponent {
public trackByTag(_index: number, tag: { name: string }) { public trackByTag(_index: number, tag: { name: string }) {
return tag.name; return tag.name;
} }
} }

8
frontend/app/features/assets/pages/assets-page.component.ts

@ -14,8 +14,8 @@ import { Settings } from '@app/shared/state/settings';
styleUrls: ['./assets-page.component.scss'], styleUrls: ['./assets-page.component.scss'],
templateUrl: './assets-page.component.html', templateUrl: './assets-page.component.html',
providers: [ providers: [
Router2State Router2State,
] ],
}) })
export class AssetsPageComponent extends ResourceOwner implements OnInit { export class AssetsPageComponent extends ResourceOwner implements OnInit {
public queries = new Queries(this.uiState, 'assets'); public queries = new Queries(this.uiState, 'assets');
@ -28,7 +28,7 @@ export class AssetsPageComponent extends ResourceOwner implements OnInit {
public readonly assetsRoute: Router2State, public readonly assetsRoute: Router2State,
public readonly assetsState: AssetsState, public readonly assetsState: AssetsState,
private readonly localStore: LocalStoreService, private readonly localStore: LocalStoreService,
private readonly uiState: UIState private readonly uiState: UIState,
) { ) {
super(); super();
@ -69,4 +69,4 @@ export class AssetsPageComponent extends ResourceOwner implements OnInit {
this.localStore.setBoolean(Settings.Local.ASSETS_MODE, isListView); this.localStore.setBoolean(Settings.Local.ASSETS_MODE, isListView);
} }
} }

2
frontend/app/features/content/index.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license

50
frontend/app/features/content/module.ts

@ -5,8 +5,6 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: max-line-length
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { CanDeactivateGuard, ContentMustExistGuard, LoadLanguagesGuard, LoadSchemasGuard, SchemaMustExistPublishedGuard, SchemaMustNotBeSingletonGuard, SqxFrameworkModule, SqxSharedModule } from '@app/shared'; import { CanDeactivateGuard, ContentMustExistGuard, LoadLanguagesGuard, LoadSchemasGuard, SchemaMustExistPublishedGuard, SchemaMustNotBeSingletonGuard, SqxFrameworkModule, SqxSharedModule } from '@app/shared';
@ -19,7 +17,7 @@ const routes: Routes = [
canActivate: [LoadLanguagesGuard, LoadSchemasGuard], canActivate: [LoadLanguagesGuard, LoadSchemasGuard],
children: [ children: [
{ {
path: '' path: '',
}, },
{ {
path: ':schemaName', path: ':schemaName',
@ -33,19 +31,19 @@ const routes: Routes = [
children: [ children: [
{ {
path: 'filters', path: 'filters',
component: ContentsFiltersPageComponent component: ContentsFiltersPageComponent,
}, },
{ {
path: 'sidebar', path: 'sidebar',
component: SidebarPageComponent component: SidebarPageComponent,
} },
] ],
}, },
{ {
path: 'new', path: 'new',
component: ContentPageComponent, component: ContentPageComponent,
canActivate: [SchemaMustNotBeSingletonGuard, ContentMustExistGuard], canActivate: [SchemaMustNotBeSingletonGuard, ContentMustExistGuard],
canDeactivate: [CanDeactivateGuard] canDeactivate: [CanDeactivateGuard],
}, },
{ {
path: ':contentId', path: ':contentId',
@ -53,33 +51,33 @@ const routes: Routes = [
canActivate: [ContentMustExistGuard], canActivate: [ContentMustExistGuard],
canDeactivate: [CanDeactivateGuard], canDeactivate: [CanDeactivateGuard],
children: [ children: [
{ {
path: 'history', path: 'history',
component: ContentHistoryPageComponent, component: ContentHistoryPageComponent,
data: { data: {
channel: 'contents.{contentId}' channel: 'contents.{contentId}',
} },
}, },
{ {
path: 'comments', path: 'comments',
component: CommentsPageComponent component: CommentsPageComponent,
}, },
{ {
path: 'sidebar', path: 'sidebar',
component: SidebarPageComponent component: SidebarPageComponent,
} },
] ],
} },
] ],
}] }],
} },
]; ];
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild(routes), RouterModule.forChild(routes),
SqxFrameworkModule, SqxFrameworkModule,
SqxSharedModule SqxSharedModule,
], ],
declarations: [ declarations: [
ArrayEditorComponent, ArrayEditorComponent,
@ -120,7 +118,7 @@ const routes: Routes = [
ReferencesEditorComponent, ReferencesEditorComponent,
SchemasPageComponent, SchemasPageComponent,
SidebarPageComponent, SidebarPageComponent,
StockPhotoEditorComponent StockPhotoEditorComponent,
] ],
}) })
export class SqxFeatureContentModule {} export class SqxFeatureContentModule {}

6
frontend/app/features/content/pages/comments/comments-page.component.ts

@ -12,13 +12,13 @@ import { map } from 'rxjs/operators';
@Component({ @Component({
selector: 'sqx-comments-page', selector: 'sqx-comments-page',
styleUrls: ['./comments-page.component.scss'], styleUrls: ['./comments-page.component.scss'],
templateUrl: './comments-page.component.html' templateUrl: './comments-page.component.html',
}) })
export class CommentsPageComponent { export class CommentsPageComponent {
public commentsId = this.route.parent!.params.pipe(map(x => x['contentId'])); public commentsId = this.route.parent!.params.pipe(map(x => x['contentId']));
constructor( constructor(
private readonly route: ActivatedRoute private readonly route: ActivatedRoute,
) { ) {
} }
} }

4
frontend/app/features/content/pages/content/content-event.component.ts

@ -12,7 +12,7 @@ import { ContentDto, HistoryEventDto } from '@app/shared';
selector: 'sqx-content-event', selector: 'sqx-content-event',
styleUrls: ['./content-event.component.scss'], styleUrls: ['./content-event.component.scss'],
templateUrl: './content-event.component.html', templateUrl: './content-event.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentEventComponent implements OnChanges { export class ContentEventComponent implements OnChanges {
@Output() @Output()
@ -35,4 +35,4 @@ export class ContentEventComponent implements OnChanges {
this.event.eventType === 'ContentCreatedEventV2') && this.event.eventType === 'ContentCreatedEventV2') &&
!this.event.version.eq(this.content.version); !this.event.version.eq(this.content.version);
} }
} }

10
frontend/app/features/content/pages/content/content-history-page.component.ts

@ -5,8 +5,6 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: triple-equals
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { AppsState, ContentDto, ContentsState, defined, fadeAnimation, HistoryEventDto, HistoryService, ModalModel, ResourceOwner, SchemasState, switchSafe } from '@app/shared'; import { AppsState, ContentDto, ContentsState, defined, fadeAnimation, HistoryEventDto, HistoryService, ModalModel, ResourceOwner, SchemasState, switchSafe } from '@app/shared';
import { Observable, timer } from 'rxjs'; import { Observable, timer } from 'rxjs';
@ -19,8 +17,8 @@ import { ContentPageComponent } from './content-page.component';
styleUrls: ['./content-history-page.component.scss'], styleUrls: ['./content-history-page.component.scss'],
templateUrl: './content-history-page.component.html', templateUrl: './content-history-page.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
] ],
}) })
export class ContentHistoryPageComponent extends ResourceOwner implements OnInit { export class ContentHistoryPageComponent extends ResourceOwner implements OnInit {
@ViewChild('dueTimeSelector', { static: false }) @ViewChild('dueTimeSelector', { static: false })
@ -41,7 +39,7 @@ export class ContentHistoryPageComponent extends ResourceOwner implements OnInit
private readonly contentPage: ContentPageComponent, private readonly contentPage: ContentPageComponent,
private readonly contentsState: ContentsState, private readonly contentsState: ContentsState,
private readonly historyService: HistoryService, private readonly historyService: HistoryService,
private readonly schemasState: SchemasState private readonly schemasState: SchemasState,
) { ) {
super(); super();
} }
@ -95,4 +93,4 @@ export class ContentHistoryPageComponent extends ResourceOwner implements OnInit
public trackByEvent(_index: number, event: HistoryEventDto) { public trackByEvent(_index: number, event: HistoryEventDto) {
return event.eventId; return event.eventId;
} }
} }

18
frontend/app/features/content/pages/content/content-page.component.ts

@ -5,8 +5,6 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: max-line-length
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { ApiUrlConfig, AppLanguageDto, AppsState, AuthService, AutoSaveKey, AutoSaveService, CanComponentDeactivate, ContentDto, ContentsState, defined, DialogService, EditContentForm, fadeAnimation, LanguagesState, ModalModel, ResourceOwner, SchemaDto, SchemasState, TempService, Version } from '@app/shared'; import { ApiUrlConfig, AppLanguageDto, AppsState, AuthService, AutoSaveKey, AutoSaveService, CanComponentDeactivate, ContentDto, ContentsState, defined, DialogService, EditContentForm, fadeAnimation, LanguagesState, ModalModel, ResourceOwner, SchemaDto, SchemasState, TempService, Version } from '@app/shared';
@ -19,8 +17,8 @@ import { ContentReferencesComponent } from './references/content-references.comp
styleUrls: ['./content-page.component.scss'], styleUrls: ['./content-page.component.scss'],
templateUrl: './content-page.component.html', templateUrl: './content-page.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
] ],
}) })
export class ContentPageComponent extends ResourceOwner implements CanComponentDeactivate, OnInit { export class ContentPageComponent extends ResourceOwner implements CanComponentDeactivate, OnInit {
private isLoadingContent: boolean; private isLoadingContent: boolean;
@ -46,7 +44,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
public confirmPreview = () => { public confirmPreview = () => {
return this.checkPendingChangesBeforePreview(); return this.checkPendingChangesBeforePreview();
} };
constructor(apiUrl: ApiUrlConfig, authService: AuthService, appsState: AppsState, constructor(apiUrl: ApiUrlConfig, authService: AuthService, appsState: AppsState,
public readonly contentsState: ContentsState, public readonly contentsState: ContentsState,
@ -56,7 +54,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
private readonly route: ActivatedRoute, private readonly route: ActivatedRoute,
private readonly router: Router, private readonly router: Router,
private readonly schemasState: SchemasState, private readonly schemasState: SchemasState,
private readonly tempService: TempService private readonly tempService: TempService,
) { ) {
super(); super();
@ -64,7 +62,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
apiUrl: apiUrl.buildUrl('api'), apiUrl: apiUrl.buildUrl('api'),
appId: contentsState.appId, appId: contentsState.appId,
appName: appsState.appName, appName: appsState.appName,
user: authService.user user: authService.user,
}; };
} }
@ -104,7 +102,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
this.autoSaveKey = { this.autoSaveKey = {
schemaId: this.schema.id, schemaId: this.schema.id,
schemaVersion: this.schema.version, schemaVersion: this.schema.version,
contentId: content?.id contentId: content?.id,
}; };
const dataAutosaved = this.autoSaveService.fetch(this.autoSaveKey); const dataAutosaved = this.autoSaveService.fetch(this.autoSaveKey);
@ -139,7 +137,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
if (confirmed) { if (confirmed) {
this.autoSaveService.remove(this.autoSaveKey); this.autoSaveService.remove(this.autoSaveKey);
} }
}) }),
); );
} }
@ -284,4 +282,4 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
function isOtherContent(lhs: ContentDto | undefined | null, rhs: ContentDto | undefined | null) { function isOtherContent(lhs: ContentDto | undefined | null, rhs: ContentDto | undefined | null) {
return !lhs || !rhs || lhs.id !== rhs.id; return !lhs || !rhs || lhs.id !== rhs.id;
} }

4
frontend/app/features/content/pages/content/editor/content-editor.component.ts

@ -11,7 +11,7 @@ import { AppLanguageDto, EditContentForm, FieldForm, FieldSection, RootFieldDto,
@Component({ @Component({
selector: 'sqx-content-editor', selector: 'sqx-content-editor',
styleUrls: ['./content-editor.component.scss'], styleUrls: ['./content-editor.component.scss'],
templateUrl: './content-editor.component.html' templateUrl: './content-editor.component.html',
}) })
export class ContentEditorComponent { export class ContentEditorComponent {
@Output() @Output()
@ -44,4 +44,4 @@ export class ContentEditorComponent {
public trackBySection(_index: number, section: FieldSection<RootFieldDto, FieldForm>) { public trackBySection(_index: number, section: FieldSection<RootFieldDto, FieldForm>) {
return section.separator?.fieldId; return section.separator?.fieldId;
} }
} }

8
frontend/app/features/content/pages/content/editor/content-field.component.ts

@ -13,7 +13,7 @@ import { map } from 'rxjs/operators';
@Component({ @Component({
selector: 'sqx-content-field', selector: 'sqx-content-field',
styleUrls: ['./content-field.component.scss'], styleUrls: ['./content-field.component.scss'],
templateUrl: './content-field.component.html' templateUrl: './content-field.component.html',
}) })
export class ContentFieldComponent implements OnChanges { export class ContentFieldComponent implements OnChanges {
@Output() @Output()
@ -67,7 +67,7 @@ export class ContentFieldComponent implements OnChanges {
constructor( constructor(
private readonly appsState: AppsState, private readonly appsState: AppsState,
private readonly localStore: LocalStoreService, private readonly localStore: LocalStoreService,
private readonly translations: TranslationsService private readonly translations: TranslationsService,
) { ) {
} }
@ -82,7 +82,7 @@ export class ContentFieldComponent implements OnChanges {
this.isDifferent = this.isDifferent =
combineLatest([ combineLatest([
value$(this.formModel.form), value$(this.formModel.form),
value$(this.formModelCompare!.form) value$(this.formModelCompare!.form),
]).pipe(map(([lhs, rhs]) => !Types.equals(lhs, rhs, true))); ]).pipe(map(([lhs, rhs]) => !Types.equals(lhs, rhs, true)));
} }
} }
@ -162,4 +162,4 @@ export class ContentFieldComponent implements OnChanges {
private configKey() { private configKey() {
return Settings.Local.FIELD_ALL(this.schema?.id, this.formModel.field.fieldId); return Settings.Local.FIELD_ALL(this.schema?.id, this.formModel.field.fieldId);
} }
} }

10
frontend/app/features/content/pages/content/editor/content-section.component.ts

@ -17,7 +17,7 @@ interface State {
selector: 'sqx-content-section', selector: 'sqx-content-section',
styleUrls: ['./content-section.component.scss'], styleUrls: ['./content-section.component.scss'],
templateUrl: './content-section.component.html', templateUrl: './content-section.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentSectionComponent extends StatefulComponent<State> implements OnChanges { export class ContentSectionComponent extends StatefulComponent<State> implements OnChanges {
@Output() @Output()
@ -48,10 +48,10 @@ export class ContentSectionComponent extends StatefulComponent<State> implements
public languages: ReadonlyArray<AppLanguageDto>; public languages: ReadonlyArray<AppLanguageDto>;
constructor(changeDetector: ChangeDetectorRef, constructor(changeDetector: ChangeDetectorRef,
private readonly localStore: LocalStoreService private readonly localStore: LocalStoreService,
) { ) {
super(changeDetector, { super(changeDetector, {
isCollapsed: false isCollapsed: false,
}); });
this.changes.subscribe(state => { this.changes.subscribe(state => {
@ -68,7 +68,7 @@ export class ContentSectionComponent extends StatefulComponent<State> implements
public toggle() { public toggle() {
this.next(s => ({ this.next(s => ({
...s, ...s,
isCollapsed: !s.isCollapsed isCollapsed: !s.isCollapsed,
})); }));
} }
@ -83,4 +83,4 @@ export class ContentSectionComponent extends StatefulComponent<State> implements
private configKey(): string { private configKey(): string {
return Settings.Local.FIELD_COLLAPSED(this.schema?.id, this.formSection?.separator?.fieldId); return Settings.Local.FIELD_COLLAPSED(this.schema?.id, this.formSection?.separator?.fieldId);
} }
} }

4
frontend/app/features/content/pages/content/editor/field-languages.component.ts

@ -12,7 +12,7 @@ import { AppLanguageDto, RootFieldDto } from '@app/shared';
selector: 'sqx-field-languages', selector: 'sqx-field-languages',
styleUrls: ['./field-languages.component.scss'], styleUrls: ['./field-languages.component.scss'],
templateUrl: './field-languages.component.html', templateUrl: './field-languages.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class FieldLanguagesComponent { export class FieldLanguagesComponent {
@Output() @Output()
@ -36,4 +36,4 @@ export class FieldLanguagesComponent {
public toggleShowAllControls() { public toggleShowAllControls() {
this.showAllControlsChange.emit(!this.showAllControls); this.showAllControlsChange.emit(!this.showAllControls);
} }
} }

8
frontend/app/features/content/pages/content/references/content-references.component.ts

@ -14,8 +14,8 @@ import { AppLanguageDto, ComponentContentsState, ContentDto, QuerySynchronizer,
templateUrl: './content-references.component.html', templateUrl: './content-references.component.html',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ providers: [
Router2State, ComponentContentsState Router2State, ComponentContentsState,
] ],
}) })
export class ContentReferencesComponent implements OnChanges { export class ContentReferencesComponent implements OnChanges {
@Input() @Input()
@ -29,7 +29,7 @@ export class ContentReferencesComponent implements OnChanges {
constructor( constructor(
public readonly contentsRoute: Router2State, public readonly contentsRoute: Router2State,
public readonly contentsState: ComponentContentsState public readonly contentsState: ComponentContentsState,
) { ) {
} }
@ -64,4 +64,4 @@ export class ContentReferencesComponent implements OnChanges {
public trackByContent(_index: number, content: ContentDto) { public trackByContent(_index: number, content: ContentDto) {
return content.id; return content.id;
} }
} }

8
frontend/app/features/content/pages/contents/contents-filters-page.component.ts

@ -12,23 +12,23 @@ import { map } from 'rxjs/operators';
@Component({ @Component({
selector: 'sqx-contents-filters-page', selector: 'sqx-contents-filters-page',
styleUrls: ['./contents-filters-page.component.scss'], styleUrls: ['./contents-filters-page.component.scss'],
templateUrl: './contents-filters-page.component.html' templateUrl: './contents-filters-page.component.html',
}) })
export class ContentsFiltersPageComponent { export class ContentsFiltersPageComponent {
public schemaQueries = public schemaQueries =
this.schemasState.selectedSchema.pipe( this.schemasState.selectedSchema.pipe(
defined(), defined(),
map(schema => new Queries(this.uiState, `schemas.${schema.name}`) map(schema => new Queries(this.uiState, `schemas.${schema.name}`),
)); ));
constructor( constructor(
public readonly contentsState: ContentsState, public readonly contentsState: ContentsState,
private readonly schemasState: SchemasState, private readonly schemasState: SchemasState,
private readonly uiState: UIState private readonly uiState: UIState,
) { ) {
} }
public search(query: Query) { public search(query: Query) {
this.contentsState.search(query); this.contentsState.search(query);
} }
} }

16
frontend/app/features/content/pages/contents/contents-page.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: max-line-length /* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
@ -19,11 +19,11 @@ import { DueTimeSelectorComponent } from './../../shared/due-time-selector.compo
styleUrls: ['./contents-page.component.scss'], styleUrls: ['./contents-page.component.scss'],
templateUrl: './contents-page.component.html', templateUrl: './contents-page.component.html',
providers: [ providers: [
Router2State Router2State,
], ],
animations: [ animations: [
fadeAnimation fadeAnimation,
] ],
}) })
export class ContentsPageComponent extends ResourceOwner implements OnInit { export class ContentsPageComponent extends ResourceOwner implements OnInit {
@ViewChild('dueTimeSelector', { static: false }) @ViewChild('dueTimeSelector', { static: false })
@ -36,7 +36,7 @@ export class ContentsPageComponent extends ResourceOwner implements OnInit {
public searchModal = new ModalModel(); public searchModal = new ModalModel();
public selectedItems: { [id: string]: boolean; } = {}; public selectedItems: { [id: string]: boolean } = {};
public selectedAll = false; public selectedAll = false;
public selectionCount = 0; public selectionCount = 0;
public selectionCanDelete = false; public selectionCanDelete = false;
@ -53,7 +53,7 @@ export class ContentsPageComponent extends ResourceOwner implements OnInit {
combineLatest([ combineLatest([
this.schemasState.selectedSchema.pipe(defined()), this.schemasState.selectedSchema.pipe(defined()),
this.languagesState.isoLanguages, this.languagesState.isoLanguages,
this.contentsState.statuses this.contentsState.statuses,
]).pipe( ]).pipe(
map(values => queryModelFromSchema(values[0], values[1], values[2]))); map(values => queryModelFromSchema(values[0], values[1], values[2])));
@ -71,7 +71,7 @@ export class ContentsPageComponent extends ResourceOwner implements OnInit {
private readonly router: Router, private readonly router: Router,
private readonly schemasState: SchemasState, private readonly schemasState: SchemasState,
private readonly tempService: TempService, private readonly tempService: TempService,
private readonly uiState: UIState private readonly uiState: UIState,
) { ) {
super(); super();
} }
@ -234,4 +234,4 @@ export class ContentsPageComponent extends ResourceOwner implements OnInit {
function getSchemaName(route: ActivatedRoute) { function getSchemaName(route: ActivatedRoute) {
return route.params.pipe(map(x => x['schemaName'] as string), distinctUntilChanged()); return route.params.pipe(map(x => x['schemaName'] as string), distinctUntilChanged());
} }

6
frontend/app/features/content/pages/contents/custom-view-editor.component.ts

@ -5,8 +5,6 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: readonly-array
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
@ -14,7 +12,7 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Out
selector: 'sqx-custom-view-editor', selector: 'sqx-custom-view-editor',
styleUrls: ['./custom-view-editor.component.scss'], styleUrls: ['./custom-view-editor.component.scss'],
templateUrl: './custom-view-editor.component.html', templateUrl: './custom-view-editor.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class CustomViewEditorComponent implements OnChanges { export class CustomViewEditorComponent implements OnChanges {
@Output() @Output()
@ -53,4 +51,4 @@ export class CustomViewEditorComponent implements OnChanges {
private updateFieldNames(fieldNames: ReadonlyArray<string>) { private updateFieldNames(fieldNames: ReadonlyArray<string>) {
this.fieldNamesChange.emit(fieldNames); this.fieldNamesChange.emit(fieldNames);
} }
} }

6
frontend/app/features/content/pages/schemas/schemas-page.component.ts

@ -12,7 +12,7 @@ import { LocalStoreService, SchemaCategory, SchemasState, Settings } from '@app/
@Component({ @Component({
selector: 'sqx-schemas-page', selector: 'sqx-schemas-page',
styleUrls: ['./schemas-page.component.scss'], styleUrls: ['./schemas-page.component.scss'],
templateUrl: './schemas-page.component.html' templateUrl: './schemas-page.component.html',
}) })
export class SchemasPageComponent { export class SchemasPageComponent {
public schemasFilter = new FormControl(); public schemasFilter = new FormControl();
@ -25,7 +25,7 @@ export class SchemasPageComponent {
constructor( constructor(
public readonly schemasState: SchemasState, public readonly schemasState: SchemasState,
private readonly localStore: LocalStoreService private readonly localStore: LocalStoreService,
) { ) {
this.isCollapsed = localStore.getBoolean(Settings.Local.SCHEMAS_COLLAPSED); this.isCollapsed = localStore.getBoolean(Settings.Local.SCHEMAS_COLLAPSED);
} }
@ -39,4 +39,4 @@ export class SchemasPageComponent {
public trackByCategory(_index: number, category: SchemaCategory) { public trackByCategory(_index: number, category: SchemaCategory) {
return category.name; return category.name;
} }
} }

8
frontend/app/features/content/pages/sidebar/sidebar-page.component.ts

@ -15,12 +15,12 @@ import { map } from 'rxjs/operators';
selector: 'sqx-sidebar-page', selector: 'sqx-sidebar-page',
styleUrls: ['./sidebar-page.component.scss'], styleUrls: ['./sidebar-page.component.scss'],
templateUrl: './sidebar-page.component.html', templateUrl: './sidebar-page.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class SidebarPageComponent { export class SidebarPageComponent {
public url = combineLatest([ public url = combineLatest([
this.schemasState.selectedSchema.pipe(defined()), this.schemasState.selectedSchema.pipe(defined()),
this.contentsState.selectedContent this.contentsState.selectedContent,
]).pipe(map(([schema, content]) => { ]).pipe(map(([schema, content]) => {
const url = const url =
content ? content ?
@ -32,7 +32,7 @@ export class SidebarPageComponent {
constructor( constructor(
public readonly contentsState: ContentsState, public readonly contentsState: ContentsState,
public readonly schemasState: SchemasState public readonly schemasState: SchemasState,
) { ) {
} }
} }

8
frontend/app/features/content/shared/content-extension.component.ts

@ -14,7 +14,7 @@ import { AppsState, AuthService, computeEditorUrl, ContentDto, SchemaDto } from
selector: 'sqx-content-extension', selector: 'sqx-content-extension',
styleUrls: ['./content-extension.component.scss'], styleUrls: ['./content-extension.component.scss'],
templateUrl: './content-extension.component.html', templateUrl: './content-extension.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentExtensionComponent extends ResourceOwner implements AfterViewInit, OnChanges { export class ContentExtensionComponent extends ResourceOwner implements AfterViewInit, OnChanges {
private readonly context: any; private readonly context: any;
@ -36,7 +36,7 @@ export class ContentExtensionComponent extends ResourceOwner implements AfterVie
constructor(apiUrl: ApiUrlConfig, authService: AuthService, constructor(apiUrl: ApiUrlConfig, authService: AuthService,
private readonly appsState: AppsState, private readonly appsState: AppsState,
private readonly renderer: Renderer2, private readonly renderer: Renderer2,
private readonly router: Router private readonly router: Router,
) { ) {
super(); super();
@ -44,7 +44,7 @@ export class ContentExtensionComponent extends ResourceOwner implements AfterVie
apiUrl: apiUrl.buildUrl('api'), apiUrl: apiUrl.buildUrl('api'),
appId: appsState.snapshot.selectedApp!.id, appId: appsState.snapshot.selectedApp!.id,
appName: appsState.snapshot.selectedApp!.name, appName: appsState.snapshot.selectedApp!.name,
user: authService.user user: authService.user,
}; };
} }
@ -118,4 +118,4 @@ export class ContentExtensionComponent extends ResourceOwner implements AfterVie
iframe.contentWindow.postMessage(message, '*'); iframe.contentWindow.postMessage(message, '*');
} }
} }
} }

4
frontend/app/features/content/shared/content-status.component.ts

@ -12,7 +12,7 @@ import { ScheduleDto } from '@app/shared';
selector: 'sqx-content-status', selector: 'sqx-content-status',
styleUrls: ['./content-status.component.scss'], styleUrls: ['./content-status.component.scss'],
templateUrl: './content-status.component.html', templateUrl: './content-status.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentStatusComponent { export class ContentStatusComponent {
@Input() @Input()
@ -48,4 +48,4 @@ export class ContentStatusComponent {
return this.status; return this.status;
} }
} }
} }

4
frontend/app/features/content/shared/due-time-selector.component.ts

@ -14,7 +14,7 @@ const OPTION_IMMEDIATELY = 'Immediately';
@Component({ @Component({
selector: 'sqx-due-time-selector', selector: 'sqx-due-time-selector',
styleUrls: ['./due-time-selector.component.scss'], styleUrls: ['./due-time-selector.component.scss'],
templateUrl: './due-time-selector.component.html' templateUrl: './due-time-selector.component.html',
}) })
export class DueTimeSelectorComponent { export class DueTimeSelectorComponent {
private dueTimeResult: Subject<string | null>; private dueTimeResult: Subject<string | null>;
@ -54,4 +54,4 @@ export class DueTimeSelectorComponent {
this.dueTimeResult = null!; this.dueTimeResult = null!;
this.dueTime = null; this.dueTime = null;
} }
} }

8
frontend/app/features/content/shared/forms/array-editor.component.ts

@ -18,8 +18,8 @@ import { ArrayItemComponent } from './array-item.component';
templateUrl: './array-editor.component.html', templateUrl: './array-editor.component.html',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
animations: [ animations: [
fadeAnimation fadeAnimation,
] ],
}) })
export class ArrayEditorComponent implements OnChanges { export class ArrayEditorComponent implements OnChanges {
@Input() @Input()
@ -70,7 +70,7 @@ export class ArrayEditorComponent implements OnChanges {
this.isFull = combineLatest([ this.isFull = combineLatest([
this.isDisabled, this.isDisabled,
this.formModel.itemChanges this.formModel.itemChanges,
]).pipe(map(([disabled, items]) => { ]).pipe(map(([disabled, items]) => {
return disabled || items.length >= maxItems; return disabled || items.length >= maxItems;
})); }));
@ -126,4 +126,4 @@ export class ArrayEditorComponent implements OnChanges {
child.reset(); child.reset();
}); });
} }
} }

8
frontend/app/features/content/shared/forms/array-item.component.ts

@ -20,7 +20,7 @@ interface State {
selector: 'sqx-array-item', selector: 'sqx-array-item',
styleUrls: ['./array-item.component.scss'], styleUrls: ['./array-item.component.scss'],
templateUrl: './array-item.component.html', templateUrl: './array-item.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ArrayItemComponent extends StatefulComponent<State> implements OnChanges { export class ArrayItemComponent extends StatefulComponent<State> implements OnChanges {
@Output() @Output()
@ -70,10 +70,10 @@ export class ArrayItemComponent extends StatefulComponent<State> implements OnCh
public title: Observable<string>; public title: Observable<string>;
constructor(changeDetector: ChangeDetectorRef constructor(changeDetector: ChangeDetectorRef,
) { ) {
super(changeDetector, { super(changeDetector, {
isCollapsed: false isCollapsed: false,
}); });
} }
@ -142,4 +142,4 @@ export class ArrayItemComponent extends StatefulComponent<State> implements OnCh
public trackBySection(_index: number, section: FieldSection<FieldDto, any>) { public trackBySection(_index: number, section: FieldSection<FieldDto, any>) {
return section.separator?.fieldId; return section.separator?.fieldId;
} }
} }

20
frontend/app/features/content/shared/forms/assets-editor.component.ts

@ -11,13 +11,13 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { AppsState, AssetDto, AssetsService, DialogModel, LocalStoreService, MessageBus, Settings, sorted, StatefulControlComponent, Types } from '@app/shared'; import { AppsState, AssetDto, AssetsService, DialogModel, LocalStoreService, MessageBus, Settings, sorted, StatefulControlComponent, Types } from '@app/shared';
export const SQX_ASSETS_EDITOR_CONTROL_VALUE_ACCESSOR: any = { export const SQX_ASSETS_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AssetsEditorComponent), multi: true provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AssetsEditorComponent), multi: true,
}; };
class AssetUpdated { class AssetUpdated {
constructor( constructor(
public readonly asset: AssetDto, public readonly asset: AssetDto,
public readonly source: any public readonly source: any,
) { ) {
} }
} }
@ -41,9 +41,9 @@ interface State {
styleUrls: ['./assets-editor.component.scss'], styleUrls: ['./assets-editor.component.scss'],
templateUrl: './assets-editor.component.html', templateUrl: './assets-editor.component.html',
providers: [ providers: [
SQX_ASSETS_EDITOR_CONTROL_VALUE_ACCESSOR SQX_ASSETS_EDITOR_CONTROL_VALUE_ACCESSOR,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AssetsEditorComponent extends StatefulControlComponent<State, ReadonlyArray<string>> implements OnInit { export class AssetsEditorComponent extends StatefulControlComponent<State, ReadonlyArray<string>> implements OnInit {
@Input() @Input()
@ -60,12 +60,12 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, Reado
private readonly appsState: AppsState, private readonly appsState: AppsState,
private readonly assetsService: AssetsService, private readonly assetsService: AssetsService,
private readonly localStore: LocalStoreService, private readonly localStore: LocalStoreService,
private readonly messageBus: MessageBus private readonly messageBus: MessageBus,
) { ) {
super(changeDetector, { super(changeDetector, {
assets: [], assets: [],
assetFiles: [], assetFiles: [],
isListView: localStore.getBoolean(Settings.Local.ASSETS_MODE) isListView: localStore.getBoolean(Settings.Local.ASSETS_MODE),
}); });
} }
@ -116,7 +116,7 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, Reado
for (const file of files) { for (const file of files) {
this.next(s => ({ this.next(s => ({
...s, ...s,
assetFiles: [file, ...s.assetFiles] assetFiles: [file, ...s.assetFiles],
})); }));
} }
} }
@ -136,7 +136,7 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, Reado
this.next(s => ({ this.next(s => ({
...s, ...s,
assetFiles: s.assetFiles.removed(file), assetFiles: s.assetFiles.removed(file),
assets: [asset, ...s.assets] assets: [asset, ...s.assets],
})); }));
this.updateValue(); this.updateValue();
@ -162,7 +162,7 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, Reado
public removeLoadingAsset(file: File) { public removeLoadingAsset(file: File) {
this.next(s => ({ this.next(s => ({
...s, ...s,
assetFiles: s.assetFiles.removed(file) assetFiles: s.assetFiles.removed(file),
})); }));
} }
@ -187,4 +187,4 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, Reado
public trackByAsset(_index: number, asset: AssetDto) { public trackByAsset(_index: number, asset: AssetDto) {
return asset.id; return asset.id;
} }
} }

4
frontend/app/features/content/shared/forms/component-section.component.ts

@ -13,7 +13,7 @@ import { FieldEditorComponent } from './field-editor.component';
selector: 'sqx-component-section', selector: 'sqx-component-section',
styleUrls: ['./component-section.component.scss'], styleUrls: ['./component-section.component.scss'],
templateUrl: './component-section.component.html', templateUrl: './component-section.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ComponentSectionComponent { export class ComponentSectionComponent {
@Input() @Input()
@ -49,4 +49,4 @@ export class ComponentSectionComponent {
public trackByField(_index: number, field: AbstractContentForm<any, any>) { public trackByField(_index: number, field: AbstractContentForm<any, any>) {
return field.field.fieldId; return field.field.fieldId;
} }
} }

8
frontend/app/features/content/shared/forms/component.component.ts

@ -15,8 +15,8 @@ import { ComponentSectionComponent } from './component-section.component';
templateUrl: './component.component.html', templateUrl: './component.component.html',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
animations: [ animations: [
fadeAnimation fadeAnimation,
] ],
}) })
export class ComponentComponent extends ResourceOwner implements OnChanges { export class ComponentComponent extends ResourceOwner implements OnChanges {
@Input() @Input()
@ -44,7 +44,7 @@ export class ComponentComponent extends ResourceOwner implements OnChanges {
public schemasList: ReadonlyArray<SchemaDto>; public schemasList: ReadonlyArray<SchemaDto>;
constructor( constructor(
private readonly changeDetector: ChangeDetectorRef private readonly changeDetector: ChangeDetectorRef,
) { ) {
super(); super();
} }
@ -78,4 +78,4 @@ export class ComponentComponent extends ResourceOwner implements OnChanges {
public trackBySection(_index: number, section: FieldSection<FieldDto, any>) { public trackBySection(_index: number, section: FieldSection<FieldDto, any>) {
return section.separator?.fieldId; return section.separator?.fieldId;
} }
} }

4
frontend/app/features/content/shared/forms/field-editor.component.ts

@ -14,7 +14,7 @@ import { map } from 'rxjs/operators';
@Component({ @Component({
selector: 'sqx-field-editor', selector: 'sqx-field-editor',
styleUrls: ['./field-editor.component.scss'], styleUrls: ['./field-editor.component.scss'],
templateUrl: './field-editor.component.html' templateUrl: './field-editor.component.html',
}) })
export class FieldEditorComponent implements OnChanges { export class FieldEditorComponent implements OnChanges {
@Input() @Input()
@ -89,4 +89,4 @@ export class FieldEditorComponent implements OnChanges {
public unset() { public unset() {
this.formModel.unset(); this.formModel.unset();
} }
} }

12
frontend/app/features/content/shared/forms/iframe-editor.component.ts

@ -12,7 +12,7 @@ import { DialogModel, DialogService, StatefulControlComponent, Types } from '@ap
import { AppsState, AssetDto, computeEditorUrl } from '@app/shared'; import { AppsState, AssetDto, computeEditorUrl } from '@app/shared';
export const SQX_IFRAME_EDITOR_CONTROL_VALUE_ACCESSOR: any = { export const SQX_IFRAME_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IFrameEditorComponent), multi: true provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IFrameEditorComponent), multi: true,
}; };
interface State { interface State {
@ -25,9 +25,9 @@ interface State {
styleUrls: ['./iframe-editor.component.scss'], styleUrls: ['./iframe-editor.component.scss'],
templateUrl: './iframe-editor.component.html', templateUrl: './iframe-editor.component.html',
providers: [ providers: [
SQX_IFRAME_EDITOR_CONTROL_VALUE_ACCESSOR SQX_IFRAME_EDITOR_CONTROL_VALUE_ACCESSOR,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class IFrameEditorComponent extends StatefulControlComponent<State, any> implements OnChanges, OnDestroy, AfterViewInit { export class IFrameEditorComponent extends StatefulControlComponent<State, any> implements OnChanges, OnDestroy, AfterViewInit {
private value: any; private value: any;
@ -72,10 +72,10 @@ export class IFrameEditorComponent extends StatefulControlComponent<State, any>
private readonly appsState: AppsState, private readonly appsState: AppsState,
private readonly dialogs: DialogService, private readonly dialogs: DialogService,
private readonly renderer: Renderer2, private readonly renderer: Renderer2,
private readonly router: Router private readonly router: Router,
) { ) {
super(changeDetector, { super(changeDetector, {
isFullscreen: false isFullscreen: false,
}); });
} }
@ -272,4 +272,4 @@ export class IFrameEditorComponent extends StatefulControlComponent<State, any>
iframe.contentWindow.postMessage(message, '*'); iframe.contentWindow.postMessage(message, '*');
} }
} }
} }

10
frontend/app/features/content/shared/forms/stock-photo-editor.component.ts

@ -12,7 +12,7 @@ import { of } from 'rxjs';
import { debounceTime, map, switchMap, tap } from 'rxjs/operators'; import { debounceTime, map, switchMap, tap } from 'rxjs/operators';
export const SQX_STOCK_PHOTO_EDITOR_CONTROL_VALUE_ACCESSOR: any = { export const SQX_STOCK_PHOTO_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StockPhotoEditorComponent), multi: true provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StockPhotoEditorComponent), multi: true,
}; };
interface State { interface State {
@ -28,9 +28,9 @@ interface State {
styleUrls: ['./stock-photo-editor.component.scss'], styleUrls: ['./stock-photo-editor.component.scss'],
templateUrl: './stock-photo-editor.component.html', templateUrl: './stock-photo-editor.component.html',
providers: [ providers: [
SQX_STOCK_PHOTO_EDITOR_CONTROL_VALUE_ACCESSOR SQX_STOCK_PHOTO_EDITOR_CONTROL_VALUE_ACCESSOR,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class StockPhotoEditorComponent extends StatefulControlComponent<State, string> implements OnInit { export class StockPhotoEditorComponent extends StatefulControlComponent<State, string> implements OnInit {
@Input() @Input()
@ -63,7 +63,7 @@ export class StockPhotoEditorComponent extends StatefulControlComponent<State, s
})); }));
constructor(changeDetector: ChangeDetectorRef, constructor(changeDetector: ChangeDetectorRef,
private readonly stockPhotoService: StockPhotoService private readonly stockPhotoService: StockPhotoService,
) { ) {
super(changeDetector, {}); super(changeDetector, {});
} }
@ -116,4 +116,4 @@ export class StockPhotoEditorComponent extends StatefulControlComponent<State, s
public trackByPhoto(_index: number, photo: StockPhotoDto) { public trackByPhoto(_index: number, photo: StockPhotoDto) {
return photo.thumbUrl; return photo.thumbUrl;
} }
} }

10
frontend/app/features/content/shared/list/content-list-cell.directive.ts

@ -53,7 +53,7 @@ export function getCellWidth(field: TableField) {
@Pipe({ @Pipe({
name: 'sqxContentsColumns', name: 'sqxContentsColumns',
pure: true pure: true,
}) })
export class ContentsColumnsPipe implements PipeTransform { export class ContentsColumnsPipe implements PipeTransform {
public transform(value: ReadonlyArray<ContentDto>) { public transform(value: ReadonlyArray<ContentDto>) {
@ -69,7 +69,7 @@ export class ContentsColumnsPipe implements PipeTransform {
@Pipe({ @Pipe({
name: 'sqxContentListWidth', name: 'sqxContentListWidth',
pure: true pure: true,
}) })
export class ContentListWidthPipe implements PipeTransform { export class ContentListWidthPipe implements PipeTransform {
public transform(value: ReadonlyArray<TableField>) { public transform(value: ReadonlyArray<TableField>) {
@ -82,7 +82,7 @@ export class ContentListWidthPipe implements PipeTransform {
} }
@Directive({ @Directive({
selector: '[sqxContentListCell]' selector: '[sqxContentListCell]',
}) })
export class ContentListCellDirective implements OnChanges { export class ContentListCellDirective implements OnChanges {
@Input('sqxContentListCell') @Input('sqxContentListCell')
@ -90,7 +90,7 @@ export class ContentListCellDirective implements OnChanges {
constructor( constructor(
private readonly element: ElementRef, private readonly element: ElementRef,
private readonly renderer: Renderer2 private readonly renderer: Renderer2,
) { ) {
} }
@ -103,4 +103,4 @@ export class ContentListCellDirective implements OnChanges {
this.renderer.setStyle(this.element.nativeElement, 'width', width); this.renderer.setStyle(this.element.nativeElement, 'width', width);
} }
} }
} }

6
frontend/app/features/content/shared/list/content-list-field.component.ts

@ -18,7 +18,7 @@ interface State {
selector: 'sqx-content-list-field', selector: 'sqx-content-list-field',
styleUrls: ['./content-list-field.component.scss'], styleUrls: ['./content-list-field.component.scss'],
templateUrl: './content-list-field.component.html', templateUrl: './content-list-field.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentListFieldComponent extends StatefulComponent<State> implements OnChanges { export class ContentListFieldComponent extends StatefulComponent<State> implements OnChanges {
@Input() @Input()
@ -38,7 +38,7 @@ export class ContentListFieldComponent extends StatefulComponent<State> implemen
constructor(changeDetector: ChangeDetectorRef) { constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector, { super(changeDetector, {
formatted: '' formatted: '',
}); });
} }
@ -73,4 +73,4 @@ export class ContentListFieldComponent extends StatefulComponent<State> implemen
public get fieldName() { public get fieldName() {
return Types.is(this.field, RootFieldDto) ? this.field.name : this.field; return Types.is(this.field, RootFieldDto) ? this.field.name : this.field;
} }
} }

4
frontend/app/features/content/shared/list/content-list-header.component.ts

@ -12,7 +12,7 @@ import { LanguageDto, MetaFields, Query, RootFieldDto, TableField, Types } from
selector: 'sqx-content-list-header', selector: 'sqx-content-list-header',
styleUrls: ['./content-list-header.component.scss'], styleUrls: ['./content-list-header.component.scss'],
templateUrl: './content-list-header.component.html', templateUrl: './content-list-header.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentListHeaderComponent { export class ContentListHeaderComponent {
@Input() @Input()
@ -52,4 +52,4 @@ export class ContentListHeaderComponent {
return `data.${this.field.name}.iv`; return `data.${this.field.name}.iv`;
} }
} }
} }

4
frontend/app/features/content/shared/list/content-value-editor.component.ts

@ -13,7 +13,7 @@ import { FieldDto, MathHelper } from '@app/shared';
selector: 'sqx-content-value-editor', selector: 'sqx-content-value-editor',
styleUrls: ['./content-value-editor.component.scss'], styleUrls: ['./content-value-editor.component.scss'],
templateUrl: './content-value-editor.component.html', templateUrl: './content-value-editor.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentValueEditorComponent { export class ContentValueEditorComponent {
@Input() @Input()
@ -23,4 +23,4 @@ export class ContentValueEditorComponent {
public form: FormGroup; public form: FormGroup;
public readonly uniqueId = MathHelper.guid(); public readonly uniqueId = MathHelper.guid();
} }

4
frontend/app/features/content/shared/list/content-value.component.ts

@ -12,7 +12,7 @@ import { HtmlValue, Types } from '@app/shared';
selector: 'sqx-content-value', selector: 'sqx-content-value',
styleUrls: ['./content-value.component.scss'], styleUrls: ['./content-value.component.scss'],
templateUrl: './content-value.component.html', templateUrl: './content-value.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentValueComponent { export class ContentValueComponent {
@Input() @Input()
@ -21,4 +21,4 @@ export class ContentValueComponent {
public get isPlain() { public get isPlain() {
return !Types.is(this.value, HtmlValue); return !Types.is(this.value, HtmlValue);
} }
} }

10
frontend/app/features/content/shared/list/content.component.ts

@ -16,9 +16,9 @@ import { ContentListFieldComponent } from './content-list-field.component';
styleUrls: ['./content.component.scss'], styleUrls: ['./content.component.scss'],
templateUrl: './content.component.html', templateUrl: './content.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentComponent implements OnChanges { export class ContentComponent implements OnChanges {
@Output() @Output()
@ -65,7 +65,7 @@ export class ContentComponent implements OnChanges {
constructor( constructor(
private readonly changeDetector: ChangeDetectorRef, private readonly changeDetector: ChangeDetectorRef,
private readonly contentsState: ContentsState private readonly contentsState: ContentsState,
) { ) {
} }
@ -89,7 +89,7 @@ export class ContentComponent implements OnChanges {
if (value) { if (value) {
this.contentsState.patch(this.content, value) this.contentsState.patch(this.content, value)
.subscribe(() => { .subscribe(() => {
this.patchForm.submitCompleted({ noReset: true}); this.patchForm.submitCompleted({ noReset: true });
this.changeDetector.markForCheck(); this.changeDetector.markForCheck();
}, error => { }, error => {
@ -113,4 +113,4 @@ export class ContentComponent implements OnChanges {
this.fields.forEach(x => x.reset()); this.fields.forEach(x => x.reset());
} }
} }

10
frontend/app/features/content/shared/preview-button.component.ts

@ -23,9 +23,9 @@ interface State {
styleUrls: ['./preview-button.component.scss'], styleUrls: ['./preview-button.component.scss'],
templateUrl: './preview-button.component.html', templateUrl: './preview-button.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class PreviewButtonComponent extends StatefulComponent<State> implements OnInit { export class PreviewButtonComponent extends StatefulComponent<State> implements OnInit {
@Input() @Input()
@ -40,10 +40,10 @@ export class PreviewButtonComponent extends StatefulComponent<State> implements
public dropdown = new ModalModel(); public dropdown = new ModalModel();
constructor(changeDetector: ChangeDetectorRef, constructor(changeDetector: ChangeDetectorRef,
private readonly localStore: LocalStoreService private readonly localStore: LocalStoreService,
) { ) {
super(changeDetector, { super(changeDetector, {
previewNamesMore: [] previewNamesMore: [],
}); });
} }
@ -104,4 +104,4 @@ export class PreviewButtonComponent extends StatefulComponent<State> implements
private configKey() { private configKey() {
return Settings.Local.SCHEMA_PREVIEW(this.schema.id); return Settings.Local.SCHEMA_PREVIEW(this.schema.id);
} }
} }

8
frontend/app/features/content/shared/references/content-creator.component.ts

@ -13,8 +13,8 @@ import { AppLanguageDto, ComponentContentsState, ContentDto, EditContentForm, Re
styleUrls: ['./content-creator.component.scss'], styleUrls: ['./content-creator.component.scss'],
templateUrl: './content-creator.component.html', templateUrl: './content-creator.component.html',
providers: [ providers: [
ComponentContentsState ComponentContentsState,
] ],
}) })
export class ContentCreatorComponent extends ResourceOwner implements OnInit { export class ContentCreatorComponent extends ResourceOwner implements OnInit {
@Output() @Output()
@ -45,7 +45,7 @@ export class ContentCreatorComponent extends ResourceOwner implements OnInit {
constructor( constructor(
private readonly contentsState: ComponentContentsState, private readonly contentsState: ComponentContentsState,
private readonly schemasState: SchemasState private readonly schemasState: SchemasState,
) { ) {
super(); super();
} }
@ -121,4 +121,4 @@ export class ContentCreatorComponent extends ResourceOwner implements OnInit {
public emitSelect(content: ContentDto) { public emitSelect(content: ContentDto) {
this.select.emit([content]); this.select.emit([content]);
} }
} }

4
frontend/app/features/content/shared/references/content-selector-item.component.ts

@ -14,7 +14,7 @@ import { ContentDto, LanguageDto, SchemaDto } from '@app/shared';
selector: '[sqxContentSelectorItem]', selector: '[sqxContentSelectorItem]',
styleUrls: ['./content-selector-item.component.scss'], styleUrls: ['./content-selector-item.component.scss'],
templateUrl: './content-selector-item.component.html', templateUrl: './content-selector-item.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentSelectorItemComponent { export class ContentSelectorItemComponent {
@Output() @Output()
@ -44,4 +44,4 @@ export class ContentSelectorItemComponent {
public select(isSelected: boolean) { public select(isSelected: boolean) {
this.selectedChange.emit(isSelected); this.selectedChange.emit(isSelected);
} }
} }

10
frontend/app/features/content/shared/references/content-selector.component.ts

@ -13,8 +13,8 @@ import { ApiUrlConfig, AppsState, ComponentContentsState, ContentDto, LanguageDt
styleUrls: ['./content-selector.component.scss'], styleUrls: ['./content-selector.component.scss'],
templateUrl: './content-selector.component.html', templateUrl: './content-selector.component.html',
providers: [ providers: [
ComponentContentsState ComponentContentsState,
] ],
}) })
export class ContentSelectorComponent extends ResourceOwner implements OnInit { export class ContentSelectorComponent extends ResourceOwner implements OnInit {
@Output() @Output()
@ -43,7 +43,7 @@ export class ContentSelectorComponent extends ResourceOwner implements OnInit {
public queryModel: QueryModel; public queryModel: QueryModel;
public selectedItems: { [id: string]: ContentDto; } = {}; public selectedItems: { [id: string]: ContentDto } = {};
public selectionCount = 0; public selectionCount = 0;
public selectedAll = false; public selectedAll = false;
@ -51,7 +51,7 @@ export class ContentSelectorComponent extends ResourceOwner implements OnInit {
public readonly appsState: AppsState, public readonly appsState: AppsState,
public readonly apiUrl: ApiUrlConfig, public readonly apiUrl: ApiUrlConfig,
public readonly contentsState: ComponentContentsState, public readonly contentsState: ComponentContentsState,
public readonly schemasState: SchemasState public readonly schemasState: SchemasState,
) { ) {
super(); super();
} }
@ -145,4 +145,4 @@ export class ContentSelectorComponent extends ResourceOwner implements OnInit {
public trackByContent(_index: number, content: ContentDto): string { public trackByContent(_index: number, content: ContentDto): string {
return content.id; return content.id;
} }
} }

4
frontend/app/features/content/shared/references/reference-item.component.ts

@ -14,7 +14,7 @@ import { AppLanguageDto, ContentDto, getContentValue } from '@app/shared';
selector: '[sqxReferenceItem]', selector: '[sqxReferenceItem]',
styleUrls: ['./reference-item.component.scss'], styleUrls: ['./reference-item.component.scss'],
templateUrl: './reference-item.component.html', templateUrl: './reference-item.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ReferenceItemComponent implements OnChanges { export class ReferenceItemComponent implements OnChanges {
@Output() @Output()
@ -70,4 +70,4 @@ export class ReferenceItemComponent implements OnChanges {
this.values = values; this.values = values;
} }
} }

10
frontend/app/features/content/shared/references/references-editor.component.ts

@ -11,7 +11,7 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { AppLanguageDto, AppsState, ContentDto, ContentsService, DialogModel, sorted, StatefulControlComponent, Types } from '@app/shared'; import { AppLanguageDto, AppsState, ContentDto, ContentsService, DialogModel, sorted, StatefulControlComponent, Types } from '@app/shared';
export const SQX_REFERENCES_EDITOR_CONTROL_VALUE_ACCESSOR: any = { export const SQX_REFERENCES_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ReferencesEditorComponent), multi: true provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ReferencesEditorComponent), multi: true,
}; };
interface State { interface State {
@ -27,9 +27,9 @@ interface State {
styleUrls: ['./references-editor.component.scss'], styleUrls: ['./references-editor.component.scss'],
templateUrl: './references-editor.component.html', templateUrl: './references-editor.component.html',
providers: [ providers: [
SQX_REFERENCES_EDITOR_CONTROL_VALUE_ACCESSOR SQX_REFERENCES_EDITOR_CONTROL_VALUE_ACCESSOR,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ReferencesEditorComponent extends StatefulControlComponent<State, ReadonlyArray<string>> { export class ReferencesEditorComponent extends StatefulControlComponent<State, ReadonlyArray<string>> {
@Input() @Input()
@ -59,7 +59,7 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, R
constructor(changeDetector: ChangeDetectorRef, constructor(changeDetector: ChangeDetectorRef,
private readonly appsState: AppsState, private readonly appsState: AppsState,
private readonly contentsService: ContentsService private readonly contentsService: ContentsService,
) { ) {
super(changeDetector, { contentItems: [] }); super(changeDetector, { contentItems: [] });
} }
@ -141,4 +141,4 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, R
public trackByContent(_index: number, content: ContentDto) { public trackByContent(_index: number, content: ContentDto) {
return content.id; return content.id;
} }
} }

2
frontend/app/features/dashboard/index.ts

@ -1,4 +1,4 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license

16
frontend/app/features/dashboard/module.ts

@ -5,20 +5,18 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
// tslint:disable: max-line-length
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { SqxFrameworkModule, SqxSharedModule } from '@app/shared'; import { SqxFrameworkModule, SqxSharedModule } from '@app/shared';
import { GridsterModule } from 'angular-gridster2'; import { GridsterModule } from 'angular-gridster2';
import { ChartModule } from 'angular2-chartjs'; import { ChartModule } from 'angular2-chartjs';
import { ApiCallsCardComponent, ApiCallsSummaryCardComponent, ApiCardComponent, ApiPerformanceCardComponent, ApiTrafficCardComponent, ApiTrafficSummaryCardComponent, AssetUploadsCountCardComponent, AssetUploadsSizeCardComponent, AssetUploadsSizeSummaryCardComponent, ContentSummaryCardComponent, DashboardConfigComponent, DashboardPageComponent, GithubCardComponent, HistoryCardComponent, IFrameCardComponent, SchemaCardComponent, SupportCardComponent } from './declarations'; import { ApiCallsCardComponent, ApiCallsSummaryCardComponent, ApiCardComponent, ApiPerformanceCardComponent, ApiTrafficCardComponent, ApiTrafficSummaryCardComponent, AssetUploadsCountCardComponent, AssetUploadsSizeCardComponent, AssetUploadsSizeSummaryCardComponent, ContentSummaryCardComponent, DashboardConfigComponent, DashboardPageComponent, GithubCardComponent, HistoryCardComponent, IFrameCardComponent, SchemaCardComponent, SupportCardComponent } from './declarations';
const routes: Routes = [ const routes: Routes = [
{ {
path: '', path: '',
component: DashboardPageComponent component: DashboardPageComponent,
} },
]; ];
@NgModule({ @NgModule({
@ -27,7 +25,7 @@ const routes: Routes = [
GridsterModule, GridsterModule,
RouterModule.forChild(routes), RouterModule.forChild(routes),
SqxFrameworkModule, SqxFrameworkModule,
SqxSharedModule SqxSharedModule,
], ],
declarations: [ declarations: [
ApiCallsCardComponent, ApiCallsCardComponent,
@ -46,7 +44,7 @@ const routes: Routes = [
HistoryCardComponent, HistoryCardComponent,
IFrameCardComponent, IFrameCardComponent,
SchemaCardComponent, SchemaCardComponent,
SupportCardComponent SupportCardComponent,
] ],
}) })
export class SqxFeatureDashboardModule {} export class SqxFeatureDashboardModule {}

12
frontend/app/features/dashboard/pages/cards/api-calls-card.component.ts

@ -14,9 +14,9 @@ import { ChartHelpers, ChartOptions } from './shared';
styleUrls: ['./api-calls-card.component.scss'], styleUrls: ['./api-calls-card.component.scss'],
templateUrl: './api-calls-card.component.html', templateUrl: './api-calls-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ApiCallsCardComponent implements OnChanges { export class ApiCallsCardComponent implements OnChanges {
@Input() @Input()
@ -29,7 +29,7 @@ export class ApiCallsCardComponent implements OnChanges {
public chartData: any; public chartData: any;
constructor( constructor(
private readonly usagesService: UsagesService private readonly usagesService: UsagesService,
) { ) {
} }
@ -45,8 +45,8 @@ export class ApiCallsCardComponent implements OnChanges {
backgroundColor: ChartHelpers.getBackgroundColor(i), backgroundColor: ChartHelpers.getBackgroundColor(i),
borderColor: ChartHelpers.getBorderColor(i), borderColor: ChartHelpers.getBorderColor(i),
borderWidth: 1, borderWidth: 1,
data: this.usage.details[k].map(x => x.totalCalls) data: this.usage.details[k].map(x => x.totalCalls),
})) })),
}; };
} }
} }
@ -57,4 +57,4 @@ export class ApiCallsCardComponent implements OnChanges {
window.open(url, '_blank'); window.open(url, '_blank');
}); });
} }
} }

6
frontend/app/features/dashboard/pages/cards/api-calls-summary-card.component.ts

@ -13,9 +13,9 @@ import { AppDto, CallsUsageDto, fadeAnimation } from '@app/shared';
styleUrls: ['./api-calls-summary-card.component.scss'], styleUrls: ['./api-calls-summary-card.component.scss'],
templateUrl: './api-calls-summary-card.component.html', templateUrl: './api-calls-summary-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ApiCallsSummaryCardComponent implements OnChanges { export class ApiCallsSummaryCardComponent implements OnChanges {
@Input() @Input()
@ -33,4 +33,4 @@ export class ApiCallsSummaryCardComponent implements OnChanges {
this.callsAllowed = this.usage.allowedCalls; this.callsAllowed = this.usage.allowedCalls;
} }
} }
} }

6
frontend/app/features/dashboard/pages/cards/api-card.component.ts

@ -13,11 +13,11 @@ import { AppDto, fadeAnimation } from '@app/shared';
styleUrls: ['./api-card.component.scss'], styleUrls: ['./api-card.component.scss'],
templateUrl: './api-card.component.html', templateUrl: './api-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ApiCardComponent { export class ApiCardComponent {
@Input() @Input()
public app: AppDto; public app: AppDto;
} }

11
frontend/app/features/dashboard/pages/cards/api-performance-card.component.ts

@ -1,4 +1,3 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
@ -15,9 +14,9 @@ import { ChartHelpers, ChartOptions } from './shared';
styleUrls: ['./api-performance-card.component.scss'], styleUrls: ['./api-performance-card.component.scss'],
templateUrl: './api-performance-card.component.html', templateUrl: './api-performance-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ApiPerformanceCardComponent implements OnChanges { export class ApiPerformanceCardComponent implements OnChanges {
@Input() @Input()
@ -51,11 +50,11 @@ export class ApiPerformanceCardComponent implements OnChanges {
backgroundColor: ChartHelpers.getBackgroundColor(i), backgroundColor: ChartHelpers.getBackgroundColor(i),
borderColor: ChartHelpers.getBorderColor(i), borderColor: ChartHelpers.getBorderColor(i),
borderWidth: 1, borderWidth: 1,
data: this.usage.details[k].map(x => x.averageElapsedMs) data: this.usage.details[k].map(x => x.averageElapsedMs),
})) })),
}; };
this.chartSummary = this.usage.averageElapsedMs; this.chartSummary = this.usage.averageElapsedMs;
} }
} }
} }

11
frontend/app/features/dashboard/pages/cards/api-traffic-card.component.ts

@ -1,4 +1,3 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
@ -15,9 +14,9 @@ import { ChartHelpers, ChartOptions } from './shared';
styleUrls: ['./api-traffic-card.component.scss'], styleUrls: ['./api-traffic-card.component.scss'],
templateUrl: './api-traffic-card.component.html', templateUrl: './api-traffic-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ApiTrafficCardComponent implements OnChanges { export class ApiTrafficCardComponent implements OnChanges {
@Input() @Input()
@ -51,11 +50,11 @@ export class ApiTrafficCardComponent implements OnChanges {
backgroundColor: ChartHelpers.getBackgroundColor(i), backgroundColor: ChartHelpers.getBackgroundColor(i),
borderColor: ChartHelpers.getBorderColor(i), borderColor: ChartHelpers.getBorderColor(i),
borderWidth: 1, borderWidth: 1,
data: this.usage.details[k].map(x => Math.round(100 * (x.totalBytes / (1024 * 1024))) / 100) data: this.usage.details[k].map(x => Math.round(100 * (x.totalBytes / (1024 * 1024))) / 100),
})) })),
}; };
this.chartSummary = this.usage.totalBytes; this.chartSummary = this.usage.totalBytes;
} }
} }
} }

7
frontend/app/features/dashboard/pages/cards/api-traffic-summary-card.component.ts

@ -1,4 +1,3 @@
/* /*
* Squidex Headless CMS * Squidex Headless CMS
* *
@ -14,9 +13,9 @@ import { AppDto, CallsUsageDto, fadeAnimation } from '@app/shared';
styleUrls: ['./api-traffic-summary-card.component.scss'], styleUrls: ['./api-traffic-summary-card.component.scss'],
templateUrl: './api-traffic-summary-card.component.html', templateUrl: './api-traffic-summary-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ApiTrafficSummaryCardComponent implements OnChanges { export class ApiTrafficSummaryCardComponent implements OnChanges {
@Input() @Input()
@ -34,4 +33,4 @@ export class ApiTrafficSummaryCardComponent implements OnChanges {
this.bytesAllowed = this.usage.allowedBytes; this.bytesAllowed = this.usage.allowedBytes;
} }
} }
} }

12
frontend/app/features/dashboard/pages/cards/asset-uploads-count-card.component.ts

@ -14,9 +14,9 @@ import { ChartHelpers, ChartOptions } from './shared';
styleUrls: ['./asset-uploads-count-card.component.scss'], styleUrls: ['./asset-uploads-count-card.component.scss'],
templateUrl: './asset-uploads-count-card.component.html', templateUrl: './asset-uploads-count-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AssetUploadsCountCardComponent implements OnChanges { export class AssetUploadsCountCardComponent implements OnChanges {
@Input() @Input()
@ -42,10 +42,10 @@ export class AssetUploadsCountCardComponent implements OnChanges {
backgroundColor: ChartHelpers.getBackgroundColor(), backgroundColor: ChartHelpers.getBackgroundColor(),
borderColor: ChartHelpers.getBorderColor(), borderColor: ChartHelpers.getBorderColor(),
borderWidth: 1, borderWidth: 1,
data: this.usage.map(x => x.totalCount) data: this.usage.map(x => x.totalCount),
} },
] ],
}; };
} }
} }
} }

12
frontend/app/features/dashboard/pages/cards/asset-uploads-size-card.component.ts

@ -14,9 +14,9 @@ import { ChartHelpers, ChartOptions } from './shared';
styleUrls: ['./asset-uploads-size-card.component.scss'], styleUrls: ['./asset-uploads-size-card.component.scss'],
templateUrl: './asset-uploads-size-card.component.html', templateUrl: './asset-uploads-size-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AssetUploadsSizeCardComponent implements OnChanges { export class AssetUploadsSizeCardComponent implements OnChanges {
@Input() @Input()
@ -42,10 +42,10 @@ export class AssetUploadsSizeCardComponent implements OnChanges {
backgroundColor: ChartHelpers.getBackgroundColor(), backgroundColor: ChartHelpers.getBackgroundColor(),
borderColor: ChartHelpers.getBorderColor(), borderColor: ChartHelpers.getBorderColor(),
borderWidth: 1, borderWidth: 1,
data: this.usage.map(x => Math.round(100 * (x.totalSize / (1024 * 1024))) / 100) data: this.usage.map(x => Math.round(100 * (x.totalSize / (1024 * 1024))) / 100),
} },
] ],
}; };
} }
} }
} }

6
frontend/app/features/dashboard/pages/cards/asset-uploads-size-summary-card.component.ts

@ -13,9 +13,9 @@ import { AppDto, CurrentStorageDto, fadeAnimation } from '@app/shared';
styleUrls: ['./asset-uploads-size-summary-card.component.scss'], styleUrls: ['./asset-uploads-size-summary-card.component.scss'],
templateUrl: './asset-uploads-size-summary-card.component.html', templateUrl: './asset-uploads-size-summary-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AssetUploadsSizeSummaryCardComponent implements OnChanges { export class AssetUploadsSizeSummaryCardComponent implements OnChanges {
@Input() @Input()
@ -33,4 +33,4 @@ export class AssetUploadsSizeSummaryCardComponent implements OnChanges {
this.storageAllowed = this.usage.maxAllowed; this.storageAllowed = this.usage.maxAllowed;
} }
} }
} }

10
frontend/app/features/dashboard/pages/cards/content-summary-card.component.ts

@ -18,9 +18,9 @@ interface State {
styleUrls: ['./content-summary-card.component.scss'], styleUrls: ['./content-summary-card.component.scss'],
templateUrl: './content-summary-card.component.html', templateUrl: './content-summary-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentSummaryCardComponent extends StatefulComponent<State> implements OnInit { export class ContentSummaryCardComponent extends StatefulComponent<State> implements OnInit {
@Input() @Input()
@ -30,10 +30,10 @@ export class ContentSummaryCardComponent extends StatefulComponent<State> implem
public options: any; public options: any;
constructor(changeDetector: ChangeDetectorRef, constructor(changeDetector: ChangeDetectorRef,
private readonly contentsService: ContentsService private readonly contentsService: ContentsService,
) { ) {
super(changeDetector, { super(changeDetector, {
itemCount: 0 itemCount: 0,
}); });
} }
@ -58,4 +58,4 @@ export class ContentSummaryCardComponent extends StatefulComponent<State> implem
this.next({ itemCount: 0 }); this.next({ itemCount: 0 });
}); });
} }
} }

6
frontend/app/features/dashboard/pages/cards/github-card.component.ts

@ -13,11 +13,11 @@ import { AppDto, fadeAnimation } from '@app/shared';
styleUrls: ['./github-card.component.scss'], styleUrls: ['./github-card.component.scss'],
templateUrl: './github-card.component.html', templateUrl: './github-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class GithubCardComponent { export class GithubCardComponent {
@Input() @Input()
public app: AppDto; public app: AppDto;
} }

8
frontend/app/features/dashboard/pages/cards/history-card.component.ts

@ -14,9 +14,9 @@ import { Observable } from 'rxjs';
styleUrls: ['./history-card.component.scss'], styleUrls: ['./history-card.component.scss'],
templateUrl: './history-card.component.html', templateUrl: './history-card.component.html',
animations: [ animations: [
fadeAnimation fadeAnimation,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class HistoryCardComponent implements OnChanges { export class HistoryCardComponent implements OnChanges {
@Input() @Input()
@ -25,11 +25,11 @@ export class HistoryCardComponent implements OnChanges {
public history: Observable<ReadonlyArray<HistoryEventDto>>; public history: Observable<ReadonlyArray<HistoryEventDto>>;
constructor( constructor(
private readonly historyService: HistoryService private readonly historyService: HistoryService,
) { ) {
} }
public ngOnChanges() { public ngOnChanges() {
this.history = this.historyService.getHistory(this.app.name, ''); this.history = this.historyService.getHistory(this.app.name, '');
} }
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save