From 9951a58eabd94c72d0f54b8bf52790f0054bf017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20GREFFIER?= Date: Mon, 15 Jan 2024 22:21:40 +0100 Subject: [PATCH] Upgrade to Angular 17 (#60) * Upgrade to Java 21 and Spring Boot 3 * Update doc * angular 12 * material 12 * angular 13 * material 13 * angular 14 * material 14 * angular 15 * material 15 * update ts * Move to ktd * Remove fx * Angular 16 * material 16 * core 17 * core 17 * Fix test * Fix display and build * Fix CI and update readme * Fix 403 --- .eslintrc.json | 51 +++++ .github/workflows/continuous_integration.yml | 12 +- .github/workflows/pull_request.yml | 8 +- .github/workflows/tag.yml | 4 +- .gitignore | 3 +- .huskyrc | 5 +- .prettierrc | 11 +- .readme/dashboard.png | Bin 0 -> 75921 bytes README.md | 6 +- angular.json | 135 ++++++++----- karma.conf.js | 41 ---- package.json | 92 ++++----- pom.xml | 7 +- .../tester/configuration/web/WebConfig.java | 6 +- .../dto/api/ProjectWidgetResponseDto.java | 1 + .../tester/services/api/WidgetService.java | 7 +- .../services/js/script/JsEndpoints.java | 2 +- .../widget/tester/utils/JavaScriptUtils.java | 2 +- src/main/webapp/.browserslistrc | 6 +- src/main/webapp/app/app.component.ts | 4 +- src/main/webapp/app/app.module.ts | 3 +- .../dashboard-screen-widget.component.html | 8 +- .../dashboard-screen-widget.component.scss | 2 + .../dashboard-screen-widget.component.spec.ts | 30 +-- .../dashboard-screen-widget.component.ts | 38 +--- .../dashboard-screen.component.html | 40 ++-- .../dashboard-screen.component.scss | 4 + .../dashboard-screen.component.ts | 105 ++++------ .../widget-configuration.component.html | 8 +- .../widget-configuration.component.scss | 2 +- .../widget-configuration.component.ts | 16 +- .../webapp/app/dashboard/dashboard.module.ts | 6 +- .../services/library/library.service.spec.ts | 2 +- .../dashboard/services/utils/file.utils.ts | 45 ----- src/main/webapp/app/mock/mock.module.ts | 10 +- .../mocked-model-builder.service.ts | 19 +- .../components/spinner/spinner.component.html | 2 +- .../components/spinner/spinner.component.scss | 5 +- .../spinner/spinner.component.spec.ts | 2 +- .../components/spinner/spinner.component.ts | 2 +- .../directives/widget-html.directive.spec.ts | 2 +- .../app/shared/models/grid/grid-options.ts | 10 + .../models/project-widget/project-widget.ts | 1 + .../app/shared/modules/material.module.ts | 33 ++++ .../http-library/http-library.service.spec.ts | 2 +- .../http-library/http-library.service.ts | 2 +- src/main/webapp/app/shared/shared.module.ts | 38 +--- .../app/shared/utils/grid-item.utils.ts | 12 +- src/main/webapp/assets/.gitkeep | 0 src/main/webapp/assets/images/logo.png | Bin 0 -> 11004 bytes .../webapp/assets/images/widget-tester.png | Bin 38838 -> 0 bytes src/main/webapp/environments/environment.ts | 9 - src/main/webapp/index.html | 3 + src/main/webapp/polyfills.ts | 47 +---- src/main/webapp/sass/_dashboard-themes.scss | 30 --- src/main/webapp/sass/_global-styles.scss | 12 +- src/main/webapp/sass/_variables.scss | 2 - .../material/_mat-button-theme.scss | 14 +- .../material/_mat-checkbox-theme.scss | 9 +- .../material/_mat-form-field-theme.scss | 4 +- .../material/_mat-grid-list-theme.scss | 4 +- .../components/material/_mat-icon-theme.scss | 6 +- .../material/_mat-sidenav-theme.scss | 10 +- .../material/_mat-slide-toggle-theme.scss | 9 +- .../material/_mat-stepper-theme.scss | 12 +- src/main/webapp/sass/styles.scss | 54 ++++-- .../webapp/sass/themes/_suricate-theme.scss | 18 +- .../light-theme/_dashboard-light-palette.scss | 183 +++++++++--------- .../light-theme/_dashboard-light-theme.scss | 32 --- src/main/webapp/test.ts | 23 --- src/main/webapp/tsconfig.app.json | 2 +- src/main/webapp/tsconfig.spec.json | 1 - .../js/services/JsExecutionServiceTest.java | 10 +- .../widget/tester/utils/WidgetUtilsTest.java | 2 +- tsconfig.json | 9 +- tslint.json | 59 ------ 76 files changed, 599 insertions(+), 817 deletions(-) create mode 100644 .eslintrc.json create mode 100644 .readme/dashboard.png delete mode 100644 karma.conf.js create mode 100644 src/main/webapp/app/shared/models/grid/grid-options.ts create mode 100644 src/main/webapp/app/shared/modules/material.module.ts delete mode 100644 src/main/webapp/assets/.gitkeep create mode 100644 src/main/webapp/assets/images/logo.png delete mode 100644 src/main/webapp/assets/images/widget-tester.png delete mode 100644 src/main/webapp/sass/_dashboard-themes.scss delete mode 100644 src/main/webapp/sass/_variables.scss delete mode 100644 src/main/webapp/sass/themes/light-theme/_dashboard-light-theme.scss delete mode 100644 src/main/webapp/test.ts delete mode 100644 tslint.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..c995d01 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,51 @@ +{ + "root": true, + "ignorePatterns": [], + "overrides": [ + { + "files": [ + "*.ts" + ], + "plugins": [ + "deprecation" + ], + "parserOptions": { + "project": [ + "tsconfig.json" + ], + "createDefaultProgram": true + }, + "extends": [ + "plugin:@angular-eslint/recommended", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/component-selector": [ + "error", + { + "prefix": "suricate", + "style": "kebab-case", + "type": "element" + } + ], + "@angular-eslint/directive-selector": [ + "error", + { + "style": "camelCase", + "type": "attribute" + } + ], + "deprecation/deprecation": "warn" + } + }, + { + "files": [ + "*.html" + ], + "extends": [ + "plugin:@angular-eslint/template/recommended" + ], + "rules": {} + } + ] +} diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml index 11bcd1f..188066b 100644 --- a/.github/workflows/continuous_integration.yml +++ b/.github/workflows/continuous_integration.yml @@ -52,18 +52,18 @@ jobs: with: fetch-depth: 0 - - name: Set up NodeJS 12.x + - name: Set up NodeJS 20.x uses: actions/setup-node@v4 with: - node-version: '12.x' + node-version: '20.x' - name: Build with NPM run: | npm install --no-progress - npm run build -- --prod + npm run build -- --configuration production - - name: Lint with NPM + - name: Lint run: npm run lint - - name: Test with NPM - run: npm run test-headless-no-sandbox -- --watch=false --progress=false --code-coverage + - name: Test + run: npm run test-ci diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 041e090..b40a4a6 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -52,18 +52,18 @@ jobs: with: fetch-depth: 0 - - name: Set up NodeJS 12.x + - name: Set up NodeJS 20.x uses: actions/setup-node@v4 with: - node-version: '12.x' + node-version: '20.x' - name: Build run: | npm install --no-progress - npm run build -- --prod + npm run build -- --configuration production - name: Lint run: npm run lint - name: Test - run: npm run test-headless-no-sandbox -- --watch=false --progress=false --code-coverage + run: npm run test-ci diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 072377a..9d6f44e 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -25,10 +25,10 @@ jobs: distribution: 'temurin' cache: maven - - name: Set up NodeJS 12.x + - name: Set up NodeJS 20.x uses: actions/setup-node@v4 with: - node-version: '12.x' + node-version: '20.x' - name: Import GPG key uses: crazy-max/ghaction-import-gpg@v6 diff --git a/.gitignore b/.gitignore index 1872b66..36a9cbe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -.idea +/.angular/cache +.idea target *.iml node_modules diff --git a/.huskyrc b/.huskyrc index 3fe21b4..03e1bd3 100644 --- a/.huskyrc +++ b/.huskyrc @@ -1,6 +1,5 @@ { "hooks": { - "pre-commit": "run-s prettyformat", - "pre-push": "run-s lint" + "pre-commit": "npx pretty-quick --staged" } -} +} \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index aef6746..af14bee 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,9 +1,12 @@ { + "arrowParens": "always", + "bracketSpacing": true, + "endOfLine": "auto", "printWidth": 140, + "quoteProps": "consistent", + "semi": true, "singleQuote": true, - "useTabs": false, "tabWidth": 2, - "semi": true, - "bracketSpacing": true, - "jsxBracketSameLine": true + "trailingComma": "none", + "useTabs": false } diff --git a/.readme/dashboard.png b/.readme/dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..1be890b74315993d21d61b25807644340d8112c8 GIT binary patch literal 75921 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 5f6c93e..4d63452 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Suricate Widget Tester +
+ suricate logo +
+ [![GitHub Build](https://img.shields.io/github/actions/workflow/status/michelin/suricate-widget-tester/continuous_integration.yml?branch=master&logo=github&style=for-the-badge)](https://img.shields.io/github/actions/workflow/status/michelin/suricate-widget-tester/continuous_integration.yml) [![GitHub release](https://img.shields.io/github/v/release/michelin/suricate-widget-tester?logo=github&style=for-the-badge)](https://github.com/michelin/suricate-widget-tester/releases) [![GitHub commits since latest release (by SemVer)](https://img.shields.io/github/commits-since/michelin/suricate-widget-tester/latest?logo=github&style=for-the-badge)](https://github.com/michelin/suricate-widget-tester/commits/master) @@ -11,7 +15,7 @@ This repository contains the source code of the Suricate Widget Tester application. -![Suricate widget tester](src/main/webapp/assets/images/widget-tester.png) +![Suricate widget tester](.readme/dashboard.png) ## Table of Contents diff --git a/angular.json b/angular.json index ae27d36..ea67b95 100644 --- a/angular.json +++ b/angular.json @@ -3,19 +3,10 @@ "version": 1, "newProjectRoot": "projects", "projects": { - "widget-tester-front": { + "widget-tester-frontend": { "projectType": "application", - "schematics": { - "@schematics/angular:component": { - "style": "scss" - }, - "@schematics/angular:application": { - "strict": true - } - }, "root": "src/main/webapp", "sourceRoot": "src/main/webapp", - "prefix": "app", "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", @@ -23,19 +14,34 @@ "outputPath": "target/dist/public", "index": "src/main/webapp/index.html", "main": "src/main/webapp/main.ts", - "polyfills": "src/main/webapp/polyfills.ts", "tsConfig": "src/main/webapp/tsconfig.app.json", - "aot": false, - "assets": ["src/main/webapp/assets"], + "polyfills": [ + "zone.js", + "src/main/webapp/polyfills.ts" + ], + "assets": [ + "src/main/webapp/assets" + ], "stylePreprocessorOptions": { "includePaths": [ "node_modules/normalize-scss/sass", - "node_modules/material-design-icons-iconfont/src", "node_modules/@fortawesome/fontawesome-free/scss" ] }, - "styles": ["src/main/webapp/sass/styles.scss"], - "scripts": ["node_modules/jquery/dist/jquery.min.js", "node_modules/moment/min/moment-with-locales.min.js"] + "styles": [ + "src/main/webapp/sass/styles.scss" + ], + "scripts": [ + "node_modules/jquery/dist/jquery.min.js", + "node_modules/moment/min/moment-with-locales.min.js" + ], + "optimization": false, + "sourceMap": true, + "namedChunks": false, + "aot": true, + "extractLicenses": false, + "vendorChunk": true, + "buildOptimizer": true }, "configurations": { "production": { @@ -45,80 +51,105 @@ "with": "src/main/webapp/environments/environment.prod.ts" } ], + "budgets": [ + { + "type": "initial", + "maximumWarning": "4mb", + "maximumError": "4mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb", + "maximumError": "8kb" + } + ], "optimization": true, "outputHashing": "all", - "sourceMap": false, + "sourceMap": true, "namedChunks": false, "aot": true, "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "anyComponentStyle", - "maximumWarning": "6kb" - } - ] + "vendorChunk": true, + "buildOptimizer": true } - } + }, + "defaultConfiguration": "" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "widget-tester-front:build" + "buildTarget": "widget-tester-frontend:build" }, "configurations": { "production": { - "browserTarget": "widget-tester-front:build:production" + "buildTarget": "widget-tester-frontend:build:production" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "widget-tester-front:build" + "buildTarget": "widget-tester-frontend:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { - "main": "src/main/webapp/test.ts", - "polyfills": "src/main/webapp/polyfills.ts", + "polyfills": [ + "zone.js", + "zone.js/testing", + "src/main/webapp/polyfills.ts" + ], "tsConfig": "src/main/webapp/tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": ["src/main/webapp/assets"], + "assets": [ + "src/main/webapp/assets" + ], "stylePreprocessorOptions": { "includePaths": [ "node_modules/normalize-scss/sass", - "node_modules/material-design-icons-iconfont/src", "node_modules/@fortawesome/fontawesome-free/scss" ] }, - "styles": ["src/main/webapp/sass/styles.scss"], - "scripts": ["node_modules/jquery/dist/jquery.min.js", "node_modules/moment/min/moment-with-locales.min.js"] + "styles": [ + "src/main/webapp/sass/styles.scss" + ], + "scripts": [ + "node_modules/jquery/dist/jquery.min.js", + "node_modules/moment/min/moment-with-locales.min.js" + ] } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": ["src/main/webapp/tsconfig.app.json", "src/main/webapp/tsconfig.spec.json"], - "exclude": ["**/node_modules/**"] - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", + "builder": "@angular-eslint/builder:lint", "options": { - "protractorConfig": "protractor.conf.js", - "devServerTarget": "widget-tester-front:serve" - }, - "configurations": { - "production": { - "devServerTarget": "widget-tester-front:serve:production" - } + "lintFilePatterns": [ + "src/main/webapp/**/*.ts", + "src/main/webapp/**/*.html" + ] } } } } }, - "defaultProject": "widget-tester-front" + "schematics": { + "@schematics/angular:component": { + "prefix": "suricate", + "style": "scss" + }, + "@schematics/angular:application": { + "strict": true + }, + "@angular-eslint/schematics:application": { + "setParserOptionsProject": true + }, + "@angular-eslint/schematics:library": { + "setParserOptionsProject": true + } + }, + "cli": { + "schematicCollections": [ + "@angular-eslint/schematics" + ], + "analytics": false + } } diff --git a/karma.conf.js b/karma.conf.js deleted file mode 100644 index da7e284..0000000 --- a/karma.conf.js +++ /dev/null @@ -1,41 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma') - ], - client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser - }, - coverageReporter: { - dir: require('path').join(__dirname, 'coverage'), - subdir: '.', - reporters: [ - { type: 'html' }, - { type: 'text-summary' } - ] - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome', 'ChromeHeadlessNoSandbox'], - customLaunchers: { - ChromeHeadlessNoSandbox: { - base: 'ChromeHeadless', - flags: ['--headless', '--disable-gpu', '--no-sandbox', '--js-flags=--max-old-space-size=8192'] - } - }, - singleRun: false, - restartOnFileChange: true - }); -}; diff --git a/package.json b/package.json index ce467c8..0ba3461 100644 --- a/package.json +++ b/package.json @@ -1,64 +1,64 @@ { - "name": "widget-tester-front", + "name": "widget-tester-frontend", "version": "1.0.4-next", - "license": "Apache2", + "license": "Apache-2.0", "scripts": { - "build": "ng build", - "e2e": "ng e2e", - "lint": "ng lint", "ng": "ng", - "prettyformat": "pretty-quick --staged", - "start": "ng serve -o", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", "test": "ng test", - "test-headless-no-sandbox": "ng test --browsers=ChromeHeadlessNoSandbox" + "test-ci": "ng test --no-watch --no-progress --code-coverage --browsers=ChromeHeadlessNoSandbox", + "lint": "ng lint", + "prettyformat": "pretty-quick --staged" }, "private": true, "dependencies": { - "@angular/animations": "^11.2.12", - "@angular/cdk": "^11.2.11", - "@angular/common": "^11.2.12", - "@angular/compiler": "^11.2.12", - "@angular/core": "^11.2.12", - "@angular/flex-layout": "^11.0.0-beta.33", - "@angular/forms": "^11.2.12", - "@angular/material": "^11.2.11", - "@angular/platform-browser": "^11.2.12", - "@angular/platform-browser-dynamic": "^11.2.12", - "@angular/router": "^11.2.12", - "@fortawesome/fontawesome-free": "^5.11.2", - "material-design-icons-iconfont": "^5.0.1", - "angular2-grid": "^4.0.0", - "classlist.js": "^1.1.20150312", - "jquery": "^3.5.0", + "@angular/animations": "^17.0.8", + "@angular/cdk": "^17.0.4", + "@angular/common": "^17.0.8", + "@angular/compiler": "^17.0.8", + "@angular/core": "^17.0.8", + "@angular/forms": "^17.0.8", + "@angular/material": "^17.0.4", + "@angular/platform-browser": "^17.0.8", + "@angular/platform-browser-dynamic": "^17.0.8", + "@angular/router": "^17.0.8", + "@fortawesome/fontawesome-free": "^6.5.1", + "@katoid/angular-grid-layout": "^2.2.0", + "jquery": "^3.7.1", "moment": "^2.22.1", "normalize-scss": "^7.0.1", "rxjs": "6.5.3", - "tslib": "^2.0.0", - "zone.js": "~0.10.2" + "zone.js": "~0.14.2" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.1102.11", - "@angular/cli": "^11.2.11", - "@angular/compiler-cli": "^11.2.12", - "@types/jasmine": "~3.6.0", - "@types/node": "^12.11.1", - "codelyzer": "^6.0.0", - "husky": "^3.0.5", - "jasmine-core": "~3.6.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "^6.3.2", + "@angular-devkit/build-angular": "^17.0.9", + "@angular-eslint/builder": "^17.2.0", + "@angular-eslint/eslint-plugin": "^17.2.0", + "@angular-eslint/eslint-plugin-template": "^17.2.0", + "@angular-eslint/schematics": "^17.2.0", + "@angular-eslint/template-parser": "^17.2.0", + "@angular/cli": "^17.0.9", + "@angular/compiler-cli": "^17.0.8", + "@types/jasmine": "~5.1.4", + "@types/node": "^20.10.2", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "eslint": "^8.53.0", + "eslint-plugin-deprecation": "^2.0.0", + "husky": "^8.0.3", + "jasmine-core": "~5.1.1", + "jasmine-spec-reporter": "~7.0.0", + "karma": "~6.4.1", "karma-chrome-launcher": "~3.1.0", "karma-coverage": "^2.0.3", "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", - "prettier": "^1.18.2", - "pretty-quick": "^1.11.1", + "karma-jasmine-html-reporter": "^1.7.0", + "prettier": "^3.1.0", + "pretty-quick": "^3.1.3", "protractor": "~7.0.0", - "npm-run-all": "^4.1.5", - "ts-node": "~3.2.0", - "tslint": "~6.1.0", - "tslint-config-prettier": "^1.18.0", - "tslint-plugin-prettier": "^2.3.0", - "typescript": "~4.1.5" + "ts-node": "~10.9.1", + "typescript": "~5.2.2" } -} +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4abf3b7..f97d96a 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.5 + 3.2.1 @@ -254,8 +254,7 @@ install-node-and-npm - - v12.13.1 + v20.10.0 @@ -275,7 +274,7 @@ npm - run build -- --prod + run build -- --configuration production diff --git a/src/main/java/com/michelin/suricate/widget/tester/configuration/web/WebConfig.java b/src/main/java/com/michelin/suricate/widget/tester/configuration/web/WebConfig.java index 6ca4275..23f5ff2 100644 --- a/src/main/java/com/michelin/suricate/widget/tester/configuration/web/WebConfig.java +++ b/src/main/java/com/michelin/suricate/widget/tester/configuration/web/WebConfig.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -14,7 +15,6 @@ import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.web.cors.CorsUtils; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; @@ -50,7 +50,9 @@ public SecurityFilterChain filterChain(HttpSecurity http, .frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) .authorizeHttpRequests(authorizeRequestsConfigurer -> authorizeRequestsConfigurer .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() - .requestMatchers(mvcMatcherBuilder.pattern("/api/**")).permitAll()) + .requestMatchers(mvcMatcherBuilder.pattern("/api/**")).permitAll() + // Front-End + .requestMatchers(mvcMatcherBuilder.pattern(HttpMethod.GET, "/**")).permitAll()) .build(); } diff --git a/src/main/java/com/michelin/suricate/widget/tester/model/dto/api/ProjectWidgetResponseDto.java b/src/main/java/com/michelin/suricate/widget/tester/model/dto/api/ProjectWidgetResponseDto.java index d1c1fe2..4d60970 100644 --- a/src/main/java/com/michelin/suricate/widget/tester/model/dto/api/ProjectWidgetResponseDto.java +++ b/src/main/java/com/michelin/suricate/widget/tester/model/dto/api/ProjectWidgetResponseDto.java @@ -13,6 +13,7 @@ @NoArgsConstructor @EqualsAndHashCode(callSuper = false) public class ProjectWidgetResponseDto extends AbstractDto { + private Long id; private String instantiateHtml; private String technicalName; private String cssContent; diff --git a/src/main/java/com/michelin/suricate/widget/tester/services/api/WidgetService.java b/src/main/java/com/michelin/suricate/widget/tester/services/api/WidgetService.java index 30036d0..62a5c63 100644 --- a/src/main/java/com/michelin/suricate/widget/tester/services/api/WidgetService.java +++ b/src/main/java/com/michelin/suricate/widget/tester/services/api/WidgetService.java @@ -85,6 +85,7 @@ public ProjectWidgetResponseDto runWidget(WidgetExecutionRequestDto widgetExecut .append("\n")); ProjectWidgetResponseDto projectWidgetResponseDto = new ProjectWidgetResponseDto(); + projectWidgetResponseDto.setId(1L); projectWidgetResponseDto.setTechnicalName(widget.getTechnicalName()); projectWidgetResponseDto.setCssContent(widget.getCssContent()); @@ -124,7 +125,7 @@ public ProjectWidgetResponseDto runWidget(WidgetExecutionRequestDto widgetExecut /** * Instantiate the HTML of a widget with the data resulting from - * the Nashorn execution. + * the Js execution. * * @param widget The widget * @param data The computed data @@ -173,9 +174,9 @@ public String instantiateProjectWidgetHtml(WidgetDto widget, String data, String } /** - * Log information about the Nashorn response. + * Log information about the Js execution. * - * @param jsResultDto The Nashorn response + * @param jsResultDto The Js execution result */ private void logResponse(JsResultDto jsResultDto) { if (StringUtils.isNotBlank(jsResultDto.getLog())) { diff --git a/src/main/java/com/michelin/suricate/widget/tester/services/js/script/JsEndpoints.java b/src/main/java/com/michelin/suricate/widget/tester/services/js/script/JsEndpoints.java index 09296a0..e9ef277 100644 --- a/src/main/java/com/michelin/suricate/widget/tester/services/js/script/JsEndpoints.java +++ b/src/main/java/com/michelin/suricate/widget/tester/services/js/script/JsEndpoints.java @@ -202,7 +202,7 @@ public static String post(String url, String body, String headerName, String hea /** * Check if a thread is interrupted. - * This method is injected during the Nashorn request preparation + * This method is injected during the Js execution preparation * * @throws InterruptedException an exception if the thread is interrupted */ diff --git a/src/main/java/com/michelin/suricate/widget/tester/utils/JavaScriptUtils.java b/src/main/java/com/michelin/suricate/widget/tester/utils/JavaScriptUtils.java index 90277d0..764370a 100644 --- a/src/main/java/com/michelin/suricate/widget/tester/utils/JavaScriptUtils.java +++ b/src/main/java/com/michelin/suricate/widget/tester/utils/JavaScriptUtils.java @@ -37,7 +37,7 @@ public final class JavaScriptUtils { JavaScriptUtils.PACKAGES_LITERAL + JsEndpoints.class.getName() + ".checkInterrupted();"; /** - * Method used to prepare Nashorn script and update path. + * Method used to prepare Js execution and update path. * * @param data javascript script * @return the script with all class path updated diff --git a/src/main/webapp/.browserslistrc b/src/main/webapp/.browserslistrc index 8084853..5c52ff3 100644 --- a/src/main/webapp/.browserslistrc +++ b/src/main/webapp/.browserslistrc @@ -5,8 +5,4 @@ # You can see what browsers were selected by your queries by running: # npx browserslist -> 0.5% -last 2 versions -Firefox ESR -not dead -not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file +defaults \ No newline at end of file diff --git a/src/main/webapp/app/app.component.ts b/src/main/webapp/app/app.component.ts index 218bb97..9dbb7f8 100644 --- a/src/main/webapp/app/app.component.ts +++ b/src/main/webapp/app/app.component.ts @@ -10,7 +10,7 @@ export class AppComponent { /** * The widget execution result */ - public widgetExecutionResult: WidgetExecutionResult | undefined; + public widgetExecutionResult: WidgetExecutionResult; /** * Constructor @@ -22,7 +22,7 @@ export class AppComponent { * * @param widgetExecutionResult The widget execution result */ - public setWidgetExecutionResult(widgetExecutionResult?: WidgetExecutionResult) { + public setWidgetExecutionResult(widgetExecutionResult: WidgetExecutionResult) { this.widgetExecutionResult = widgetExecutionResult; } } diff --git a/src/main/webapp/app/app.module.ts b/src/main/webapp/app/app.module.ts index e2d8226..b77838c 100644 --- a/src/main/webapp/app/app.module.ts +++ b/src/main/webapp/app/app.module.ts @@ -4,9 +4,8 @@ import { DashboardModule } from './dashboard/dashboard.module'; import { SharedModule } from './shared/shared.module'; @NgModule({ - declarations: [AppComponent], imports: [DashboardModule, SharedModule], - providers: [], + declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule {} diff --git a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.html b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.html index b983234..23f2d1e 100644 --- a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.html +++ b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.html @@ -1,10 +1,6 @@
+ class="widget" + [ngClass]="projectWidget?.technicalName + ' widget-1'"> diff --git a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.scss b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.scss index 14a90b1..478d25a 100644 --- a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.scss +++ b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.scss @@ -1,4 +1,6 @@ .widget { + width: 100%; + height: 100%; background-color: transparent; &.moving { diff --git a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.spec.ts b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.spec.ts index 0a74028..d558221 100644 --- a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.spec.ts +++ b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.spec.ts @@ -1,4 +1,4 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import { DashboardScreenWidgetComponent } from './dashboard-screen-widget.component'; import { MockModule } from '../../../../mock/mock.module'; import { MockedModelBuilderService } from '../../../../mock/services/mocked-model-builder/mocked-model-builder.service'; @@ -7,22 +7,22 @@ describe('DashboardScreenWidgetComponent', () => { let component: DashboardScreenWidgetComponent; let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [MockModule], - declarations: [DashboardScreenWidgetComponent] - }).compileComponents(); - }); + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [MockModule], + declarations: [DashboardScreenWidgetComponent] + }).compileComponents(); - beforeEach(() => { - const mockedModelBuilderService = TestBed.inject(MockedModelBuilderService); - fixture = TestBed.createComponent(DashboardScreenWidgetComponent); - component = fixture.componentInstance; - component.projectWidget = mockedModelBuilderService.buildMockedProjectWidget(); - component.gridStackItem = mockedModelBuilderService.buildGridStackItem(); + const mockedModelBuilderService = TestBed.inject(MockedModelBuilderService); - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DashboardScreenWidgetComponent); + component = fixture.componentInstance; + component.projectWidget = mockedModelBuilderService.buildMockedProjectWidget(); + + fixture.detectChanges(); + }) + ); it('should create', () => { expect(component).toBeTruthy(); diff --git a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.ts b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.ts index e857b2a..c0dbd65 100644 --- a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.ts +++ b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen-widget/dashboard-screen-widget.component.ts @@ -1,6 +1,5 @@ import { Component, Input, OnInit } from '@angular/core'; import { ProjectWidget } from '../../../../shared/models/project-widget/project-widget'; -import { NgGridItemConfig, NgGridItemEvent } from 'angular2-grid'; import { GridItemUtils } from '../../../../shared/utils/grid-item.utils'; import { LibraryService } from '../../../services/library/library.service'; @@ -14,18 +13,7 @@ export class DashboardScreenWidgetComponent implements OnInit { * The projectWidget to display */ @Input() - public projectWidget?: ProjectWidget; - - /** - * The grid item config - */ - @Input() - public gridStackItem!: NgGridItemConfig; - - /** - * The configuration of this project widget on the grid - */ - private startGridStackItem!: NgGridItemConfig; + public projectWidget: ProjectWidget; /** * Is the widget loading or not @@ -41,32 +29,8 @@ export class DashboardScreenWidgetComponent implements OnInit { * Init method */ ngOnInit(): void { - this.startGridStackItem = { ...this.gridStackItem }; - this.libraryService.allExternalLibrariesLoaded.subscribe((areExternalLibrariesLoaded: boolean) => { this.loading = !areExternalLibrariesLoaded; }); } - - /** - * Register the new position of the element - * - * @param gridItemEvent The grid item event - */ - public registerNewPosition(gridItemEvent: NgGridItemEvent): void { - this.gridStackItem.col = gridItemEvent.col; - this.gridStackItem.row = gridItemEvent.row; - this.gridStackItem.sizey = gridItemEvent.sizey; - this.gridStackItem.sizex = gridItemEvent.sizex; - } - - /** - * Disable click event if the item have been moved - * @param event The click event - */ - public preventDefault(event: MouseEvent): void { - if (GridItemUtils.isItemHaveBeenMoved(this.startGridStackItem, this.gridStackItem)) { - event.preventDefault(); - } - } } diff --git a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.html b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.html index da39659..83d1d6c 100644 --- a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.html +++ b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.html @@ -8,20 +8,34 @@

Widget sandbox

{{ widgetExecutionResult.widgetExecutionErrorMessage! }}

-
- - -
- + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.scss b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.scss index 4c52b4c..2e38213 100644 --- a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.scss +++ b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.scss @@ -13,4 +13,8 @@ .grid-stack { overflow-x: hidden; + + .grid-placeholder { + opacity: 0.2; + } } diff --git a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.ts b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.ts index 5fd71ad..cad90c5 100644 --- a/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.ts +++ b/src/main/webapp/app/dashboard/components/dashboard-screen/dashboard-screen.component.ts @@ -1,17 +1,17 @@ -import { Component, ElementRef, Input, OnChanges, OnInit, Renderer2, SimpleChanges, ViewChild } from '@angular/core'; -import { NgGridConfig, NgGridItemConfig } from 'angular2-grid'; -import { ProjectWidget } from '../../../shared/models/project-widget/project-widget'; +import { Component, ElementRef, Input, OnChanges, Renderer2, SimpleChanges, ViewChild } from '@angular/core'; import { LibraryService } from '../../services/library/library.service'; import { HttpLibraryService } from '../../../shared/services/backend/http-library/http-library.service'; import { WidgetExecutionResult } from '../../../shared/models/widget-execution/widget-execution-result/widget-execution-result'; import { GridItemUtils } from '../../../shared/utils/grid-item.utils'; +import {GridOptions} from "../../../shared/models/grid/grid-options"; +import {KtdGridLayout} from "@katoid/angular-grid-layout"; @Component({ selector: 'suricate-dashboard-screen', templateUrl: './dashboard-screen.component.html', styleUrls: ['./dashboard-screen.component.scss'] }) -export class DashboardScreenComponent implements OnInit, OnChanges { +export class DashboardScreenComponent implements OnChanges { /** * Reference on the span containing all the required JS libraries */ @@ -22,33 +22,23 @@ export class DashboardScreenComponent implements OnInit, OnChanges { * The widget execution result */ @Input() - public widgetExecutionResult: WidgetExecutionResult | undefined; + public widgetExecutionResult: WidgetExecutionResult; /** * The path of the widget folder */ @Input() - public widgetPath: string | undefined; + public widgetPath: string; /** - * The options for the plugin angular2-grid + * The grid options */ - public gridOptions: NgGridConfig = {}; + public gridOptions: GridOptions; /** - * The grid items description + * All the grids of the dashboard */ - public gridStackItems: NgGridItemConfig[] = []; - - /** - * Grid state when widgets were first loaded - */ - protected startGridStackItems: NgGridItemConfig[] = []; - - /** - * Grid configuration of the widget - */ - private widgetGridConfig: NgGridItemConfig = { col: 0, row: 0, sizey: 1, sizex: 1 }; + public currentGrid: KtdGridLayout = []; /** * Constructor @@ -58,11 +48,6 @@ export class DashboardScreenComponent implements OnInit, OnChanges { */ constructor(private renderer: Renderer2, private readonly libraryService: LibraryService) {} - /** - * Init method - */ - ngOnInit(): void {} - /** * Changes method * @@ -78,21 +63,16 @@ export class DashboardScreenComponent implements OnInit, OnChanges { this.initGridStackOptions(); } - this.initGridStackItems(); + this.initGrid(); this.addExternalJSLibrariesToTheDOM(); } /** - * Create the list of gridStackItems used to display widgets on the grid + * Create the list of grid items used to display widgets on the grids */ - private initGridStackItems(): void { - this.gridStackItems = []; - + private initGrid(): void { if (this.widgetExecutionResult && this.widgetExecutionResult.projectWidget) { - this.startGridStackItems = this.getGridStackItemsFromProjectWidgets(this.widgetExecutionResult.projectWidget); - - // Make a copy with a new reference - this.gridStackItems = JSON.parse(JSON.stringify(this.startGridStackItems)); + this.currentGrid = this.getGridLayoutFromProjectWidgets(); } } @@ -101,47 +81,30 @@ export class DashboardScreenComponent implements OnInit, OnChanges { */ private initGridStackOptions(): void { this.gridOptions = { - visible_cols: 5, - min_cols: 1, - row_height: 360, - min_rows: 1, - margins: [4], - auto_resize: true, + cols: 5, + rowHeight: 360, + gap: 5, draggable: true, - resizable: true + resizable: true, + compactType: undefined }; } /** * Get the list of GridItemConfigs from project widget - * - * @param projectWidget The project widgets */ - private getGridStackItemsFromProjectWidgets(projectWidget: ProjectWidget): NgGridItemConfig[] { - const gridStackItemsConfig: NgGridItemConfig[] = []; - - if (this.widgetExecutionResult?.projectWidget) { - gridStackItemsConfig.push({ - col: this.widgetGridConfig.col, - row: this.widgetGridConfig.row, - sizey: this.widgetGridConfig.sizey, - sizex: this.widgetGridConfig.sizex, - payload: this.widgetExecutionResult.projectWidget - }); - } + private getGridLayoutFromProjectWidgets(): KtdGridLayout { + const layout: KtdGridLayout = []; - return gridStackItemsConfig; - } - - /** - * Update the project widget position - */ - public updateProjectWidgetsPosition(): void { - if (this.isGridItemsHasMoved()) { - this.widgetGridConfig = this.gridStackItems[0]; + layout.push({ + id: String(this.widgetExecutionResult.projectWidget.id), + x: 0, + y: 0, + w: 1, + h: 1 + }); - this.initGridStackItems(); - } + return layout; } /** @@ -176,11 +139,15 @@ export class DashboardScreenComponent implements OnInit, OnChanges { /** * Checks if the grid elements have been moved */ - private isGridItemsHasMoved(): boolean { + private isGridItemsHasMoved(layout: KtdGridLayout): boolean { let itemHaveBeenMoved = false; - this.startGridStackItems.forEach(startGridItem => { - if (this.gridStackItems[0] && GridItemUtils.isItemHaveBeenMoved(startGridItem, this.gridStackItems[0])) { + this.currentGrid.forEach(currentGridItem => { + const gridItemFound = layout.find(newGridItem => { + return currentGridItem.id === newGridItem.id; + }); + + if (gridItemFound && GridItemUtils.isItemHaveBeenMoved(currentGridItem, gridItemFound)) { itemHaveBeenMoved = true; } }); diff --git a/src/main/webapp/app/dashboard/components/widget-configuration/widget-configuration.component.html b/src/main/webapp/app/dashboard/components/widget-configuration/widget-configuration.component.html index 4401d74..b505b39 100644 --- a/src/main/webapp/app/dashboard/components/widget-configuration/widget-configuration.component.html +++ b/src/main/webapp/app/dashboard/components/widget-configuration/widget-configuration.component.html @@ -37,23 +37,23 @@

Widget parameters

Value - - None + None {{ possibleValue.value }} - -
+