diff --git a/.travis.yml b/.travis.yml index 01817b460..dc9afcb73 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,12 +60,12 @@ matrix: - language: node_js name: "Client: Linting" node_js: - - "10.5" + - "10.9" cache: directories: - node_modules before_install: - - npm install -g @angular/cli@~7.3.8 + - npm install -g @angular/cli@~8.0.6 - ng --version - cd client install: @@ -76,12 +76,12 @@ matrix: - language: node_js name: "Client: Code Formatting Check" node_js: - - "10.5" + - "10.9" cache: directories: - node_modules before_install: - - npm install -g @angular/cli@~7.3.8 + - npm install -g @angular/cli@~8.0.6 - ng --version - cd client install: @@ -93,7 +93,7 @@ matrix: - language: node_js name: "Client: Testing" node_js: - - "10.5" + - "10.9" apt: sources: - google-chrome @@ -107,7 +107,7 @@ matrix: before_install: - export CHROME_BIN=/usr/bin/google-chrome - export DISPLAY=:99.0 - - npm install -g @angular/cli@~7.3.8 + - npm install -g @angular/cli@~8.0.6 - ng --version - cd client install: @@ -118,12 +118,12 @@ matrix: - language: node_js name: "Client: Build" node_js: - - "10.5" + - "10.9" cache: directories: - node_modules before_install: - - npm install -g @angular/cli@~7.3.8 + - npm install -g @angular/cli@~8.0.6 - ng --version - cd client install: @@ -134,12 +134,12 @@ matrix: - language: node_js name: "Client: Production Build" node_js: - - "10.5" + - "10.9" cache: directories: - node_modules before_install: - - npm install -g @angular/cli@~7.3.8 + - npm install -g @angular/cli@~8.0.6 - ng --version - cd client install: diff --git a/client/README.md b/client/README.md index e299d3025..650f2022b 100644 --- a/client/README.md +++ b/client/README.md @@ -59,62 +59,63 @@ Language files can be found in `/src/assets/i18n`. OpenSlides uses the following software or parts of them: -- [@angular/animations@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/cdk-experimental@7.3.7](https://github.com/angular/material2), License: MIT -- [@angular/cdk@7.3.7](https://github.com/angular/material2), License: MIT -- [@angular/common@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/compiler@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/core@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/forms@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/http@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/material@7.3.7](https://github.com/angular/material2), License: MIT -- [@angular/platform-browser-dynamic@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/platform-browser@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/pwa@0.13.8](https://github.com/angular/angular-cli), License: MIT -- [@angular/router@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/service-worker@7.2.14](https://github.com/angular/angular), License: MIT -- [@ngx-pwa/local-storage@7.4.2](https://github.com/cyrilletuzi/angular-async-local-storage), License: MIT +- [@angular/animations@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/cdk-experimental@8.0.1](https://github.com/angular/components), License: MIT +- [@angular/cdk@8.0.1](https://github.com/angular/components), License: MIT +- [@angular/common@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/compiler@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/core@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/forms@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/material@8.0.1](https://github.com/angular/components), License: MIT +- [@angular/platform-browser-dynamic@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/platform-browser@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/pwa@0.800.6](https://github.com/angular/angular-cli), License: MIT +- [@angular/router@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/service-worker@8.0.3](https://github.com/angular/angular), License: MIT +- [@ngx-pwa/local-storage@8.0.2](https://github.com/cyrilletuzi/angular-async-local-storage), License: MIT - [@ngx-translate/core@11.0.1](https://github.com/ngx-translate/core), License: MIT - [@ngx-translate/http-loader@4.0.0](https://github.com/ngx-translate/http-loader), License: MIT -- [@pebula/ngrid-material@1.0.0-alpha.20](https://github.com/shlomiassaf/ngrid), License: MIT -- [@pebula/ngrid@1.0.0-alpha.20](https://github.com/shlomiassaf/ngrid), License: MIT +- [@pebula/ngrid-material@1.0.0-alpha.26](https://github.com/shlomiassaf/ngrid), License: MIT +- [@pebula/ngrid@1.0.0-alpha.26](https://github.com/shlomiassaf/ngrid), License: MIT - [@pebula/utils@1.0.0-alpha.3](https://github.com/shlomiassaf/ngrid), License: MIT -- [@tinymce/tinymce-angular@3.0.0](https://github.com/tinymce/tinymce-angular), License: Apache-2.0 -- [core-js@3.0.1](https://github.com/zloirock/core-js), License: MIT -- [css-element-queries@1.1.1](https://github.com/marcj/css-element-queries), License: MIT -- [exceljs@1.9.1](https://github.com/exceljs/exceljs), License: MIT -- [file-saver@2.0.1](https://github.com/eligrey/FileSaver.js), License: MIT +- [@tinymce/tinymce-angular@3.2.0](https://github.com/tinymce/tinymce-angular), License: Apache-2.0 +- [acorn@6.1.1](https://github.com/acornjs/acorn), License: MIT +- [core-js@3.1.4](https://github.com/zloirock/core-js), License: MIT +- [css-element-queries@1.2.0](https://github.com/marcj/css-element-queries), License: MIT +- [exceljs@1.13.0](https://github.com/exceljs/exceljs), License: MIT +- [file-saver@2.0.2](https://github.com/eligrey/FileSaver.js), License: MIT - [hammerjs@2.0.8](https://github.com/hammerjs/hammer.js), License: MIT - [lz4js@0.2.0](https://github.com/Benzinga/lz4js), License: ISC - [material-icon-font@0.1.0](https://github.com//petergng/svgFontCreator), License: ISC -- [ng-pick-datetime@7.0.0](https://github.com/DanielYKPan/date-time-picker), License: MIT - [ng2-pdf-viewer@5.3.2](git+https://vadimdez@github.com/VadimDez/ng2-pdf-viewer), License: MIT -- [ngx-file-drop@6.0.0](https://github.com/georgipeltekov/ngx-file-drop), License: MIT -- [ngx-mat-select-search@1.7.2](https://github.com/bithost-gmbh/ngx-mat-select-search), License: MIT -- [ngx-papaparse@3.0.2](https://github.com/alberthaff/ngx-papaparse), License: MIT -- [pdfmake@0.1.54](https://github.com/bpampuch/pdfmake), License: MIT +- [ngx-file-drop@8.0.3](https://github.com/georgipeltekov/ngx-file-drop), License: MIT +- [ngx-mat-select-search@1.7.6](https://github.com/bithost-gmbh/ngx-mat-select-search), License: MIT +- [ngx-papaparse@3.0.3](https://github.com/alberthaff/ngx-papaparse), License: MIT +- [pdfmake@0.1.57](https://github.com/bpampuch/pdfmake), License: MIT - [po2json@1.0.0-alpha](https://github.com/mikeedwards/po2json), License: GNU Library General Public License -- [rxjs@6.5.1](https://github.com/reactivex/rxjs), License: Apache-2.0 -- [tinymce@4.9.4](https://github.com/tinymce/tinymce-dist), License: LGPL-2.1 +- [rxjs@6.5.2](https://github.com/reactivex/rxjs), License: Apache-2.0 +- [text-encoding@0.7.0](https://github.com/inexorabletash/text-encoding), License: (Unlicense OR Apache-2.0) +- [tinymce@5.0.9](https://github.com/tinymce/tinymce-dist), License: LGPL-2.1 +- [tslib@1.10.0](https://github.com/Microsoft/tslib), License: Apache-2.0 - [uuid@3.3.2](https://github.com/kelektiv/node-uuid), License: MIT -- [zone.js@0.8.29](https://github.com/angular/zone.js), License: MIT -- [@angular-devkit/build-angular@0.13.8](https://github.com/angular/angular-cli), License: MIT -- [@angular/cli@7.3.8](https://github.com/angular/angular-cli), License: MIT -- [@angular/compiler-cli@7.2.14](https://github.com/angular/angular), License: MIT -- [@angular/language-service@7.2.14](https://github.com/angular/angular), License: MIT +- [zone.js@0.9.1](https://github.com/angular/zone.js), License: MIT +- [@angular-devkit/build-angular@0.800.6](https://github.com/angular/angular-cli), License: MIT +- [@angular/cli@8.0.6](https://github.com/angular/angular-cli), License: MIT +- [@angular/compiler-cli@8.0.3](https://github.com/angular/angular), License: MIT +- [@angular/language-service@8.0.3](https://github.com/angular/angular), License: MIT - [@biesbjerg/ngx-translate-extract@2.3.4](https://github.com/biesbjerg/ngx-translate-extract), License: MIT - [@compodoc/compodoc@1.1.9](https://github.com/compodoc/compodoc), License: MIT -- [@types/jasmine@3.3.12](https://github.com/DefinitelyTyped/DefinitelyTyped), License: MIT +- [@types/jasmine@3.3.13](https://github.com/DefinitelyTyped/DefinitelyTyped), License: MIT - [@types/jasminewd2@2.0.6](https://github.com/DefinitelyTyped/DefinitelyTyped), License: MIT -- [@types/node@11.13.7](https://github.com/DefinitelyTyped/DefinitelyTyped), License: MIT +- [@types/node@8.9.5](https://github.com/DefinitelyTyped/DefinitelyTyped), License: MIT - [@types/yargs@13.0.0](https://github.com/DefinitelyTyped/DefinitelyTyped), License: MIT -- [codelyzer@5.0.1](https://github.com/mgechev/codelyzer), License: MIT -- [husky@1.3.1](https://github.com/typicode/husky), License: MIT +- [codelyzer@5.1.0](https://github.com/mgechev/codelyzer), License: MIT +- [husky@2.7.0](https://github.com/typicode/husky), License: MIT - [jasmine-core@3.4.0](https://github.com/jasmine/jasmine), License: MIT - [jasmine-spec-reporter@4.2.1](https://github.com/bcaudan/jasmine-spec-reporter), License: Apache-2.0 - [karma-chrome-launcher@2.2.0](https://github.com/karma-runner/karma-chrome-launcher), License: MIT - [karma-coverage-istanbul-reporter@2.0.5](https://github.com/mattlewis92/karma-coverage-istanbul-reporter), License: MIT -- [karma-jasmine-html-reporter@1.4.0](https://github.com/dfederm/karma-jasmine-html-reporter), License: MIT +- [karma-jasmine-html-reporter@1.4.2](https://github.com/dfederm/karma-jasmine-html-reporter), License: MIT - [karma-jasmine@2.0.1](https://github.com/karma-runner/karma-jasmine), License: MIT - [karma@4.1.0](https://github.com/karma-runner/karma), License: MIT - [npm-license-crawler@0.2.1](https://github.com/mwittig/npm-license-crawler), License: BSD-3-Clause @@ -122,8 +123,9 @@ OpenSlides uses the following software or parts of them: - [prettier@1.18.2](https://github.com/prettier/prettier), License: MIT - [protractor@5.4.2](https://github.com/angular/protractor), License: MIT - [resize-observer-polyfill@1.5.1](https://github.com/que-etc/resize-observer-polyfill), License: MIT -- [source-map-explorer@1.8.0](https://github.com/danvk/source-map-explorer), License: Apache-2.0 -- [ts-node@8.1.0](https://github.com/TypeStrong/ts-node), License: MIT -- [tslint@5.16.0](https://github.com/palantir/tslint), License: Apache-2.0 -- [tsutils@3.10.0](https://github.com/ajafff/tsutils), License: MIT +- [source-map-explorer@2.0.1](https://github.com/danvk/source-map-explorer), License: Apache-2.0 +- [ts-node@7.0.1](https://github.com/TypeStrong/ts-node), License: MIT +- [tslint@5.15.0](https://github.com/palantir/tslint), License: Apache-2.0 +- [tsutils@3.14.0](https://github.com/ajafff/tsutils), License: MIT +- [typescript@3.4.5](https://github.com/Microsoft/TypeScript), License: Apache-2.0 - [webpack-bundle-analyzer@3.3.2](https://github.com/webpack-contrib/webpack-bundle-analyzer), License: MIT diff --git a/client/angular.json b/client/angular.json index 6ee2e9931..e67627591 100644 --- a/client/angular.json +++ b/client/angular.json @@ -4,15 +4,15 @@ "newProjectRoot": "projects", "projects": { "client": { - "root": "", - "sourceRoot": "src", "projectType": "application", - "prefix": "os", "schematics": { "@schematics/angular:component": { "styleext": "scss" } }, + "root": "", + "sourceRoot": "src", + "prefix": "os", "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", @@ -21,26 +21,17 @@ "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.app.json", - "assets": ["src/assets", "src/manifest.json"], + "tsConfig": "tsconfig.app.json", + "aot": false, + "assets": [ + "src/assets", + "src/manifest.json", + { "glob": "**/*", "input": "node_modules/tinymce/skins", "output": "/tinymce/skins/" }, + { "glob": "**/*", "input": "node_modules/tinymce/themes", "output": "/tinymce/themes/" }, + { "glob": "**/*", "input": "node_modules/tinymce/plugins", "output": "/tinymce/plugins/" } + ], "styles": ["src/styles.scss"], - "scripts": [ - "node_modules/tinymce/tinymce.min.js", - "node_modules/tinymce/themes/modern/theme.js", - "node_modules/tinymce/plugins/autolink/plugin.js", - "node_modules/tinymce/plugins/charmap/plugin.js", - "node_modules/tinymce/plugins/code/plugin.js", - "node_modules/tinymce/plugins/colorpicker/plugin.js", - "node_modules/tinymce/plugins/fullscreen/plugin.js", - "node_modules/tinymce/plugins/image/plugin.js", - "node_modules/tinymce/plugins/imagetools/plugin.js", - "node_modules/tinymce/plugins/lists/plugin.js", - "node_modules/tinymce/plugins/link/plugin.js", - "node_modules/tinymce/plugins/paste/plugin.js", - "node_modules/tinymce/plugins/preview/plugin.js", - "node_modules/tinymce/plugins/searchreplace/plugin.js", - "node_modules/tinymce/plugins/textcolor/plugin.js" - ] + "scripts": ["node_modules/tinymce/tinymce.min.js"] }, "configurations": { "production": { @@ -59,7 +50,14 @@ "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, - "serviceWorker": true + "serviceWorker": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] } } }, @@ -85,27 +83,27 @@ "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.spec.json", - "karmaConfig": "src/karma.conf.js", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", "styles": ["src/styles.scss"], "scripts": ["node_modules/tinymce/tinymce.min.js"], - "assets": ["src/assets", "src/manifest.json"] + "assets": [ + "src/assets", + "src/manifest.json", + { "glob": "**/*", "input": "node_modules/tinymce/skins", "output": "/tinymce/skins/" }, + { "glob": "**/*", "input": "node_modules/tinymce/themes", "output": "/tinymce/themes/" }, + { "glob": "**/*", "input": "node_modules/tinymce/plugins", "output": "/tinymce/plugins/" } + ] } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { - "tsConfig": "src/tsconfig.spec.json", + "tsConfig": "tsconfig.spec.json", "format": "stylish", "exclude": ["**/node_modules/**"] } - } - } - }, - "client-e2e": { - "root": "e2e/", - "projectType": "application", - "architect": { + }, "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { @@ -117,13 +115,6 @@ "devServerTarget": "client:serve:production" } } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": "e2e/tsconfig.e2e.json", - "exclude": ["**/node_modules/**"] - } } } } diff --git a/client/src/browserslist b/client/browserslist similarity index 97% rename from client/src/browserslist rename to client/browserslist index 8e09ab492..3c10d97ef 100644 --- a/client/src/browserslist +++ b/client/browserslist @@ -6,4 +6,4 @@ last 2 versions Firefox ESR not dead -# IE 9-11 \ No newline at end of file +IE 9-11 diff --git a/client/src/karma.conf.js b/client/karma.conf.js similarity index 100% rename from client/src/karma.conf.js rename to client/karma.conf.js diff --git a/client/package.json b/client/package.json index 6e108496c..1a8f5e7ff 100644 --- a/client/package.json +++ b/client/package.json @@ -25,60 +25,60 @@ "prettify-write": "prettier --config ./.prettierrc --write \"src/{app,environments}/**/*{.ts,.js,.json,.css,.scss}\"" }, "dependencies": { - "@angular/animations": "^7.2.14", - "@angular/cdk": "^7.3.7", - "@angular/cdk-experimental": "^7.3.7", - "@angular/common": "^7.2.14", - "@angular/compiler": "^7.2.14", - "@angular/core": "^7.2.14", - "@angular/forms": "^7.2.14", - "@angular/http": "^7.2.14", - "@angular/material": "^7.3.7", - "@angular/platform-browser": "^7.2.14", - "@angular/platform-browser-dynamic": "^7.2.14", - "@angular/pwa": "^0.13.8", - "@angular/router": "^7.2.14", - "@angular/service-worker": "^7.2.14", - "@ngx-pwa/local-storage": "^7.4.1", + "@angular/animations": "^8.0.3", + "@angular/cdk": "^8.0.1", + "@angular/cdk-experimental": "^8.0.1", + "@angular/common": "^8.0.3", + "@angular/compiler": "^8.0.3", + "@angular/core": "^8.0.3", + "@angular/forms": "^8.0.3", + "@angular/material": "^8.0.1", + "@angular/platform-browser": "^8.0.3", + "@angular/platform-browser-dynamic": "^8.0.3", + "@angular/pwa": "^0.800.6", + "@angular/router": "^8.0.3", + "@angular/service-worker": "^8.0.3", + "@ngx-pwa/local-storage": "^8.0.2", "@ngx-translate/core": "^11.0.1", "@ngx-translate/http-loader": "^4.0.0", - "@pebula/ngrid": "1.0.0-alpha.20", - "@pebula/ngrid-material": "1.0.0-alpha.20", - "@pebula/utils": "1.0.0-alpha.3", - "@tinymce/tinymce-angular": "^3.0.0", + "@pebula/ngrid": "^1.0.0-alpha.26", + "@pebula/ngrid-material": "^1.0.0-alpha.26", + "@pebula/utils": "^1.0.0-alpha.3", + "@tinymce/tinymce-angular": "^3.2.0", + "acorn": "^6.1.1", "core-js": "^3.0.1", "css-element-queries": "^1.1.1", - "exceljs": "1.9.1", + "exceljs": "1.13.0", "file-saver": "^2.0.1", "hammerjs": "^2.0.8", "lz4js": "^0.2.0", "material-icon-font": "git+https://github.com/petergng/materialIconFont.git", - "ng-pick-datetime": "^7.0.0", "ng2-pdf-viewer": "^5.2.3", - "ngx-file-drop": "^6.0.0", + "ngx-file-drop": "^8.0.3", "ngx-mat-select-search": "^1.7.2", "ngx-papaparse": "^3.0.2", "pdfmake": "^0.1.53", "po2json": "^1.0.0-alpha", - "rxjs": "^6.5.1", + "rxjs": "^6.5.2", "text-encoding": "^0.7.0", - "tinymce": "^4.9.2", + "tinymce": "^5.0.9", + "tslib": "^1.9.0", "uuid": "^3.3.2", - "zone.js": "~0.8.26" + "zone.js": "~0.9.1" }, "devDependencies": { - "@angular-devkit/build-angular": "^0.13.8", - "@angular/cli": "^7.3.8", - "@angular/compiler-cli": "^7.2.14", - "@angular/language-service": "^7.2.14", + "@angular-devkit/build-angular": "~0.800.6", + "@angular/cli": "^8.0.6", + "@angular/compiler-cli": "^8.0.3", + "@angular/language-service": "^8.0.3", "@biesbjerg/ngx-translate-extract": "^2.3.4", "@compodoc/compodoc": "^1.1.8", "@types/jasmine": "^3.3.9", "@types/jasminewd2": "^2.0.6", - "@types/node": "^11.13.7", + "@types/node": "~8.9.4", "@types/yargs": "^13.0.0", - "codelyzer": "~5.0.0", - "husky": "^1.3.1", + "codelyzer": "^5.0.1", + "husky": "^2.7.0", "jasmine-core": "~3.4.0", "jasmine-spec-reporter": "~4.2.1", "karma": "^4.1.0", @@ -91,11 +91,11 @@ "prettier": "^1.18.0", "protractor": "^5.4.2", "resize-observer-polyfill": "^1.5.1", - "source-map-explorer": "^1.7.0", - "ts-node": "~8.1.0", - "tslint": "~5.16.0", - "tsutils": "3.10.0", - "typescript": "~3.2.0", + "source-map-explorer": "^2.0.1", + "ts-node": "~7.0.0", + "tslint": "~5.15.0", + "tsutils": "3.14.0", + "typescript": "~3.4.3", "webpack-bundle-analyzer": "^3.3.2" } } diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index ab555c939..86f493725 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts @@ -25,10 +25,11 @@ const routes: Routes = [ }, { path: 'projector', - loadChildren: './fullscreen-projector/fullscreen-projector.module#FullscreenProjectorModule', + loadChildren: () => + import('./fullscreen-projector/fullscreen-projector.module').then(m => m.FullscreenProjectorModule), data: { noInterruption: true } }, - { path: '', loadChildren: './site/site.module#SiteModule' }, + { path: '', loadChildren: () => import('./site/site.module').then(m => m.SiteModule) }, { path: '**', redirectTo: '' } ]; diff --git a/client/src/app/base.component.ts b/client/src/app/base.component.ts index 6288dbda5..814c69d35 100644 --- a/client/src/app/base.component.ts +++ b/client/src/app/base.component.ts @@ -31,9 +31,11 @@ export abstract class BaseComponent { * Settings for the TinyMCE editor selector */ public tinyMceSettings = { + base_url: '/tinymce', // Root for resources + suffix: '.min', // Suffix to use when loading resources + theme: 'silver', language: null, language_url: null, - skin_url: '/assets/tinymce/skins/lightgray', inline: false, statusbar: false, browser_spellcheck: true, @@ -41,13 +43,17 @@ export abstract class BaseComponent { image_description: false, link_title: false, height: 320, - // TODO: image_list: images, - plugins: `autolink charmap code colorpicker fullscreen image imagetools - lists link paste searchreplace textcolor`, - menubar: '', + plugins: `autolink charmap code fullscreen image imagetools + lists link paste searchreplace`, + menubar: false, + contextmenu: false, toolbar: `styleselect | bold italic underline strikethrough | forecolor backcolor removeformat | bullist numlist | - link image charmap | code fullscreen` + link image charmap | code fullscreen`, + mobile: { + theme: 'mobile', + plugins: ['autosave', 'lists', 'autolink'] + } }; public constructor(protected titleService: Title, protected translate: TranslateService) { diff --git a/client/src/app/core/core-services/autoupdate.service.ts b/client/src/app/core/core-services/autoupdate.service.ts index 12784f2d5..2947ffaa4 100644 --- a/client/src/app/core/core-services/autoupdate.service.ts +++ b/client/src/app/core/core-services/autoupdate.service.ts @@ -2,9 +2,8 @@ import { Injectable } from '@angular/core'; import { WebsocketService, WEBSOCKET_ERROR_CODES } from './websocket.service'; import { CollectionStringMapperService } from './collection-string-mapper.service'; -import { DataStoreService } from './data-store.service'; +import { DataStoreService, DataStoreUpdateManagerService } from './data-store.service'; import { BaseModel } from '../../shared/models/base/base-model'; -import { DataStoreUpdateManagerService } from './data-store-update-manager.service'; interface AutoupdateFormat { /** diff --git a/client/src/app/core/core-services/data-store-update-manager.service.spec.ts b/client/src/app/core/core-services/data-store-update-manager.service.spec.ts deleted file mode 100644 index 5af903aab..000000000 --- a/client/src/app/core/core-services/data-store-update-manager.service.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; - -import { E2EImportsModule } from '../../../e2e-imports.module'; -import { DataStoreUpdateManagerService } from './data-store-update-manager.service'; - -describe('DataStoreUpdateManagerService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [E2EImportsModule], - providers: [DataStoreUpdateManagerService] - }); - }); - - it('should be created', inject([DataStoreUpdateManagerService], (service: DataStoreUpdateManagerService) => { - expect(service).toBeTruthy(); - })); -}); diff --git a/client/src/app/core/core-services/data-store-update-manager.service.ts b/client/src/app/core/core-services/data-store-update-manager.service.ts deleted file mode 100644 index f1f2d394e..000000000 --- a/client/src/app/core/core-services/data-store-update-manager.service.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Deferred } from '../deferred'; -import { DataStoreService } from './data-store.service'; -import { CollectionStringMapperService } from './collection-string-mapper.service'; - -export interface CollectionIds { - [collection: string]: number[]; -} - -/** - * Helper class for collecting data during the update phase of the DataStore. - */ -export class UpdateSlot { - /** - * Count instnaces of this class to easily compare them. - */ - private static ID_COUTNER = 1; - - /** - * Mapping of changed model ids to their collection. - */ - private changedModels: CollectionIds = {}; - - /** - * Mapping of deleted models to their collection. - */ - private deletedModels: CollectionIds = {}; - - /** - * The object's id. - */ - private _id: number; - - /** - * @param DS Carries the DataStore: TODO (see below `DataStoreUpdateManagerService.getNewUpdateSlot`) - */ - public constructor(public readonly DS: DataStoreService) { - this._id = UpdateSlot.ID_COUTNER++; - } - - /** - * Adds changed model information - * - * @param collection The collection - * @param id The id - */ - public addChangedModel(collection: string, id: number): void { - if (!this.changedModels[collection]) { - this.changedModels[collection] = []; - } - this.changedModels[collection].push(id); - } - - /** - * Adds deleted model information - * - * @param collection The collection - * @param id The id - */ - public addDeletedModel(collection: string, id: number): void { - if (!this.deletedModels[collection]) { - this.deletedModels[collection] = []; - } - this.deletedModels[collection].push(id); - } - - /** - * @param collection The collection - * @returns the list of changed model ids for the collection - */ - public getChangedModelIdsForCollection(collection: string): number[] { - return this.changedModels[collection] || []; - } - - /** - * @returns the mapping of all changed models - */ - public getChangedModels(): CollectionIds { - return this.changedModels; - } - - /** - * @param collection The collection - * @returns the list of deleted model ids for the collection - */ - public getDeletedModelIdsForCollection(collection: string): number[] { - return this.deletedModels[collection] || []; - } - - /** - * Compares this object to another update slot. - */ - public equal(other: UpdateSlot): boolean { - return this._id === other._id; - } -} - -/** - * Manages updates in the DS. Collects all ids for changed and deleted models and bulk-update - * affected repositories. - */ -@Injectable({ - providedIn: 'root' -}) -export class DataStoreUpdateManagerService { - /** - * The current update slot - */ - private currentUpdateSlot: UpdateSlot | null = null; - - /** - * Requests for getting an update slot. - */ - private updateSlotRequests: Deferred[] = []; - - /** - * @param mapperService - */ - public constructor(private mapperService: CollectionStringMapperService) {} - - /** - * Retrieve the current update slot. - */ - public getCurrentUpdateSlot(): UpdateSlot | null { - return this.currentUpdateSlot; - } - - /** - * Get a new update slot. Returns a promise that must be awaited, if there is another - * update in progress. - * - * @param DS The DataStore. This is a hack, becuase we cannot use the DataStore - * here, because these are cyclic dependencies... --> TODO - */ - public async getNewUpdateSlot(DS: DataStoreService): Promise { - if (this.currentUpdateSlot) { - const request = new Deferred(); - this.updateSlotRequests.push(request); - await request; - } - this.currentUpdateSlot = new UpdateSlot(DS); - return this.currentUpdateSlot; - } - - /** - * Commits the given update slot. THis slot must be the current one. If there are requests - * for update slots queued, the next one will be served. - * - * Note: I added this param to make sure, that only the user of the slot - * can commit the update and no one else. - * - * @param slot The slot to commit - */ - public commit(slot: UpdateSlot): void { - if (!this.currentUpdateSlot || !this.currentUpdateSlot.equal(slot)) { - throw new Error('No or wrong update slot to be finished!'); - } - this.currentUpdateSlot = null; - - // notify repositories in two phases - const repositories = this.mapperService.getAllRepositories(); - - // Phase 1: deleting and creating of view models (in this order) - repositories.forEach(repo => { - repo.deleteModels(slot.getDeletedModelIdsForCollection(repo.collectionString)); - repo.changedModels(slot.getChangedModelIdsForCollection(repo.collectionString)); - }); - - // Phase 2: updating dependencies - repositories.forEach(repo => { - repo.updateDependencies(slot.getChangedModels()); - }); - - slot.DS.triggerModifiedObservable(); - - // serve next slot request - if (this.updateSlotRequests.length > 0) { - const request = this.updateSlotRequests.pop(); - request.resolve(); - } - } -} diff --git a/client/src/app/core/core-services/data-store.service.ts b/client/src/app/core/core-services/data-store.service.ts index d5ecf235f..b36f09b6f 100644 --- a/client/src/app/core/core-services/data-store.service.ts +++ b/client/src/app/core/core-services/data-store.service.ts @@ -1,11 +1,10 @@ import { Injectable, EventEmitter } from '@angular/core'; - import { Observable, Subject } from 'rxjs'; import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model'; -import { StorageService } from './storage.service'; import { CollectionStringMapperService } from './collection-string-mapper.service'; -import { DataStoreUpdateManagerService } from './data-store-update-manager.service'; +import { Deferred } from '../deferred'; +import { StorageService } from './storage.service'; /** * Represents information about a deleted model. @@ -17,6 +16,98 @@ export interface DeletedInformation { id: number; } +export interface CollectionIds { + [collection: string]: number[]; +} + +/** + * Helper class for collecting data during the update phase of the DataStore. + */ +export class UpdateSlot { + /** + * Count instnaces of this class to easily compare them. + */ + private static ID_COUTNER = 1; + + /** + * Mapping of changed model ids to their collection. + */ + private changedModels: CollectionIds = {}; + + /** + * Mapping of deleted models to their collection. + */ + private deletedModels: CollectionIds = {}; + + /** + * The object's id. + */ + private _id: number; + + /** + * @param DS Carries the DataStore: TODO (see below `DataStoreUpdateManagerService.getNewUpdateSlot`) + */ + public constructor(public readonly DS: DataStoreService) { + this._id = UpdateSlot.ID_COUTNER++; + } + + /** + * Adds changed model information + * + * @param collection The collection + * @param id The id + */ + public addChangedModel(collection: string, id: number): void { + if (!this.changedModels[collection]) { + this.changedModels[collection] = []; + } + this.changedModels[collection].push(id); + } + + /** + * Adds deleted model information + * + * @param collection The collection + * @param id The id + */ + public addDeletedModel(collection: string, id: number): void { + if (!this.deletedModels[collection]) { + this.deletedModels[collection] = []; + } + this.deletedModels[collection].push(id); + } + + /** + * @param collection The collection + * @returns the list of changed model ids for the collection + */ + public getChangedModelIdsForCollection(collection: string): number[] { + return this.changedModels[collection] || []; + } + + /** + * @returns the mapping of all changed models + */ + public getChangedModels(): CollectionIds { + return this.changedModels; + } + + /** + * @param collection The collection + * @returns the list of deleted model ids for the collection + */ + public getDeletedModelIdsForCollection(collection: string): number[] { + return this.deletedModels[collection] || []; + } + + /** + * Compares this object to another update slot. + */ + public equal(other: UpdateSlot): boolean { + return this._id === other._id; + } +} + /** * represents a collection on the Django server, uses an ID to access a {@link BaseModel}. * @@ -49,6 +140,91 @@ interface JsonStorage { [collectionString: string]: JsonCollection; } +/** + * TODO: Avoid circular dependencies between `DataStoreUpdateManagerService` and `DataStoreService` and split them into two files + */ +@Injectable({ + providedIn: 'root' +}) +export class DataStoreUpdateManagerService { + /** + * The current update slot + */ + private currentUpdateSlot: UpdateSlot | null = null; + + /** + * Requests for getting an update slot. + */ + private updateSlotRequests: Deferred[] = []; + + /** + * @param mapperService + */ + public constructor(private mapperService: CollectionStringMapperService) {} + + /** + * Retrieve the current update slot. + */ + public getCurrentUpdateSlot(): UpdateSlot | null { + return this.currentUpdateSlot; + } + + /** + * Get a new update slot. Returns a promise that must be awaited, if there is another + * update in progress. + * + * @param DS The DataStore. This is a hack, becuase we cannot use the DataStore + * here, because these are cyclic dependencies... --> TODO + */ + public async getNewUpdateSlot(DS: DataStoreService): Promise { + if (this.currentUpdateSlot) { + const request = new Deferred(); + this.updateSlotRequests.push(request); + await request; + } + this.currentUpdateSlot = new UpdateSlot(DS); + return this.currentUpdateSlot; + } + + /** + * Commits the given update slot. THis slot must be the current one. If there are requests + * for update slots queued, the next one will be served. + * + * Note: I added this param to make sure, that only the user of the slot + * can commit the update and no one else. + * + * @param slot The slot to commit + */ + public commit(slot: UpdateSlot): void { + if (!this.currentUpdateSlot || !this.currentUpdateSlot.equal(slot)) { + throw new Error('No or wrong update slot to be finished!'); + } + this.currentUpdateSlot = null; + + // notify repositories in two phases + const repositories = this.mapperService.getAllRepositories(); + + // Phase 1: deleting and creating of view models (in this order) + repositories.forEach(repo => { + repo.deleteModels(slot.getDeletedModelIdsForCollection(repo.collectionString)); + repo.changedModels(slot.getChangedModelIdsForCollection(repo.collectionString)); + }); + + // Phase 2: updating dependencies + repositories.forEach(repo => { + repo.updateDependencies(slot.getChangedModels()); + }); + + slot.DS.triggerModifiedObservable(); + + // serve next slot request + if (this.updateSlotRequests.length > 0) { + const request = this.updateSlotRequests.pop(); + request.resolve(); + } + } +} + /** * All mighty DataStore that comes with all OpenSlides components. * Use this.DS in an OpenSlides Component to Access the store. diff --git a/client/src/app/core/core-services/storage.service.ts b/client/src/app/core/core-services/storage.service.ts index bba7830c9..54c7815ea 100644 --- a/client/src/app/core/core-services/storage.service.ts +++ b/client/src/app/core/core-services/storage.service.ts @@ -4,7 +4,6 @@ import { LocalStorage } from '@ngx-pwa/local-storage'; import { Observable } from 'rxjs'; import { OpenSlidesStatusService } from './openslides-status.service'; -import { StoragelockService } from '../local-storage/storagelock.service'; /** * Provides an async API to an key-value store using ngx-pwa which is internally @@ -18,11 +17,7 @@ export class StorageService { * Constructor to create the StorageService. Needs the localStorage service. * @param localStorage */ - public constructor( - private localStorage: LocalStorage, - private OSStatus: OpenSlidesStatusService, - private lock: StoragelockService - ) {} + public constructor(private localStorage: LocalStorage, private OSStatus: OpenSlidesStatusService) {} /** * Sets the item into the store asynchronously. @@ -30,8 +25,6 @@ export class StorageService { * @param item */ public async set(key: string, item: any): Promise { - await this.lock.promise; - this.assertNotHistoryMode(); if (item === null || item === undefined) { await this.remove(key); // You cannot do a setItem with null or undefined... @@ -49,8 +42,6 @@ export class StorageService { * @returns The requested value to the key */ public async get(key: string): Promise { - await this.lock.promise; - return ((await this.localStorage.getItem(key)) as Observable).toPromise(); } @@ -59,8 +50,6 @@ export class StorageService { * @param key The key to remove the value from */ public async remove(key: string): Promise { - await this.lock.promise; - this.assertNotHistoryMode(); if (!(await this.localStorage.removeItem(key).toPromise())) { throw new Error('Could not delete the item.'); @@ -71,8 +60,6 @@ export class StorageService { * Clear the whole cache */ public async clear(): Promise { - await this.lock.promise; - this.assertNotHistoryMode(); if (!(await this.localStorage.clear().toPromise())) { throw new Error('Could not clear the storage.'); diff --git a/client/src/app/core/core-services/time-travel.service.ts b/client/src/app/core/core-services/time-travel.service.ts index 06d16acdd..08c96133c 100644 --- a/client/src/app/core/core-services/time-travel.service.ts +++ b/client/src/app/core/core-services/time-travel.service.ts @@ -3,13 +3,12 @@ import { Injectable } from '@angular/core'; import { environment } from 'environments/environment'; import { CollectionStringMapperService } from './collection-string-mapper.service'; import { History } from 'app/shared/models/core/history'; -import { DataStoreService } from './data-store.service'; +import { DataStoreService, DataStoreUpdateManagerService } from './data-store.service'; import { WebsocketService } from './websocket.service'; import { BaseModel } from 'app/shared/models/base/base-model'; import { OpenSlidesStatusService } from './openslides-status.service'; import { OpenSlidesService } from './openslides.service'; import { HttpService } from './http.service'; -import { DataStoreUpdateManagerService } from './data-store-update-manager.service'; /** * Interface for full history data objects. diff --git a/client/src/app/core/core-services/websocket.service.ts b/client/src/app/core/core-services/websocket.service.ts index def28c1f6..0cbf1ade3 100644 --- a/client/src/app/core/core-services/websocket.service.ts +++ b/client/src/app/core/core-services/websocket.service.ts @@ -1,5 +1,5 @@ import { Injectable, NgZone, EventEmitter } from '@angular/core'; -import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from '@angular/material'; +import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from '@angular/material/snack-bar'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index f7ae34fba..031a4140a 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -1,9 +1,7 @@ -import { NgModule, Optional, SkipSelf, Type, PLATFORM_ID } from '@angular/core'; +import { NgModule, Optional, SkipSelf, Type } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Title } from '@angular/platform-browser'; -import { LocalDatabase, LOCAL_STORAGE_PREFIX } from '@ngx-pwa/local-storage'; - // Shared Components import { PromptDialogComponent } from '../shared/components/prompt-dialog/prompt-dialog.component'; import { ChoiceDialogComponent } from '../shared/components/choice-dialog/choice-dialog.component'; @@ -11,8 +9,6 @@ import { ProjectionDialogComponent } from 'app/shared/components/projection-dial import { OperatorService } from './core-services/operator.service'; import { OnAfterAppsLoaded } from './onAfterAppsLoaded'; -import { StoragelockService } from './local-storage/storagelock.service'; -import { customLocalDatabaseFactory } from './local-storage/custom-indexeddb-database'; export const ServicesToLoadOnAppsLoaded: Type[] = [OperatorService]; @@ -21,15 +17,7 @@ export const ServicesToLoadOnAppsLoaded: Type[] = [OperatorSe */ @NgModule({ imports: [CommonModule], - providers: [ - Title, - // Use our own localStorage wrapper. - { - provide: LocalDatabase, - useFactory: customLocalDatabaseFactory, - deps: [PLATFORM_ID, StoragelockService, [new Optional(), LOCAL_STORAGE_PREFIX]] - } - ], + providers: [Title], entryComponents: [PromptDialogComponent, ChoiceDialogComponent, ProjectionDialogComponent] }) export class CoreModule { diff --git a/client/src/app/core/local-storage/custom-indexeddb-database.ts b/client/src/app/core/local-storage/custom-indexeddb-database.ts deleted file mode 100644 index 9be5c5fbc..000000000 --- a/client/src/app/core/local-storage/custom-indexeddb-database.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Optional, Inject, Injectable } from '@angular/core'; -import { isPlatformBrowser } from '@angular/common'; - -import { - IndexedDBDatabase, - LOCAL_STORAGE_PREFIX, - LocalStorageDatabase, - MockLocalDatabase, - LocalDatabase -} from '@ngx-pwa/local-storage'; -import { fromEvent, race, Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; - -import { StoragelockService } from './storagelock.service'; - -@Injectable({ - providedIn: 'root' -}) -export class CustomIndexedDBDatabase extends IndexedDBDatabase { - public constructor( - private storageLock: StoragelockService, - @Optional() @Inject(LOCAL_STORAGE_PREFIX) protected prefix: string | null = null - ) { - super(prefix); - } - - /** - * Connects to IndexedDB and creates the object store on first time - */ - protected connect(prefix: string | null = null): void { - let request: IDBOpenDBRequest; - - // Connecting to IndexedDB - try { - request = indexedDB.open(this.dbName); - } catch (error) { - // Fallback storage if IndexedDb connection is failing - this.setFallback(prefix); - return; - } - - // Listening the event fired on first connection, creating the object store for local storage - (fromEvent(request, 'upgradeneeded') as Observable).pipe(first()).subscribe(event => { - // Getting the database connection - const database = (event.target as IDBRequest).result as IDBDatabase; - - // Checking if the object store already exists, to avoid error - if (!database.objectStoreNames.contains(this.objectStoreName)) { - // Creating the object store for local storage - database.createObjectStore(this.objectStoreName); - } - }); - - // Listening the success event and converting to an RxJS Observable - const success = fromEvent(request, 'success') as Observable; - - // Merging success and errors events - (race(success, this.toErrorObservable(request, `connection`)) as Observable).pipe(first()).subscribe( - event => { - const db = (event.target as IDBRequest).result as IDBDatabase; - - // CUSTOM: If the indexedDB initialization fails, because 'upgradeneeded' didn't fired - // the fallback will be used. - if (!db.objectStoreNames.contains(this.objectStoreName)) { - this.setFallback(prefix); - } else { - // Storing the database connection for further access - this.database.next(db); - this.storageLock.OK(true); - } - }, - () => { - // Fallback storage if IndexedDb connection is failing - this.setFallback(prefix); - } - ); - } - - // CUSTOM: If the fallback is used, unlock the storage service - public setFallback(prefix: string): void { - console.log('uses localStorage as IndexedDB fallback!'); - super.setFallback(prefix); - this.storageLock.OK(false); - } -} - -export function customLocalDatabaseFactory( - platformId: Object, - storagelock: StoragelockService, - prefix: string | null -): LocalDatabase { - if (isPlatformBrowser(platformId) && 'indexedDB' in window && indexedDB !== undefined && indexedDB !== null) { - // Try with IndexedDB in modern browsers - // CUSTOM: Use our own IndexedDB implementation - return new CustomIndexedDBDatabase(storagelock, prefix); - } else if ( - isPlatformBrowser(platformId) && - 'localStorage' in window && - localStorage !== undefined && - localStorage !== null - ) { - // Try with localStorage in old browsers (IE9) - return new LocalStorageDatabase(prefix); - } else { - // Fake database for server-side rendering (Universal) - return new MockLocalDatabase(); - } -} diff --git a/client/src/app/core/local-storage/storagelock.service.ts b/client/src/app/core/local-storage/storagelock.service.ts deleted file mode 100644 index 6218367d8..000000000 --- a/client/src/app/core/local-storage/storagelock.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from '@angular/core'; - -/** - * Provides a storage lock for waiting to database to be initialized. - */ -@Injectable({ - providedIn: 'root' -}) -export class StoragelockService { - private lock: Promise; - private resolve: () => void; - private _indexedDBUsed = false; - - public get promise(): Promise { - return this.lock; - } - - public get indexedDBUsed(): boolean { - return this._indexedDBUsed; - } - - public constructor() { - this.lock = new Promise(resolve => (this.resolve = resolve)); - } - - public OK(indexedDBUsed: boolean): void { - this._indexedDBUsed = indexedDBUsed; - this.resolve(); - } -} diff --git a/client/src/app/core/repositories/base-repository.ts b/client/src/app/core/repositories/base-repository.ts index 833573056..09c4ecbf6 100644 --- a/client/src/app/core/repositories/base-repository.ts +++ b/client/src/app/core/repositories/base-repository.ts @@ -6,12 +6,11 @@ import { BaseViewModel, TitleInformation } from '../../site/base/base-view-model import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model'; import { CollectionStringMapperService } from '../core-services/collection-string-mapper.service'; import { DataSendService } from '../core-services/data-send.service'; -import { DataStoreService } from '../core-services/data-store.service'; +import { DataStoreService, CollectionIds } from '../core-services/data-store.service'; import { Identifiable } from '../../shared/models/base/identifiable'; import { ViewModelStoreService } from '../core-services/view-model-store.service'; import { OnAfterAppsLoaded } from '../onAfterAppsLoaded'; import { Collection } from 'app/shared/models/base/collection'; -import { CollectionIds } from '../core-services/data-store-update-manager.service'; export abstract class BaseRepository implements OnAfterAppsLoaded, Collection { diff --git a/client/src/app/core/repositories/motions/motion-repository.service.ts b/client/src/app/core/repositories/motions/motion-repository.service.ts index 97f822bd1..67ddbd335 100644 --- a/client/src/app/core/repositories/motions/motion-repository.service.ts +++ b/client/src/app/core/repositories/motions/motion-repository.service.ts @@ -10,7 +10,7 @@ import { ChangeRecoMode, ViewMotion, MotionTitleInformation } from 'app/site/mot import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { ConfigService } from 'app/core/ui-services/config.service'; import { DataSendService } from '../../core-services/data-send.service'; -import { DataStoreService } from '../../core-services/data-store.service'; +import { DataStoreService, CollectionIds } from '../../core-services/data-store.service'; import { DiffLinesInParagraph, DiffService, LineRange, ModificationType } from '../../ui-services/diff.service'; import { HttpService } from 'app/core/core-services/http.service'; import { LinenumberingService, LineNumberRange } from '../../ui-services/linenumbering.service'; @@ -38,7 +38,6 @@ import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile'; import { ViewTag } from 'app/site/tags/models/view-tag'; import { ViewPersonalNote } from 'app/site/users/models/view-personal-note'; import { OperatorService } from 'app/core/core-services/operator.service'; -import { CollectionIds } from 'app/core/core-services/data-store-update-manager.service'; import { PersonalNote, PersonalNoteContent } from 'app/shared/models/users/personal-note'; import { ViewListOfSpeakers } from 'app/site/agenda/models/view-list-of-speakers'; import { BaseIsAgendaItemAndListOfSpeakersContentObjectRepository } from '../base-is-agenda-item-and-list-of-speakers-content-object-repository'; diff --git a/client/src/app/core/ui-services/base-import.service.ts b/client/src/app/core/ui-services/base-import.service.ts index 5ede5079e..271056e29 100644 --- a/client/src/app/core/ui-services/base-import.service.ts +++ b/client/src/app/core/ui-services/base-import.service.ts @@ -1,6 +1,6 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { Injectable, EventEmitter } from '@angular/core'; -import { MatSnackBar } from '@angular/material'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { Papa, PapaParseConfig } from 'ngx-papaparse'; import { TranslateService } from '@ngx-translate/core'; diff --git a/client/src/app/core/ui-services/choice.service.ts b/client/src/app/core/ui-services/choice.service.ts index f522061e3..ecaaa8c9d 100644 --- a/client/src/app/core/ui-services/choice.service.ts +++ b/client/src/app/core/ui-services/choice.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import { ChoiceDialogComponent, diff --git a/client/src/app/core/ui-services/count-users.service.ts b/client/src/app/core/ui-services/count-users.service.ts index d983e8af3..dede276d8 100644 --- a/client/src/app/core/ui-services/count-users.service.ts +++ b/client/src/app/core/ui-services/count-users.service.ts @@ -4,7 +4,6 @@ import { Observable, Subject } from 'rxjs'; import { NotifyService } from '../core-services/notify.service'; import { OperatorService } from '../core-services/operator.service'; -import { StoragelockService } from '../local-storage/storagelock.service'; interface CountUserRequest { token: string; @@ -41,11 +40,7 @@ export class CountUsersService { * @param notifyService * @param operator */ - public constructor( - private notifyService: NotifyService, - operator: OperatorService, - storageLockService: StoragelockService - ) { + public constructor(private notifyService: NotifyService, operator: OperatorService) { // Listen for requests to send an answer. this.notifyService.getMessageObservable(REQUEST_NAME).subscribe(request => { if (request.content.token) { @@ -55,7 +50,7 @@ export class CountUsersService { token: request.content.token, data: { userId: this.currentUserId, - usesIndexedDB: storageLockService.indexedDBUsed + usesIndexedDB: true } }, request.senderChannelName diff --git a/client/src/app/core/ui-services/projection-dialog.service.ts b/client/src/app/core/ui-services/projection-dialog.service.ts index 8601e4235..0e4ac8822 100644 --- a/client/src/app/core/ui-services/projection-dialog.service.ts +++ b/client/src/app/core/ui-services/projection-dialog.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import { Projectable, ProjectorElementBuildDeskriptor, isProjectable } from 'app/site/base/projectable'; import { diff --git a/client/src/app/core/ui-services/prompt.service.ts b/client/src/app/core/ui-services/prompt.service.ts index 146fc992d..c81af7ff9 100644 --- a/client/src/app/core/ui-services/prompt.service.ts +++ b/client/src/app/core/ui-services/prompt.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { PromptDialogComponent } from '../../shared/components/prompt-dialog/prompt-dialog.component'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; /** * A general service for prompting 'yes' or 'cancel' thinks from the user. diff --git a/client/src/app/fullscreen-projector/fullscreen-projector/fullscreen-projector.component.ts b/client/src/app/fullscreen-projector/fullscreen-projector/fullscreen-projector.component.ts index a646382a2..b36603ff7 100644 --- a/client/src/app/fullscreen-projector/fullscreen-projector/fullscreen-projector.component.ts +++ b/client/src/app/fullscreen-projector/fullscreen-projector/fullscreen-projector.component.ts @@ -56,7 +56,7 @@ export class FullscreenProjectorComponent implements OnInit { /** * The container to get the window size. */ - @ViewChild('container') + @ViewChild('container', { static: true }) private containerElement: ElementRef; /** diff --git a/client/src/app/shared/components/block-tile/block-tile.component.ts b/client/src/app/shared/components/block-tile/block-tile.component.ts index 8a6f6f5c7..a8383f3e8 100644 --- a/client/src/app/shared/components/block-tile/block-tile.component.ts +++ b/client/src/app/shared/components/block-tile/block-tile.component.ts @@ -48,19 +48,19 @@ export class BlockTileComponent extends TileComponent { /** * Reference to the content of the content part. */ - @ContentChild(TemplateRef) + @ContentChild(TemplateRef, { static: true }) public contentNode: TemplateRef; /** * Reference to the block part, if it is a node. */ - @ContentChild(TemplateRef) + @ContentChild(TemplateRef, { static: true }) public blockNode: TemplateRef; /** * Reference to the action buttons in the content part, if used. */ - @ContentChild(TemplateRef) + @ContentChild(TemplateRef, { static: true }) public actionNode: TemplateRef; /** diff --git a/client/src/app/shared/components/choice-dialog/choice-dialog.component.ts b/client/src/app/shared/components/choice-dialog/choice-dialog.component.ts index 123a73256..b83c78fa7 100644 --- a/client/src/app/shared/components/choice-dialog/choice-dialog.component.ts +++ b/client/src/app/shared/components/choice-dialog/choice-dialog.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, ViewEncapsulation } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Displayable } from 'app/site/base/displayable'; import { Identifiable } from 'app/shared/models/base/identifiable'; diff --git a/client/src/app/shared/components/copyright-sign/copyright-sign.component.ts b/client/src/app/shared/components/copyright-sign/copyright-sign.component.ts index cbe7b3b26..4d50dbb4d 100644 --- a/client/src/app/shared/components/copyright-sign/copyright-sign.component.ts +++ b/client/src/app/shared/components/copyright-sign/copyright-sign.component.ts @@ -3,7 +3,7 @@ */ import { Component, OnInit, OnDestroy } from '@angular/core'; -import { MatDialogRef, MatDialog } from '@angular/material'; +import { MatDialogRef, MatDialog } from '@angular/material/dialog'; import { OperatorService } from 'app/core/core-services/operator.service'; import { NotifyService, NotifyResponse } from 'app/core/core-services/notify.service'; import { Subscription } from 'rxjs'; diff --git a/client/src/app/shared/components/list-view-table/list-view-table.component.ts b/client/src/app/shared/components/list-view-table/list-view-table.component.ts index f096b8355..3a0f8eac9 100644 --- a/client/src/app/shared/components/list-view-table/list-view-table.component.ts +++ b/client/src/app/shared/components/list-view-table/list-view-table.component.ts @@ -83,7 +83,7 @@ export class ListViewTableComponent