diff --git a/ClientApp/staff-db-ui/.vscode/launch.json b/ClientApp/staff-db-ui/.vscode/launch.json new file mode 100644 index 0000000..1e42eb5 --- /dev/null +++ b/ClientApp/staff-db-ui/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "name": "ng serve", + "type": "chrome", + "request": "launch", + "url": "http://localhost:4204", + "webRoot": "${workspaceFolder}" + }, + { + "name": "ng test", + "type": "chrome", + "request": "launch", + "preLaunchTask": "npm: test", + "url": "http://localhost:4204/debug.html", + "webRoot": "${workspaceFolder}" + } + ] +} diff --git a/ClientApp/staff-db-ui/.vscode/settings.json b/ClientApp/staff-db-ui/.vscode/settings.json new file mode 100644 index 0000000..95ff930 --- /dev/null +++ b/ClientApp/staff-db-ui/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "angular.enable-strict-mode-prompt": false, + "typescript.tsdk": "node_modules\\typescript\\lib", + "azdoPullRequests.projectName": "StaffDB", + "azdoPullRequests.pullRequestTitle": "commit" +} diff --git a/ClientApp/staff-db-ui/angular.json b/ClientApp/staff-db-ui/angular.json new file mode 100644 index 0000000..f5d8a56 --- /dev/null +++ b/ClientApp/staff-db-ui/angular.json @@ -0,0 +1,302 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "staffdb": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "app", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "aot": true, + "outputPath": "dist", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.app.json", + "assets": [ + "src/assets", + { + "glob": "**/*", + "ignore": [ + "styles/*" + ], + "input": "src/app/shared/core/assets/", + "output": "/assets/" + }, + { + "glob": "dhr-icon-152x152i.png", + "input": "src/assets/icons/develop/", + "output": "/assets/icons/" + }, + "src/webmanifest.json", + { + "glob": "environment.js", + "input": "src/environments/", + "output": "/assets/js/" + }, + { + "glob": "package.json", + "input": "./", + "output": "./assets/json" + } + ], + "styles": [ + "src/styles.scss", + "node_modules/ngx-spinner/animations/ball-clip-rotate.css" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "src/app/shared/core/css/0-base/", + "src/app/shared/core/components/popup-base" + ] + }, + "scripts": [], + "serviceWorker": true, + "ngswConfigPath": "ngsw-config.json" + }, + "configurations": { + "default": { + "progress": true, + "optimization": false, + "outputHashing": "all", + "sourceMap": true, + "namedChunks": true, + "aot": true, + "extractLicenses": false, + "vendorChunk": true, + "buildOptimizer": false, + "budgets": [ + { + "type": "initial", + "maximumWarning": "30mb", + "maximumError": "70mb" + } + ] + }, + "develop": { + "assets": [ + "src/assets", + { + "glob": "**/*", + "ignore": [ + "styles/*" + ], + "input": "src/app/shared/core/assets/", + "output": "/assets/" + }, + { + "glob": "dhr-icon-152x152i.png", + "input": "src/assets/icons/develop/", + "output": "/assets/icons/" + }, + { + "glob": "webmanifest.json", + "input": "src/manifest/develop/", + "output": "/" + }, + { + "glob": "environment.js", + "input": "src/environments/develop/", + "output": "/assets/js/" + }, + { + "glob": "package.json", + "input": "./", + "output": "./assets/json" + } + ], + "progress": true, + "optimization": false, + "outputHashing": "all", + "sourceMap": true, + "namedChunks": true, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": false, + "budgets": [ + { + "type": "initial", + "maximumWarning": "30mb", + "maximumError": "70mb" + } + ] + }, + "production": { + "assets": [ + "src/assets", + { + "glob": "**/*", + "ignore": [ + "styles/*" + ], + "input": "src/app/shared/core/assets/", + "output": "/assets/" + }, + { + "glob": "dhr-icon-152x152i.png", + "input": "src/assets/icons/production/", + "output": "/assets/icons/" + }, + { + "glob": "webmanifest.json", + "input": "src/manifest/production/", + "output": "/" + }, + { + "glob": "environment.js", + "input": "src/environments/production/", + "output": "/assets/js/" + }, + { + "glob": "package.json", + "input": "./", + "output": "./assets/json" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "30mb", + "maximumError": "50mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "10kb" + } + ] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "liveReload": false, + "port": 4204, + "buildTarget": "staffdb:build" + }, + "configurations": { + "production": { + "buildTarget": "staffdb:build:production" + }, + "develop": { + "buildTarget": "staffdb:build:develop" + }, + "default": { + "buildTarget": "staffdb:build:default" + } + }, + "defaultConfiguration": "default" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "staffdb:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "karmaConfig": "src/karma.conf.js", + "styles": [ + "src/styles.scss", + "node_modules/ngx-spinner/animations/ball-clip-rotate.css" + ], + "scripts": [], + "assets": [ + "src/assets", + { + "glob": "translate-core/*", + "input": "src/app/shared/core/assets/", + "output": "/assets/" + }, + { + "glob": "dhr-icon-152x152i.png", + "input": "src/assets/icons/develop/", + "output": "/assets/icons/" + }, + "src/webmanifest.json", + { + "glob": "environment.js", + "input": "src/environments/", + "output": "/assets/js/" + }, + { + "glob": "package.json", + "input": "./", + "output": "./assets/json" + } + ] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "staffdb-e2e": { + "root": "e2e/", + "projectType": "application", + "prefix": "", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "staffdb:serve" + }, + "configurations": { + "production": { + "devServerTarget": "staffdb:serve:production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "e2e/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "cli": { + "analytics": false, + "cache": { + "enabled": false + } + } +} diff --git a/ClientApp/staff-db-ui/ngcc.config.js b/ClientApp/staff-db-ui/ngcc.config.js new file mode 100644 index 0000000..fb12d52 --- /dev/null +++ b/ClientApp/staff-db-ui/ngcc.config.js @@ -0,0 +1,9 @@ +module.exports = { + packages: { + 'devextreme-angular': { + ignorableDeepImportMatchers: [ + /devextreme\// + ] + }, + } +}; diff --git a/ClientApp/staff-db-ui/ngsw-config.json b/ClientApp/staff-db-ui/ngsw-config.json new file mode 100644 index 0000000..bbdf93b --- /dev/null +++ b/ClientApp/staff-db-ui/ngsw-config.json @@ -0,0 +1,30 @@ +{ + "$schema": "./node_modules/@angular/service-worker/config/schema.json", + "index": "/index.html", + "assetGroups": [ + { + "name": "app", + "installMode": "prefetch", + "resources": { + "files": [ + "/assets/icons/hr-logo_color.ico", + "/index.html", + "/webmanifest.json", + "/*.css", + "/*.js" + ] + } + }, + { + "name": "assets", + "installMode": "lazy", + "updateMode": "prefetch", + "resources": { + "files": [ + "/assets/**", + "/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)" + ] + } + } + ] +} diff --git a/ClientApp/staff-db-ui/package-lock.json b/ClientApp/staff-db-ui/package-lock.json new file mode 100644 index 0000000..581c130 --- /dev/null +++ b/ClientApp/staff-db-ui/package-lock.json @@ -0,0 +1,16517 @@ +{ + "name": "staffdb", + "version": "14.23.33", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "staffdb", + "version": "14.23.33", + "dependencies": { + "@angular/animations": "^17.3.10", + "@angular/cdk": "^16.2.14", + "@angular/common": "^17.3.10", + "@angular/compiler": "^17.3.10", + "@angular/core": "^17.3.10", + "@angular/forms": "^17.3.10", + "@angular/localize": "^17.3.10", + "@angular/material": "^16.2.14", + "@angular/material-moment-adapter": "^16.2.14", + "@angular/platform-browser": "^17.3.10", + "@angular/platform-browser-dynamic": "^17.3.10", + "@angular/pwa": "^17.3.8", + "@angular/router": "^17.3.10", + "@angular/service-worker": "^17.3.10", + "@ngx-translate/core": "^15.0.0", + "@ngx-translate/http-loader": "^8.0.0", + "@sentry/angular": "^8.4.0", + "angular-in-memory-web-api": "^0.17.0", + "devextreme-angular": "~23.2.6", + "exceljs": "^4.4.0", + "file-saver": "^2.0.5", + "jspdf": "^2.5.1", + "moment": "^2.30.1", + "ngx-clipboard": "^16.0.0", + "ngx-device-detector": "^7.0.0", + "ngx-mask": "^17.0.8", + "ngx-spinner": "^17.0.0", + "ngx-translate-multi-http-loader": "^17.0.0", + "ngx-webcam": "^0.4.1", + "rxjs": "^7.8.1", + "zone.js": "^0.14.6" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^17.3.8", + "@angular/cli": "^17.3.8", + "@angular/compiler-cli": "^17.3.10", + "@angular/language-service": "^17.3.10", + "@types/jasmine": "latest", + "@types/node": "latest", + "codelyzer": "latest", + "jasmine-core": "latest", + "jasmine-spec-reporter": "latest", + "karma": "latest", + "karma-chrome-launcher": "latest", + "karma-coverage": "latest", + "karma-jasmine": "latest", + "karma-jasmine-html-reporter": "latest", + "protractor": "latest", + "ts-node": "latest", + "tslint": "latest", + "typescript": "~5.4.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1703.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1703.8.tgz", + "integrity": "sha512-lKxwG4/QABXZvJpqeSIn/kAwnY6MM9HdHZUV+o5o3UiTi+vO8rZApG4CCaITH3Bxebm7Nam7Xbk8RuukC5rq6g==", + "devOptional": true, + "dependencies": { + "@angular-devkit/core": "17.3.8", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-angular": { + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.3.8.tgz", + "integrity": "sha512-ixsdXggWaFRP7Jvxd0AMukImnePuGflT9Yy7NJ9/y0cL/k//S/3RnkQv5i411KzN+7D4RIbNkRGGTYeqH24zlg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1703.8", + "@angular-devkit/build-webpack": "0.1703.8", + "@angular-devkit/core": "17.3.8", + "@babel/core": "7.24.0", + "@babel/generator": "7.23.6", + "@babel/helper-annotate-as-pure": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", + "@babel/plugin-transform-async-generator-functions": "7.23.9", + "@babel/plugin-transform-async-to-generator": "7.23.3", + "@babel/plugin-transform-runtime": "7.24.0", + "@babel/preset-env": "7.24.0", + "@babel/runtime": "7.24.0", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "17.3.8", + "@vitejs/plugin-basic-ssl": "1.1.0", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.18", + "babel-loader": "9.1.3", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.21.5", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.22", + "css-loader": "6.10.0", + "esbuild-wasm": "0.20.1", + "fast-glob": "3.3.2", + "http-proxy-middleware": "2.0.6", + "https-proxy-agent": "7.0.4", + "inquirer": "9.2.15", + "jsonc-parser": "3.2.1", + "karma-source-map-support": "1.4.0", + "less": "4.2.0", + "less-loader": "11.1.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "magic-string": "0.30.8", + "mini-css-extract-plugin": "2.8.1", + "mrmime": "2.0.0", + "open": "8.4.2", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.1", + "piscina": "4.4.0", + "postcss": "8.4.35", + "postcss-loader": "8.1.1", + "resolve-url-loader": "5.0.0", + "rxjs": "7.8.1", + "sass": "1.71.1", + "sass-loader": "14.1.1", + "semver": "7.6.0", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "terser": "5.29.1", + "tree-kill": "1.2.2", + "tslib": "2.6.2", + "undici": "6.11.1", + "vite": "5.1.7", + "watchpack": "2.4.0", + "webpack": "5.90.3", + "webpack-dev-middleware": "6.1.2", + "webpack-dev-server": "4.15.1", + "webpack-merge": "5.10.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.20.1" + }, + "peerDependencies": { + "@angular/compiler-cli": "^17.0.0", + "@angular/localize": "^17.0.0", + "@angular/platform-server": "^17.0.0", + "@angular/service-worker": "^17.0.0", + "@web/test-runner": "^0.18.0", + "browser-sync": "^3.0.2", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "karma": "^6.3.0", + "ng-packagr": "^17.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=5.2 <5.5" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@web/test-runner": { + "optional": true + }, + "browser-sync": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1703.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1703.8.tgz", + "integrity": "sha512-9u6fl8VVOxcLOEMzrUeaybSvi9hSLSRucHnybneYrabsgreDo32tuy/4G8p6YAHQjpWEj9jvF9Um13ertdni5Q==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1703.8", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.8.tgz", + "integrity": "sha512-Q8q0voCGudbdCgJ7lXdnyaxKHbNQBARH68zPQV72WT8NWy+Gw/tys870i6L58NWbBaCJEUcIj/kb6KoakSRu+Q==", + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.8.tgz", + "integrity": "sha512-QRVEYpIfgkprNHc916JlPuNbLzOgrm9DZalHasnLUz4P6g7pR21olb8YCyM2OTJjombNhya9ZpckcADU5Qyvlg==", + "dependencies": { + "@angular-devkit/core": "17.3.8", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.8", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/animations": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.3.10.tgz", + "integrity": "sha512-9fR5snTuG4aM2K54TG/6DXcKXMDKZMovZhjQOxO8l68/oqn6fKrHs8DLzckFs0XGRZ+2OyURH8WggFm1Z828rA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.10" + } + }, + "node_modules/@angular/cdk": { + "version": "16.2.14", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.2.14.tgz", + "integrity": "sha512-n6PrGdiVeSTEmM/HEiwIyg6YQUUymZrb5afaNLGFRM5YL0Y8OBqd+XhCjb0OfD/AfgCUtedVEPwNqrfW8KzgGw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "parse5": "^7.1.2" + }, + "peerDependencies": { + "@angular/common": "^16.0.0 || ^17.0.0", + "@angular/core": "^16.0.0 || ^17.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cli": { + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.3.8.tgz", + "integrity": "sha512-X5ZOQ6ZTKVHjhIsfl32ZRqbs+FUoeHLbT7x4fh2Os/8ObDDwrUcCJPqxe2b2RB5E2d0vepYigknHeLE7gwzlNQ==", + "devOptional": true, + "dependencies": { + "@angular-devkit/architect": "0.1703.8", + "@angular-devkit/core": "17.3.8", + "@angular-devkit/schematics": "17.3.8", + "@schematics/angular": "17.3.8", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "ini": "4.1.2", + "inquirer": "9.2.15", + "jsonc-parser": "3.2.1", + "npm-package-arg": "11.0.1", + "npm-pick-manifest": "9.0.0", + "open": "8.4.2", + "ora": "5.4.1", + "pacote": "17.0.6", + "resolve": "1.22.8", + "semver": "7.6.0", + "symbol-observable": "4.0.0", + "yargs": "17.7.2" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/common": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.3.10.tgz", + "integrity": "sha512-6SfD21M3LujymmZsZQIxAsV8Bj5u6He6ImZ+p2rr7FAhFxpVJyKldK8LCmJcFsBD4srpQcxEZ0iDxXvg+0ihAw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.10", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.3.10.tgz", + "integrity": "sha512-6Ce4siHyF0fCZBDm/cz+blJByGDu1/hbPkQVGmk5HGZTmCUeKkgyjoM6bZr7ssAsyGDRwxBh2SGHO4Ce31vuPA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.10" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.3.10.tgz", + "integrity": "sha512-85SBphqRj3szac3FbeYgEZ+I6WaAlo5h7JX06BdjOLLiaoIwlFhLeAuG+jVekseV+95grFUxIsCMphWHi2e6hQ==", + "dependencies": { + "@babel/core": "7.23.9", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/index.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/compiler": "17.3.10", + "typescript": ">=5.2 <5.5" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular/core": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.3.10.tgz", + "integrity": "sha512-ocEKu7X0yFCOvgJn1uZy76qjhsjKvULrO1k/BuIX0nwhp61DTGYTvCqKmwCBLM8/gvcKYH5vMKMHoQKtiSGE0A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.14.0" + } + }, + "node_modules/@angular/forms": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.3.10.tgz", + "integrity": "sha512-0VZWSXDi2M3DAGJlpdV3lo73Yo/73GPRqmfTOrvIoUIenFg5Dz6oNGzvt/1aRkRn6HKccjix6iMpH91EN65pWA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.10", + "@angular/core": "17.3.10", + "@angular/platform-browser": "17.3.10", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/language-service": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-17.3.10.tgz", + "integrity": "sha512-6y0yEnjuKGCnH+YxmZZUC/KEb2ZuB5z7y0AOj4PwOladMWSwHv71x1rz5MokBVBf7ZTeN2w89f9jSWBzSz+fPw==", + "dev": true, + "engines": { + "node": "^18.13.0 || >=20.9.0" + } + }, + "node_modules/@angular/localize": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-17.3.10.tgz", + "integrity": "sha512-B/r+jsYiuxm2llBsOE2rKomB5vSnTnICWcfooBDtDUAfTZNQIoSdPt2SAIbRN/c4GLZsiU53k0+jLl67HdtO2g==", + "dependencies": { + "@babel/core": "7.23.9", + "@types/babel__core": "7.20.5", + "fast-glob": "3.3.2", + "yargs": "^17.2.1" + }, + "bin": { + "localize-extract": "tools/bundles/src/extract/cli.js", + "localize-migrate": "tools/bundles/src/migrate/cli.js", + "localize-translate": "tools/bundles/src/translate/cli.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/compiler": "17.3.10", + "@angular/compiler-cli": "17.3.10" + } + }, + "node_modules/@angular/localize/node_modules/@babel/core": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/localize/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@angular/localize/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular/material": { + "version": "16.2.14", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-16.2.14.tgz", + "integrity": "sha512-zQIxUb23elPfiIvddqkIDYqQhAHa9ZwMblfbv+ug8bxr4D0Dw360jIarxCgMjAcLj7Ccl3GBqZMUnVeM6cjthw==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/auto-init": "15.0.0-canary.bc9ae6c9c.0", + "@material/banner": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/button": "15.0.0-canary.bc9ae6c9c.0", + "@material/card": "15.0.0-canary.bc9ae6c9c.0", + "@material/checkbox": "15.0.0-canary.bc9ae6c9c.0", + "@material/chips": "15.0.0-canary.bc9ae6c9c.0", + "@material/circular-progress": "15.0.0-canary.bc9ae6c9c.0", + "@material/data-table": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dialog": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/drawer": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/fab": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/floating-label": "15.0.0-canary.bc9ae6c9c.0", + "@material/form-field": "15.0.0-canary.bc9ae6c9c.0", + "@material/icon-button": "15.0.0-canary.bc9ae6c9c.0", + "@material/image-list": "15.0.0-canary.bc9ae6c9c.0", + "@material/layout-grid": "15.0.0-canary.bc9ae6c9c.0", + "@material/line-ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/linear-progress": "15.0.0-canary.bc9ae6c9c.0", + "@material/list": "15.0.0-canary.bc9ae6c9c.0", + "@material/menu": "15.0.0-canary.bc9ae6c9c.0", + "@material/menu-surface": "15.0.0-canary.bc9ae6c9c.0", + "@material/notched-outline": "15.0.0-canary.bc9ae6c9c.0", + "@material/radio": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/segmented-button": "15.0.0-canary.bc9ae6c9c.0", + "@material/select": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/slider": "15.0.0-canary.bc9ae6c9c.0", + "@material/snackbar": "15.0.0-canary.bc9ae6c9c.0", + "@material/switch": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab-bar": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab-indicator": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab-scroller": "15.0.0-canary.bc9ae6c9c.0", + "@material/textfield": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tooltip": "15.0.0-canary.bc9ae6c9c.0", + "@material/top-app-bar": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/animations": "^16.0.0 || ^17.0.0", + "@angular/cdk": "16.2.14", + "@angular/common": "^16.0.0 || ^17.0.0", + "@angular/core": "^16.0.0 || ^17.0.0", + "@angular/forms": "^16.0.0 || ^17.0.0", + "@angular/platform-browser": "^16.0.0 || ^17.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/material-moment-adapter": { + "version": "16.2.14", + "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-16.2.14.tgz", + "integrity": "sha512-LagTDXEq8XOVLy8CVswCbmq7v9bb84+VikEEN09tz831U/7PHjDZ3xRgpKtv7hXrh8cTZOg3UPQw5tZk0hwh3Q==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": "^16.0.0 || ^17.0.0", + "@angular/material": "16.2.14", + "moment": "^2.18.1" + } + }, + "node_modules/@angular/platform-browser": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.10.tgz", + "integrity": "sha512-LEhBDOKm2A7nRmZqsafVp6OinRDG1OYZBSqjnT1jZ+f0CRRFIXz6aJ0TMPoU6vq9SLRJ7vrGD9P/eBf2hW00NQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/animations": "17.3.10", + "@angular/common": "17.3.10", + "@angular/core": "17.3.10" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.3.10.tgz", + "integrity": "sha512-TW6G4+isdHM2ssQTRTobeAKtR2516pJ25BSwRb+9+Jw/ZAEYOOi+KQyofIFYQccaUjb3+LpjRcaZbtZ9m/Ispg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.10", + "@angular/compiler": "17.3.10", + "@angular/core": "17.3.10", + "@angular/platform-browser": "17.3.10" + } + }, + "node_modules/@angular/pwa": { + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-17.3.8.tgz", + "integrity": "sha512-NWp88mGEJWUhCaUFDdDMeen0Y81hxZoFNPX9/VaTQ5a2kNUjvQ08iI4ceJB89R4sQSMnmNr30c9Rovo1gS+RTw==", + "dependencies": { + "@angular-devkit/schematics": "17.3.8", + "@schematics/angular": "17.3.8", + "parse5-html-rewriting-stream": "7.0.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/cli": "^17.0.0" + }, + "peerDependenciesMeta": { + "@angular/cli": { + "optional": true + } + } + }, + "node_modules/@angular/router": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.3.10.tgz", + "integrity": "sha512-HlZlR9BOLoEKGOSMjmL5EfYL7F7PeDifbFi0dYWNcrG8zFrVKFklB1cuBdJhfPZgYhDEoGms/EToD71tg5wliA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.10", + "@angular/core": "17.3.10", + "@angular/platform-browser": "17.3.10", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/service-worker": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-17.3.10.tgz", + "integrity": "sha512-tRoO1WrA4TxLyQK4DFtant3R93DQuGs/DIvhYZ5Tpevaj8h/gL1Uwxzj3GAyZpMSbXvETlHAK8HcwG4IkXkxBg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "bin": { + "ngsw-config": "ngsw-config.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.10", + "@angular/core": "17.3.10" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", + "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "dependencies": { + "@babel/highlight": "^7.24.6", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz", + "integrity": "sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", + "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.6.tgz", + "integrity": "sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz", + "integrity": "sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==", + "dependencies": { + "@babel/compat-data": "^7.24.6", + "@babel/helper-validator-option": "^7.24.6", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz", + "integrity": "sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6", + "@babel/helper-replace-supers": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", + "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.6.tgz", + "integrity": "sha512-C875lFBIWWwyv6MHZUG9HmRrlTDgOsLWZfYR0nW69gaKJNe0/Mpxx5r0EID2ZdHQkdUmQo2t0uNckTL08/1BgA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", + "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", + "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", + "dependencies": { + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz", + "integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==", + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz", + "integrity": "sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", + "integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==", + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz", + "integrity": "sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-module-imports": "^7.24.6", + "@babel/helper-simple-access": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", + "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz", + "integrity": "sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.6.tgz", + "integrity": "sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-wrap-function": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz", + "integrity": "sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", + "integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==", + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz", + "integrity": "sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", + "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", + "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz", + "integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.6.tgz", + "integrity": "sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.24.6", + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.6.tgz", + "integrity": "sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==", + "dependencies": { + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", + "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.6", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", + "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.6.tgz", + "integrity": "sha512-iVuhb6poq5ikqRq2XWU6OQ+R5o9wF+r/or9CeUyovgptz0UlnK4/seOQ1Istu/XybYjAhQv1FRSSfHHufIku5Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.6.tgz", + "integrity": "sha512-c8TER5xMDYzzFcGqOEp9l4hvB7dcbhcGjcLVwxWfe4P5DOafdwjsBJZKsmv+o3aXh7NhopvayQIovHrh2zSRUQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/plugin-transform-optional-chaining": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.6.tgz", + "integrity": "sha512-z8zEjYmwBUHN/pCF3NuWBhHQjJCrd33qAi8MgANfMrAvn72k2cImT8VjK9LJFu4ysOLJqhfkYYb3MvwANRUNZQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.6.tgz", + "integrity": "sha512-BE6o2BogJKJImTmGpkmOic4V0hlRRxVtzqxiSPa8TIFxyhi4EFjHm08nq1M4STK4RytuLMgnSz0/wfflvGFNOg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.6.tgz", + "integrity": "sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.6.tgz", + "integrity": "sha512-jSSSDt4ZidNMggcLx8SaKsbGNEfIl0PHx/4mFEulorE7bpYLbN0d3pDW3eJ7Y5Z3yPhy3L3NaPCYyTUY7TuugQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.6.tgz", + "integrity": "sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.6.tgz", + "integrity": "sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.6.tgz", + "integrity": "sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.6.tgz", + "integrity": "sha512-1QSRfoPI9RoLRa8Mnakc6v3e0gJxiZQTYrMfLn+mD0sz5+ndSzwymp2hDcYJTyT0MOn0yuWzj8phlIvO72gTHA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.6.tgz", + "integrity": "sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-compilation-targets": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-replace-supers": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", + "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.6.tgz", + "integrity": "sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/template": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.6.tgz", + "integrity": "sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.6.tgz", + "integrity": "sha512-rCXPnSEKvkm/EjzOtLoGvKseK+dS4kZwx1HexO3BtRtgL0fQ34awHn34aeSHuXtZY2F8a1X8xqBBPRtOxDVmcA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.6.tgz", + "integrity": "sha512-/8Odwp/aVkZwPFJMllSbawhDAO3UJi65foB00HYnK/uXvvCPm0TAXSByjz1mpRmp0q6oX2SIxpkUOpPFHk7FLA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.6.tgz", + "integrity": "sha512-vpq8SSLRTBLOHUZHSnBqVo0AKX3PBaoPs2vVzYVWslXDTDIpwAcCDtfhUcHSQQoYoUvcFPTdC8TZYXu9ZnLT/w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.6.tgz", + "integrity": "sha512-EemYpHtmz0lHE7hxxxYEuTYOOBZ43WkDgZ4arQ4r+VX9QHuNZC+WH3wUWmRNvR8ECpTRne29aZV6XO22qpOtdA==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.6.tgz", + "integrity": "sha512-inXaTM1SVrIxCkIJ5gqWiozHfFMStuGbGJAxZFBoHcRRdDP0ySLb3jH6JOwmfiinPwyMZqMBX+7NBDCO4z0NSA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.6.tgz", + "integrity": "sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.6.tgz", + "integrity": "sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.6.tgz", + "integrity": "sha512-Uvgd9p2gUnzYJxVdBLcU0KurF8aVhkmVyMKW4MIY1/BByvs3EBpv45q01o7pRTVmTvtQq5zDlytP3dcUgm7v9w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.6.tgz", + "integrity": "sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.6.tgz", + "integrity": "sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.6.tgz", + "integrity": "sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.6.tgz", + "integrity": "sha512-eAGogjZgcwqAxhyFgqghvoHRr+EYRQPFjUXrTYKBRb5qPnAVxOOglaxc4/byHqjvq/bqO2F3/CGwTHsgKJYHhQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.6.tgz", + "integrity": "sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-simple-access": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.6.tgz", + "integrity": "sha512-xg1Z0J5JVYxtpX954XqaaAT6NpAY6LtZXvYFCJmGFJWwtlz2EmJoR8LycFRGNE8dBKizGWkGQZGegtkV8y8s+w==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.24.6", + "@babel/helper-module-transforms": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.6.tgz", + "integrity": "sha512-esRCC/KsSEUvrSjv5rFYnjZI6qv4R1e/iHQrqwbZIoRJqk7xCvEUiN7L1XrmW5QSmQe3n1XD88wbgDTWLbVSyg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.6.tgz", + "integrity": "sha512-6DneiCiu91wm3YiNIGDWZsl6GfTTbspuj/toTEqLh9d4cx50UIzSdg+T96p8DuT7aJOBRhFyaE9ZvTHkXrXr6Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.6.tgz", + "integrity": "sha512-f8liz9JG2Va8A4J5ZBuaSdwfPqN6axfWRK+y66fjKYbwf9VBLuq4WxtinhJhvp1w6lamKUwLG0slK2RxqFgvHA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.6.tgz", + "integrity": "sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.6.tgz", + "integrity": "sha512-6voawq8T25Jvvnc4/rXcWZQKKxUNZcKMS8ZNrjxQqoRFernJJKjE3s18Qo6VFaatG5aiX5JV1oPD7DbJhn0a4Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.6.tgz", + "integrity": "sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.6.tgz", + "integrity": "sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-replace-supers": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.6.tgz", + "integrity": "sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.6.tgz", + "integrity": "sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.6.tgz", + "integrity": "sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.6.tgz", + "integrity": "sha512-T9LtDI0BgwXOzyXrvgLTT8DFjCC/XgWLjflczTLXyvxbnSR/gpv0hbmzlHE/kmh9nOvlygbamLKRo6Op4yB6aw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.6.tgz", + "integrity": "sha512-Qu/ypFxCY5NkAnEhCF86Mvg3NSabKsh/TPpBVswEdkGl7+FbsYHy1ziRqJpwGH4thBdQHh8zx+z7vMYmcJ7iaQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-create-class-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.6.tgz", + "integrity": "sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.6.tgz", + "integrity": "sha512-SMDxO95I8WXRtXhTAc8t/NFQUT7VYbIWwJCJgEli9ml4MhqUMh4S6hxgH6SmAC3eAQNWCDJFxcFeEt9w2sDdXg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.6.tgz", + "integrity": "sha512-DcrgFXRRlK64dGE0ZFBPD5egM2uM8mgfrvTMOSB2yKzOtjpGegVYkzh3s1zZg1bBck3nkXiaOamJUqK3Syk+4A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.0.tgz", + "integrity": "sha512-zc0GA5IitLKJrSfXlXmp8KDqLrnGECK7YRfQBmEKg1NmBOQ7e+KuclBEKJgzifQeUYLdNiAw4B4bjyvzWVLiSA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.6.tgz", + "integrity": "sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.6.tgz", + "integrity": "sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.6.tgz", + "integrity": "sha512-fN8OcTLfGmYv7FnDrsjodYBo1DhPL3Pze/9mIIE2MGCT1KgADYIOD7rEglpLHZj8PZlC/JFX5WcD+85FLAQusw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.6.tgz", + "integrity": "sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.6.tgz", + "integrity": "sha512-IshCXQ+G9JIFJI7bUpxTE/oA2lgVLAIK8q1KdJNoPXOpvRaNjMySGuvLfBw/Xi2/1lLo953uE8hyYSDW3TSYig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.6.tgz", + "integrity": "sha512-bKl3xxcPbkQQo5eX9LjjDpU2xYHeEeNQbOhj0iPvetSzA+Tu9q/o5lujF4Sek60CM6MgYvOS/DJuwGbiEYAnLw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.6.tgz", + "integrity": "sha512-8EIgImzVUxy15cZiPii9GvLZwsy7Vxc+8meSlR3cXFmBIl5W5Tn9LGBf7CDKkHj4uVfNXCJB8RsVfnmY61iedA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.6.tgz", + "integrity": "sha512-pssN6ExsvxaKU638qcWb81RrvvgZom3jDgU/r5xFZ7TONkZGFf4MhI2ltMb8OcQWhHyxgIavEU+hgqtbKOmsPA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.6.tgz", + "integrity": "sha512-quiMsb28oXWIDK0gXLALOJRXLgICLiulqdZGOaPPd0vRT7fQp74NtdADAVu+D8s00C+0Xs0MxVP0VKF/sZEUgw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", + "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.24.0", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", + "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", + "dependencies": { + "@babel/code-frame": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.6.tgz", + "integrity": "sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==", + "dependencies": { + "@babel/code-frame": "^7.24.6", + "@babel/generator": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-hoist-variables": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/types": "^7.24.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.6.tgz", + "integrity": "sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==", + "dependencies": { + "@babel/types": "^7.24.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", + "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@devexpress/utils": { + "version": "1.3.16", + "resolved": "https://registry.npmjs.org/@devexpress/utils/-/utils-1.3.16.tgz", + "integrity": "sha512-4Az8FUtvesew89j6N7zmDGfZQyHicvSwVoPZMmxRPvz2u4UiLpI/LDD0zuzLYWsLa8pr+SsJ3JRIKmhlcDAsgA==", + "peer": true, + "dependencies": { + "tslib": "2.0.1" + } + }, + "node_modules/@devexpress/utils/node_modules/tslib": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", + "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==", + "peer": true + }, + "node_modules/@devextreme/runtime": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@devextreme/runtime/-/runtime-3.0.12.tgz", + "integrity": "sha512-a2VCfi82xvB19E2UpaziHDwvbwJESfxm8KUoe1QzQeOFZ3tcgBnWh+oOhf2EIFLCTU34amG7AGVxrSDz+b+ZHg==", + "peer": true, + "dependencies": { + "inferno": "^7.4.6", + "inferno-create-element": "^7.4.6", + "inferno-hydrate": "^7.4.6" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", + "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", + "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", + "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", + "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", + "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", + "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", + "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", + "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", + "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", + "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", + "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", + "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", + "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", + "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", + "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", + "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", + "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", + "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", + "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", + "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", + "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", + "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/format/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" + }, + "node_modules/@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/@fast-csv/parse/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "devOptional": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "devOptional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "devOptional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "devOptional": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "devOptional": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "devOptional": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@ljharb/through": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/@material/animation": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-leRf+BcZTfC/iSigLXnYgcHAGvFVQveoJT5+2PIRdyPI/bIG7hhciRgacHRsCKC0sGya81dDblLgdkjSUemYLw==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@material/auto-init": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-uxzDq7q3c0Bu1pAsMugc1Ik9ftQYQqZY+5e2ybNplT8gTImJhNt4M2mMiMHbMANk2l3UgICmUyRSomgPBWCPIA==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/banner": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/banner/-/banner-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-SHeVoidCUFVhXANN6MNWxK9SZoTSgpIP8GZB7kAl52BywLxtV+FirTtLXkg/8RUkxZRyRWl7HvQ0ZFZa7QQAyA==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/button": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/base": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-Fc3vGuOf+duGo22HTRP6dHdc+MUe0VqQfWOuKrn/wXKD62m0QQR2TqJd3rRhCumH557T5QUyheW943M3E+IGfg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@material/button": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/button/-/button-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-3AQgwrPZCTWHDJvwgKq7Cj+BurQ4wTjDdGL+FEnIGUAjJDskwi1yzx5tW2Wf/NxIi7IoPFyOY3UB41jwMiOrnw==", + "dependencies": { + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/focus-ring": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/card": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/card/-/card-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-nPlhiWvbLmooTnBmV5gmzB0eLWSgLKsSRBYAbIBmO76Okgz1y+fQNLag+lpm/TDaHVsn5fmQJH8e0zIg0rYsQA==", + "dependencies": { + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/checkbox": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-4tpNnO1L0IppoMF3oeQn8F17t2n0WHB0D7mdJK9rhrujen/fLbekkIC82APB3fdGtLGg3qeNqDqPsJm1YnmrwA==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/focus-ring": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/chips": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/chips/-/chips-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-fqHKvE5bSWK0bXVkf57MWxZtytGqYBZvvHIOs4JI9HPHEhaJy4CpSw562BEtbm3yFxxALoQknvPW2KYzvADnmA==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/checkbox": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/focus-ring": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "safevalues": "^0.3.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/circular-progress": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/circular-progress/-/circular-progress-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-Lxe8BGAxQwCQqrLhrYrIP0Uok10h7aYS3RBXP41ph+5GmwJd5zdyE2t93qm2dyThvU6qKuXw9726Dtq/N+wvZQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/progress-indicator": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/data-table": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/data-table/-/data-table-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-j/7qplT9+sUpfe4pyWhPbl01qJA+OoNAG3VMJruBBR461ZBKyTi7ssKH9yksFGZ8eCEPkOsk/+kDxsiZvRWkeQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/checkbox": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/icon-button": "15.0.0-canary.bc9ae6c9c.0", + "@material/linear-progress": "15.0.0-canary.bc9ae6c9c.0", + "@material/list": "15.0.0-canary.bc9ae6c9c.0", + "@material/menu": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/select": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/density": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/density/-/density-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-Zt3u07fXrBWLW06Tl5fgvjicxNQMkFdawLyNTzZ5TvbXfVkErILLePwwGaw8LNcvzqJP6ABLA8jiR+sKNoJQCg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@material/dialog": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-o+9a/fmwJ9+gY3Z/uhj/PMVJDq7it1NTWKJn2GwAKdB+fDkT4hb9qEdcxMPyvJJ5ups+XiKZo03+tZrD+38c1w==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/button": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/icon-button": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/dom": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/dom/-/dom-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-ly78R7aoCJtundSUu0UROU+5pQD5Piae0Y1MkN6bs0724azeazX1KeXFeaf06JOXnlr5/41ol+fSUPowjoqnOg==", + "dependencies": { + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/drawer": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-PFL4cEFnt7VTxDsuspFVNhsFDYyumjU0VWfj3PWB7XudsEfQ3lo85D3HCEtTTbRsCainGN8bgYNDNafLBqiigw==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/list": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/elevation": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-Ro+Pk8jFuap+T0B0shA3xI1hs2b89dNQ2EIPCNjNMp87emHKAzJfhKb7EZGIwv3+gFLlVaLyIVkb94I89KLsyg==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/fab": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/fab/-/fab-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-dvU0KWMRglwJEQwmQtFAmJcAjzg9VFF6Aqj78bJYu/DAIGFJ1VTTTSgoXM/XCm1YyQEZ7kZRvxBO37CH54rSDg==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/focus-ring": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/feature-targeting": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-wkDjVcoVEYYaJvun28IXdln/foLgPD7n9ZC9TY76GErGCwTq+HWpU6wBAAk+ePmpRFDayw4vI4wBlaWGxLtysQ==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@material/floating-label": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-bUWPtXzZITOD/2mkvLkEPO1ngDWmb74y0Kgbz6llHLOQBtycyJIpuoQJ1q2Ez0NM/tFLwPphhAgRqmL3YQ/Kzw==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/focus-ring": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-cZHThVose3GvAlJzpJoBI1iqL6d1/Jj9hXrR+r8Mwtb1hBIUEG3hxfsRd4vGREuzROPlf0OgNf/V+YHoSwgR5w==", + "dependencies": { + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0" + } + }, + "node_modules/@material/form-field": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-+JFXy5X44Gue1CbZZAQ6YejnI203lebYwL0i6k0ylDpWHEOdD5xkF2PyHR28r9/65Ebcbwbff6q7kI1SGoT7MA==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/icon-button": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-1a0MHgyIwOs4RzxrVljsqSizGYFlM1zY2AZaLDsgT4G3kzsplTx8HZQ022GpUCjAygW+WLvg4z1qAhQHvsbqlw==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/focus-ring": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/image-list": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-WKWmiYap2iu4QdqmeUSliLlN4O2Ueqa0OuVAYHn/TCzmQ2xmnhZ1pvDLbs6TplpOmlki7vFfe+aSt5SU9gwfOQ==", + "dependencies": { + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/layout-grid": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-5GqmT6oTZhUGWIb+CLD0ZNyDyTiJsr/rm9oRIi3+vCujACwxFkON9tzBlZohdtFS16nuzUusthN6Jt9UrJcN6Q==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@material/line-ripple": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-8S30WXEuUdgDdBulzUDlPXD6qMzwCX9SxYb5mGDYLwl199cpSGdXHtGgEcCjokvnpLhdZhcT1Dsxeo1g2Evh5Q==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/linear-progress": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-6EJpjrz6aoH2/gXLg9iMe0yF2C42hpQyZoHpmcgTLKeci85ktDvJIjwup8tnk8ULQyFiGiIrhXw2v2RSsiFjvQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/progress-indicator": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/list": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-TQ1ppqiCMQj/P7bGD4edbIIv4goczZUoiUAaPq/feb1dflvrFMzYqJ7tQRRCyBL8nRhJoI2x99tk8Q2RXvlGUQ==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/menu": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-IlAh61xzrzxXs38QZlt74UYt8J431zGznSzDtB1Fqs6YFNd11QPKoiRXn1J2Qu/lUxbFV7i8NBKMCKtia0n6/Q==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/list": "15.0.0-canary.bc9ae6c9c.0", + "@material/menu-surface": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/menu-surface": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-dMtSPN+olTWE+08M5qe4ea1IZOhVryYqzK0Gyb2u1G75rSArUxCOB5rr6OC/ST3Mq3RS6zGuYo7srZt4534K9Q==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/notched-outline": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-WuurMg44xexkvLTBTnsO0A+qnzFjpcPdvgWBGstBepYozsvSF9zJGdb1x7Zv1MmqbpYh/Ohnuxtb/Y3jOh6irg==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/floating-label": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/progress-indicator": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/progress-indicator/-/progress-indicator-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-uOnsvqw5F2fkeTnTl4MrYzjI7KCLmmLyZaM0cgLNuLsWVlddQE+SGMl28tENx7DUK3HebWq0FxCP8f25LuDD+w==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@material/radio": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/radio/-/radio-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-ehzOK+U1IxQN+OQjgD2lsnf1t7t7RAwQzeO6Czkiuid29ookYbQynWuLWk7NW8H8ohl7lnmfqTP1xSNkkL/F0g==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/focus-ring": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/ripple": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-JfLW+g3GMVDv4cruQ19+HUxpKVdWCldFlIPw1UYezz2h3WTNDy05S3uP2zUdXzZ01C3dkBFviv4nqZ0GCT16MA==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/rtl": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-SkKLNLFp5QtG7/JEFg9R92qq4MzTcZ5As6sWbH7rRg6ahTHoJEuqE+pOb9Vrtbj84k5gtX+vCYPvCILtSlr2uw==", + "dependencies": { + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/segmented-button": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/segmented-button/-/segmented-button-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-YDwkCWP9l5mIZJ7pZJZ2hMDxfBlIGVJ+deNzr8O+Z7/xC5LGXbl4R5aPtUVHygvXAXxpf5096ZD+dSXzYzvWlw==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/touch-target": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/select": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/select/-/select-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-unfOWVf7T0sixVG+3k3RTuATfzqvCF6QAzA6J9rlCh/Tq4HuIBNDdV4z19IVu4zwmgWYxY0iSvqWUvdJJYwakQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/floating-label": "15.0.0-canary.bc9ae6c9c.0", + "@material/line-ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/list": "15.0.0-canary.bc9ae6c9c.0", + "@material/menu": "15.0.0-canary.bc9ae6c9c.0", + "@material/menu-surface": "15.0.0-canary.bc9ae6c9c.0", + "@material/notched-outline": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/shape": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-Dsvr771ZKC46ODzoixLdGwlLEQLfxfLrtnRojXABoZf5G3o9KtJU+J+5Ld5aa960OAsCzzANuaub4iR88b1guA==", + "dependencies": { + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/slider": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/slider/-/slider-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-3AEu+7PwW4DSNLndue47dh2u7ga4hDJRYmuu7wnJCIWJBnLCkp6C92kNc4Rj5iQY2ftJio5aj1gqryluh5tlYg==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/snackbar": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-TwwQSYxfGK6mc03/rdDamycND6o+1p61WNd7ElZv1F1CLxB4ihRjbCoH7Qo+oVDaP8CTpjeclka+24RLhQq0mA==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/button": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/icon-button": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/switch": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/switch/-/switch-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-OjUjtT0kRz1ASAsOS+dNzwMwvsjmqy5edK57692qmrP6bL4GblFfBDoiNJ6t0AN4OaKcmL5Hy/xNrTdOZW7Qqw==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/focus-ring": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "safevalues": "^0.3.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/tab": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/tab/-/tab-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-s/L9otAwn/pZwVQZBRQJmPqYeNbjoEbzbjMpDQf/VBG/6dJ+aP03ilIBEkqo8NVnCoChqcdtVCoDNRtbU+yp6w==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/focus-ring": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab-indicator": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/tab-bar": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-Xmtq0wJGfu5k+zQeFeNsr4bUKv7L+feCmUp/gsapJ655LQKMXOUQZtSv9ZqWOfrCMy55hoF1CzGFV+oN3tyWWQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab-indicator": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab-scroller": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/tab-indicator": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-despCJYi1GrDDq7F2hvLQkObHnSLZPPDxnOzU16zJ6FNYvIdszgfzn2HgAZ6pl5hLOexQ8cla6cAqjTDuaJBhQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/tab-scroller": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-QWHG/EWxirj4V9u2IHz+OSY9XCWrnNrPnNgEufxAJVUKV/A8ma1DYeFSQqxhX709R8wKGdycJksg0Flkl7Gq7w==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/tab": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/textfield": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-R3qRex9kCaZIAK8DuxPnVC42R0OaW7AB7fsFknDKeTeVQvRcbnV8E+iWSdqTiGdsi6QQHifX8idUrXw+O45zPw==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/density": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/floating-label": "15.0.0-canary.bc9ae6c9c.0", + "@material/line-ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/notched-outline": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/theme": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-CpUwXGE0dbhxQ45Hu9r9wbJtO/MAlv5ER4tBHA9tp/K+SU+lDgurBE2touFMg5INmdfVNtdumxb0nPPLaNQcUg==", + "dependencies": { + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/tokens": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-nbEuGj05txWz6ZMUanpM47SaAD7soyjKILR+XwDell9Zg3bGhsnexCNXPEz2fD+YgomS+jM5XmIcaJJHg/H93Q==", + "dependencies": { + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0" + } + }, + "node_modules/@material/tooltip": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/tooltip/-/tooltip-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-UzuXp0b9NuWuYLYpPguxrjbJnCmT/Cco8CkjI/6JajxaeA3o2XEBbQfRMTq8PTafuBjCHTc0b0mQY7rtxUp1Gg==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/button": "15.0.0-canary.bc9ae6c9c.0", + "@material/dom": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/tokens": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "safevalues": "^0.3.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/top-app-bar": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-vJWjsvqtdSD5+yQ/9vgoBtBSCvPJ5uF/DVssv8Hdhgs1PYaAcODUi77kdi0+sy/TaWyOsTkQixqmwnFS16zesA==", + "dependencies": { + "@material/animation": "15.0.0-canary.bc9ae6c9c.0", + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/elevation": "15.0.0-canary.bc9ae6c9c.0", + "@material/ripple": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/shape": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "@material/typography": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/touch-target": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-AqYh9fjt+tv4ZE0C6MeYHblS2H+XwLbDl2mtyrK0DOEnCVQk5/l5ImKDfhrUdFWHvS4a5nBM4AA+sa7KaroLoA==", + "dependencies": { + "@material/base": "15.0.0-canary.bc9ae6c9c.0", + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/rtl": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/typography": { + "version": "15.0.0-canary.bc9ae6c9c.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-15.0.0-canary.bc9ae6c9c.0.tgz", + "integrity": "sha512-CKsG1zyv34AKPNyZC8olER2OdPII64iR2SzQjpqh1UUvmIFiMPk23LvQ1OnC5aCB14pOXzmVgvJt31r9eNdZ6Q==", + "dependencies": { + "@material/feature-targeting": "15.0.0-canary.bc9ae6c9c.0", + "@material/theme": "15.0.0-canary.bc9ae6c9c.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@ngtools/webpack": { + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.3.8.tgz", + "integrity": "sha512-CjSVVa/9fzMpEDQP01SC4colKCbZwj7vUq0H2bivp8jVsmd21x9Fu0gDBH0Y9NdfAIm4eGZvmiZKMII3vIOaYQ==", + "dev": true, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^17.0.0", + "typescript": ">=5.2 <5.5", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-translate/core": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-15.0.0.tgz", + "integrity": "sha512-Am5uiuR0bOOxyoercDnAA3rJVizo4RRqJHo8N3RqJ+XfzVP/I845yEnMADykOHvM6HkVm4SZSnJBOiz0Anx5BA==", + "engines": { + "node": "^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0", + "rxjs": "^6.5.5 || ^7.4.0" + } + }, + "node_modules/@ngx-translate/http-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-8.0.0.tgz", + "integrity": "sha512-SFMsdUcmHF5OdZkL1CHEoSAwbP5EbAOPTLLboOCRRoOg21P4GJx+51jxGdJeGve6LSKLf4Pay7BkTwmE6vxYlg==", + "engines": { + "node": "^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0", + "@ngx-translate/core": ">=15.0.0", + "rxjs": "^6.5.5 || ^7.4.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "devOptional": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "devOptional": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "devOptional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.7.tgz", + "integrity": "sha512-WaOVvto604d5IpdCRV2KjQu8PzkfE96d50CQGKgywXh2GxXmDeUO5EWcBC4V57uFyrNqx83+MewuJh3WTR3xPA==", + "devOptional": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^4.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "devOptional": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "devOptional": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/git/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "devOptional": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", + "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", + "devOptional": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.1.0.tgz", + "integrity": "sha512-1aL4TuVrLS9sf8quCLerU3H9J4vtCtgu8VauYozrmEyU57i/EdKleCnsQ7vpnABIH6c9mnTxcH5sFkO3BlV8wQ==", + "devOptional": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^4.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "devOptional": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", + "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", + "devOptional": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "devOptional": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "devOptional": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz", + "integrity": "sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ==", + "devOptional": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "devOptional": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "devOptional": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "devOptional": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@schematics/angular": { + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.8.tgz", + "integrity": "sha512-2g4OmSyE9YGq50Uj7fNI26P/TSAFJ7ZuirwTF2O7Xc4XRQ29/tYIIqhezpNlTb6rlYblcQuMcUZBrMfWJHcqJw==", + "dependencies": { + "@angular-devkit/core": "17.3.8", + "@angular-devkit/schematics": "17.3.8", + "jsonc-parser": "3.2.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@sentry-internal/browser-utils": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.5.0.tgz", + "integrity": "sha512-R2h4JssvmY/mnq3iW49Oxas9BJ8CPR7yP88lCHiCHtwH/gHxemgCtq/NY1ptA0t45Eae+4ILU0ppOsJcDg9VBw==", + "dependencies": { + "@sentry/core": "8.5.0", + "@sentry/types": "8.5.0", + "@sentry/utils": "8.5.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry-internal/feedback": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.5.0.tgz", + "integrity": "sha512-GTLIfRKx2Ye0pIxhVUSxxwPbQfiSNhXpQMnSrSYHDo1KHLgbgZ4MaX2Qnx+CZN6mXDVVrtk1sqTR83ytFCwRcw==", + "dependencies": { + "@sentry/core": "8.5.0", + "@sentry/types": "8.5.0", + "@sentry/utils": "8.5.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry-internal/replay": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.5.0.tgz", + "integrity": "sha512-eluGqUjuSZKqe3dqqBvMkh3HJ9aPxXOT0i3ydUHoV9XWA7oeUfWk6gIqMm7WLTHagOGYp3v4KTOYdzu4QS6OMA==", + "dependencies": { + "@sentry-internal/browser-utils": "8.5.0", + "@sentry/core": "8.5.0", + "@sentry/types": "8.5.0", + "@sentry/utils": "8.5.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry-internal/replay-canvas": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.5.0.tgz", + "integrity": "sha512-BOwoUjRHQ0OUsUwHiBhXtkvJXe+9LlB9cb8KmhcHdfqajp4L10aN+4OC8UTSbCX832Ph/K6nu5gelK4wAI9NVw==", + "dependencies": { + "@sentry-internal/replay": "8.5.0", + "@sentry/core": "8.5.0", + "@sentry/types": "8.5.0", + "@sentry/utils": "8.5.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/angular": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry/angular/-/angular-8.5.0.tgz", + "integrity": "sha512-0a22ON8KwYVfyEfFAxQiX1/8MgT2DZlfQf2RyFSxI+7B6viCAlnTS2Bs+xVxo2vuG1SVq2M1LrPUrRU+be7JMQ==", + "dependencies": { + "@sentry/browser": "8.5.0", + "@sentry/core": "8.5.0", + "@sentry/types": "8.5.0", + "@sentry/utils": "8.5.0", + "tslib": "^2.4.1" + }, + "engines": { + "node": ">=14.18" + }, + "peerDependencies": { + "@angular/common": ">= 14.x <= 18.x", + "@angular/core": ">= 14.x <= 18.x", + "@angular/router": ">= 14.x <= 18.x", + "rxjs": "^6.5.5 || ^7.x" + } + }, + "node_modules/@sentry/browser": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.5.0.tgz", + "integrity": "sha512-rxthVdwkkGqArQLM+/O8y0J4oe/J5MLE7WzzRkzSJWLdt6cJMrrb43sKGQf2IQSg6kf1se+qKmpRly5uEOf8OA==", + "dependencies": { + "@sentry-internal/browser-utils": "8.5.0", + "@sentry-internal/feedback": "8.5.0", + "@sentry-internal/replay": "8.5.0", + "@sentry-internal/replay-canvas": "8.5.0", + "@sentry/core": "8.5.0", + "@sentry/types": "8.5.0", + "@sentry/utils": "8.5.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/core": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.5.0.tgz", + "integrity": "sha512-SO3ddBzGdha+Oflp+IKwBxj+7ds1q69OAT3VsypTd+WUFQdI9DIhR92Bjf+QQZCIzUNOi79VWOh3aOi3f6hMnw==", + "dependencies": { + "@sentry/types": "8.5.0", + "@sentry/utils": "8.5.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/types": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.5.0.tgz", + "integrity": "sha512-eDgkSmKI4+XL0QZm4H3j/n1RgnrbnjXZmjj+LsfccRZQwbPu9bWlc8q7Y7Ty1gOsoUpX+TecNLp2a8CRID4KHA==", + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/utils": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.5.0.tgz", + "integrity": "sha512-fdrCzo8SAYiw9JBhkJPqYqJkDXZ/wICzN7+zcXIuzKNhE1hdoFjeKcPnpUI3bKZCG6e3hT1PTYQXhVw7GIZV9w==", + "dependencies": { + "@sentry/types": "8.5.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sigstore/bundle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", + "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", + "devOptional": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", + "devOptional": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", + "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", + "devOptional": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", + "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", + "devOptional": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "make-fetch-happen": "^13.0.1", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", + "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", + "devOptional": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2", + "tuf-js": "^2.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", + "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", + "devOptional": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "devOptional": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", + "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", + "devOptional": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.1.tgz", + "integrity": "sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.4.tgz", + "integrity": "sha512-px7OMFO/ncXxixDe1zR13V1iycqWae0MxTaw62RpFlksUi5QuNWgQJFkTQjIOvrmutJbI7Fp2Y2N1F6D2R4G6w==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "optional": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/selenium-webdriver": { + "version": "3.0.26", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", + "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "dev": true, + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "devOptional": true + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz", + "integrity": "sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "devOptional": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "devOptional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/angular-in-memory-web-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/angular-in-memory-web-api/-/angular-in-memory-web-api-0.17.0.tgz", + "integrity": "sha512-q1VPfyg8B0dBKjjURitxFnUBqEiR4JyATxgHuAVTLfgcMJwJIBqfEYrejCPRE2GslzqMjf2PdLklxoYs/HDd7Q==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.0", + "@angular/core": "^17.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "devOptional": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.18", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", + "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001591", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", + "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==", + "dev": true + }, + "node_modules/axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "blocking-proxy": "built/lib/bin.js" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserstack": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", + "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + } + }, + "node_modules/browserstack/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/browserstack/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/browserstack/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "devOptional": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "devOptional": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "devOptional": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "devOptional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001623", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001623.tgz", + "integrity": "sha512-X/XhAVKlpIxWPpgRTnlgZssJrF0m6YtRA0QDWgsBNT12uZM6LPRydR7ip405Y3t1LamD8cP2TZFEDZFBf5ApcA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/canvg": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", + "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/canvg/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "optional": true + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "devOptional": true + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "devOptional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "devOptional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/codelyzer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz", + "integrity": "sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g==", + "dev": true, + "dependencies": { + "@angular/compiler": "9.0.0", + "@angular/core": "9.0.0", + "app-root-path": "^3.0.0", + "aria-query": "^3.0.0", + "axobject-query": "2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "rxjs": "^6.5.3", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2", + "tslib": "^1.10.0", + "zone.js": "~0.10.3" + }, + "peerDependencies": { + "@angular/compiler": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next", + "@angular/core": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next", + "tslint": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/codelyzer/node_modules/@angular/compiler": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", + "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==", + "dev": true, + "peerDependencies": { + "tslib": "^1.10.0" + } + }, + "node_modules/codelyzer/node_modules/@angular/core": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", + "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==", + "dev": true, + "peerDependencies": { + "rxjs": "^6.5.3", + "tslib": "^1.10.0", + "zone.js": "~0.10.2" + } + }, + "node_modules/codelyzer/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/codelyzer/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/codelyzer/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/codelyzer/node_modules/zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/core-js": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", + "integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/critters": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.22.tgz", + "integrity": "sha512-NU7DEcQZM2Dy8XTKFHxtdnIM/drE312j2T4PCVaSUcS0oBeyT/NImpRw/Ap0zOr/1SE7SgPK9tGPg1WK/sVakw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "postcss-media-query-parser": "^0.2.3" + } + }, + "node_modules/critters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/critters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/critters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/critters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/critters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/critters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "devOptional": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/css-loader": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-selector-tokenizer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", + "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", + "dev": true, + "dependencies": { + "through": "X.X.X" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/dayjs": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deepmerge-ts": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-5.1.0.tgz", + "integrity": "sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw==", + "peer": true, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "devOptional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", + "dev": true, + "dependencies": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/devexpress-diagram": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/devexpress-diagram/-/devexpress-diagram-2.2.5.tgz", + "integrity": "sha512-gxcBYNChijcfmsOnWOWPmTGxIPn+eGIf3635PUgpTBL/WPpDVZJsXdEV+eXe92OEX0MopcyxiCSJZN5o3zZ4hQ==", + "peer": true, + "dependencies": { + "@devexpress/utils": "1.3.16", + "es6-object-assign": "^1.1.0" + } + }, + "node_modules/devexpress-gantt": { + "version": "4.1.54", + "resolved": "https://registry.npmjs.org/devexpress-gantt/-/devexpress-gantt-4.1.54.tgz", + "integrity": "sha512-5o5Y/v+mc/ukYGwmRy9UJ2SegKB/XXsa981BsXXT437QGHcwLzT47+NBRhsmQ8yIkp7NvCzKz8nEsF4tYORGFg==", + "peer": true, + "dependencies": { + "@devexpress/utils": "^1.4.3", + "tslib": "2.3.1" + } + }, + "node_modules/devexpress-gantt/node_modules/@devexpress/utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@devexpress/utils/-/utils-1.4.3.tgz", + "integrity": "sha512-UmmIwVRGQ6u6itE/zJ1xNmMuugXo/t1fWBtjROb7mhq2nY4ecDBdnRIqogKWAasGbMbhCxW9+ijkgRaNBVCIzQ==", + "peer": true, + "dependencies": { + "tslib": "2.3.1" + } + }, + "node_modules/devexpress-gantt/node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "peer": true + }, + "node_modules/devextreme": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/devextreme/-/devextreme-23.2.6.tgz", + "integrity": "sha512-JZkqvjLdv66feFWH0+23XRLSEKdp/DnW+AXJVTLeUc4ZvGcuZVLkOnusLF0yZ21BTG+xKxkZ4lTaSrw1BeYLDQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.12.1", + "@devextreme/runtime": "3.0.12", + "devexpress-diagram": "2.2.5", + "devexpress-gantt": "4.1.54", + "devextreme-quill": "1.6.4", + "inferno": "^7.4.9", + "inferno-hydrate": "^7.4.9", + "jszip": "^3.10.1", + "rrule": "^2.7.1", + "showdown": "^2.1.0", + "turndown": "~7.1.0" + }, + "bin": { + "devextreme-bundler": "bin/bundler.js", + "devextreme-bundler-init": "bin/bundler-init.js" + } + }, + "node_modules/devextreme-angular": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/devextreme-angular/-/devextreme-angular-23.2.6.tgz", + "integrity": "sha512-v/Q30m7kj3yZ4TEl1QvEWcLJULNuhdwJ16S4LJn7u5kGNxOLSiEP6Tovi1MUNd1p5AZrZyzEwCFb1FWNzQB1Dg==", + "dependencies": { + "@angular-devkit/schematics": "^12.2.18", + "devextreme-schematics": "*", + "inferno-server": "7.4.11", + "tslib": "^2.2.0" + }, + "peerDependencies": { + "@angular/common": ">12.0.0", + "@angular/core": ">12.0.0", + "@angular/forms": ">12.0.0", + "devextreme": "~23.2.6" + } + }, + "node_modules/devextreme-angular/node_modules/@angular-devkit/core": { + "version": "12.2.18", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-12.2.18.tgz", + "integrity": "sha512-GDLHGe9HEY5SRS+NrKr14C8aHsRCiBFkBFSSbeohgLgcgSXzZHFoU84nDWrl3KZNP8oqcUSv5lHu6dLcf2fnww==", + "dependencies": { + "ajv": "8.6.2", + "ajv-formats": "2.1.0", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/devextreme-angular/node_modules/@angular-devkit/schematics": { + "version": "12.2.18", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-12.2.18.tgz", + "integrity": "sha512-bZ9NS5PgoVfetRC6WeQBHCY5FqPZ9y2TKHUo12sOB2YSL3tgWgh1oXyP8PtX34gasqsLjNULxEQsAQYEsiX/qQ==", + "dependencies": { + "@angular-devkit/core": "12.2.18", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/devextreme-angular/node_modules/ajv": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/devextreme-angular/node_modules/ajv-formats": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz", + "integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/devextreme-angular/node_modules/magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/devextreme-angular/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/devextreme-angular/node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/devextreme-angular/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/devextreme-quill": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/devextreme-quill/-/devextreme-quill-1.6.4.tgz", + "integrity": "sha512-qs8lt+nn/2vQX1PrImQmCj2B1c8ydD5Hrjn42wWeqa4sVFd/9e2UM+PL979EtKqX0k1M4ncMe25cSbgYz5nNdA==", + "peer": true, + "dependencies": { + "core-js": "^3.34.0", + "eventemitter3": "^4.0.7", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.merge": "^4.6.2", + "parchment": "^2.0.1", + "quill-delta": "^5.0.0" + } + }, + "node_modules/devextreme-schematics": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/devextreme-schematics/-/devextreme-schematics-1.6.9.tgz", + "integrity": "sha512-TGW0yK8ZPUt8KIDruZrbUYM6TyB98+zHs93P0GYC0aepGODDW5OAiBAUCa99Hf4VabA2aopa0W/0MWhFH3P0SA==", + "dependencies": { + "@angular-devkit/core": "^12.2.18", + "@angular-devkit/schematics": "^12.2.18", + "@schematics/angular": "^12.2.18" + } + }, + "node_modules/devextreme-schematics/node_modules/@angular-devkit/core": { + "version": "12.2.18", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-12.2.18.tgz", + "integrity": "sha512-GDLHGe9HEY5SRS+NrKr14C8aHsRCiBFkBFSSbeohgLgcgSXzZHFoU84nDWrl3KZNP8oqcUSv5lHu6dLcf2fnww==", + "dependencies": { + "ajv": "8.6.2", + "ajv-formats": "2.1.0", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/devextreme-schematics/node_modules/@angular-devkit/schematics": { + "version": "12.2.18", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-12.2.18.tgz", + "integrity": "sha512-bZ9NS5PgoVfetRC6WeQBHCY5FqPZ9y2TKHUo12sOB2YSL3tgWgh1oXyP8PtX34gasqsLjNULxEQsAQYEsiX/qQ==", + "dependencies": { + "@angular-devkit/core": "12.2.18", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/devextreme-schematics/node_modules/@schematics/angular": { + "version": "12.2.18", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-12.2.18.tgz", + "integrity": "sha512-niRS9Ly9y8uI0YmTSbo8KpdqCCiZ/ATMZWeS2id5M8JZvfXbngwiqJvojdSol0SWU+n1W4iA+lJBdt4gSKlD5w==", + "dependencies": { + "@angular-devkit/core": "12.2.18", + "@angular-devkit/schematics": "12.2.18", + "jsonc-parser": "3.0.0" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/devextreme-schematics/node_modules/ajv": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/devextreme-schematics/node_modules/ajv-formats": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz", + "integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/devextreme-schematics/node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==" + }, + "node_modules/devextreme-schematics/node_modules/magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/devextreme-schematics/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/devextreme-schematics/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/devextreme-schematics/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domino": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz", + "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==", + "peer": true + }, + "node_modules/dompurify": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.4.tgz", + "integrity": "sha512-l5NNozANzaLPPe0XaAwvg3uZcHtDBnziX/HjsY1UcDj1MxTK8Dd0Kv096jyPK5HRzs/XM5IMj20dW8Fk+HnbUA==", + "optional": true + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "devOptional": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecc-jsbn/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.783", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.783.tgz", + "integrity": "sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", + "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "devOptional": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "devOptional": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz", + "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==", + "dev": true + }, + "node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", + "peer": true + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/esbuild": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", + "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.1", + "@esbuild/android-arm": "0.20.1", + "@esbuild/android-arm64": "0.20.1", + "@esbuild/android-x64": "0.20.1", + "@esbuild/darwin-arm64": "0.20.1", + "@esbuild/darwin-x64": "0.20.1", + "@esbuild/freebsd-arm64": "0.20.1", + "@esbuild/freebsd-x64": "0.20.1", + "@esbuild/linux-arm": "0.20.1", + "@esbuild/linux-arm64": "0.20.1", + "@esbuild/linux-ia32": "0.20.1", + "@esbuild/linux-loong64": "0.20.1", + "@esbuild/linux-mips64el": "0.20.1", + "@esbuild/linux-ppc64": "0.20.1", + "@esbuild/linux-riscv64": "0.20.1", + "@esbuild/linux-s390x": "0.20.1", + "@esbuild/linux-x64": "0.20.1", + "@esbuild/netbsd-x64": "0.20.1", + "@esbuild/openbsd-x64": "0.20.1", + "@esbuild/sunos-x64": "0.20.1", + "@esbuild/win32-arm64": "0.20.1", + "@esbuild/win32-ia32": "0.20.1", + "@esbuild/win32-x64": "0.20.1" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.1.tgz", + "integrity": "sha512-6v/WJubRsjxBbQdz6izgvx7LsVFvVaGmSdwrFHmEzoVgfXL89hkKPoQHsnVI2ngOkcBUQT9kmAM1hVL1k/Av4A==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/exceljs": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", + "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", + "dependencies": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.10.1", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "devOptional": true + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "devOptional": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "devOptional": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "dependencies": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "devOptional": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "devOptional": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "devOptional": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "devOptional": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "devOptional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "devOptional": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "devOptional": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "devOptional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "devOptional": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "devOptional": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "devOptional": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "optional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "devOptional": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "devOptional": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "devOptional": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "devOptional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", + "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", + "devOptional": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, + "node_modules/immutable": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", + "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "devOptional": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inferno": { + "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno/-/inferno-7.4.11.tgz", + "integrity": "sha512-N+cs33ESWI8fdToCd98yMRYl7jkLnCkJskxov3FKKlaKOvk3PRlAttbhmUaYdWXlRvt2WeXi+J4MbzNj3V6G0w==", + "hasInstallScript": true, + "dependencies": { + "inferno-shared": "7.4.11", + "inferno-vnode-flags": "7.4.11", + "opencollective-postinstall": "^2.0.3" + } + }, + "node_modules/inferno-create-element": { + "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-create-element/-/inferno-create-element-7.4.11.tgz", + "integrity": "sha512-kE6XIx2hPAd5qpDli2iGjNXgubvuyxdLvoiW71WnSzIIxA+Uxa/s8lY8m03VyHHVypFV3n329ZY5dFvKc7UQMg==", + "peer": true, + "dependencies": { + "inferno": "7.4.11" + } + }, + "node_modules/inferno-hydrate": { + "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-hydrate/-/inferno-hydrate-7.4.11.tgz", + "integrity": "sha512-hF9Ke4GHAkj8GQrMXBZPfsUqhq6WjkoDCAfXhPBuF1Wiceqyy8KerOOXEnuocHky77fuEXq0AzVnQcC064Bkfw==", + "peer": true, + "dependencies": { + "inferno": "7.4.11" + } + }, + "node_modules/inferno-server": { + "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-server/-/inferno-server-7.4.11.tgz", + "integrity": "sha512-SUnkCqZNWOIrjRVoVk/E1/70O1f1ImkCX9H2gDPbS0uc3GDxuzIeCgn0rpcc0XV9KzZJ2LTGxuBtEoQQOjUn2Q==", + "dependencies": { + "inferno": "7.4.11" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inferno-shared": { + "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-shared/-/inferno-shared-7.4.11.tgz", + "integrity": "sha512-pN725bDSTxkQmRS3e/3H02/xAqgHl+xgddCMjPm8M0etRdRcVCisi3NGPhzSbDDmiftrxhY31exs7+dwsngcDA==" + }, + "node_modules/inferno-vnode-flags": { + "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-vnode-flags/-/inferno-vnode-flags-7.4.11.tgz", + "integrity": "sha512-L7lslEQCq3IfwgT/b9zhuMf8fv6KXCNXXHZevk/WYxnqJsOWGDcKpJn0zkzXfvmj0otbB149iLUQVBq3oe2sfA==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", + "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "9.2.15", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", + "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", + "devOptional": true, + "dependencies": { + "@ljharb/through": "^2.3.12", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^3.2.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "devOptional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "devOptional": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "devOptional": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "devOptional": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "devOptional": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "devOptional": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "devOptional": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", + "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", + "devOptional": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", + "dev": true, + "dependencies": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.1.2.tgz", + "integrity": "sha512-2oIUMGn00FdUiqz6epiiJr7xcFyNYj3rDcfmnzfkBnHyBQ3cBQUs4mmyGsOb7TTLb9kxk7dBcmEmqhDKkBoDyA==", + "dev": true + }, + "node_modules/jasmine-spec-reporter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", + "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", + "dev": true, + "dependencies": { + "colors": "1.4.0" + } + }, + "node_modules/jasmine/node_modules/jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", + "dev": true + }, + "node_modules/jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", + "dev": true, + "engines": { + "node": ">= 6.9.x" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "devOptional": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "devOptional": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jspdf": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", + "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", + "dependencies": { + "@babel/runtime": "^7.14.0", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "fflate": "^0.4.8" + }, + "optionalDependencies": { + "canvg": "^3.0.6", + "core-js": "^3.6.0", + "dompurify": "^2.2.0", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/karma": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", + "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.7.2", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-coverage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", + "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "dev": true, + "dependencies": { + "jasmine-core": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "karma": "^6.0.0" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", + "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", + "dev": true, + "peerDependencies": { + "jasmine-core": "^4.0.0 || ^5.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" + } + }, + "node_modules/karma-jasmine/node_modules/jasmine-core": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", + "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", + "dev": true + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/karma/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/karma/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/karma/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", + "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "devOptional": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "peer": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "peer": true + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "devOptional": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", + "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "devOptional": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "devOptional": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "devOptional": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "devOptional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "devOptional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "devOptional": true + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "devOptional": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "devOptional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "devOptional": true + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "devOptional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "devOptional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "devOptional": true + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "devOptional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "devOptional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "devOptional": true + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "devOptional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "devOptional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "devOptional": true + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "devOptional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/ngx-clipboard": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-16.0.0.tgz", + "integrity": "sha512-rZ/Eo1PqiKMiyF8tdjhmUkoUu68f7OzBJ7YH1YFeh2RAaNrerTaW8XfFOzppSckjFQqA1fwGSYuTTJlDhDag5w==", + "dependencies": { + "ngx-window-token": ">=7.0.0", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=13.0.0", + "@angular/core": ">=13.0.0" + } + }, + "node_modules/ngx-device-detector": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ngx-device-detector/-/ngx-device-detector-7.0.0.tgz", + "integrity": "sha512-6IQZLlB31wQecbFr/5YyBfoj9zXgLz/2UHHrslgBnWIzbgdnjfEYSiwqXiJlBC9wIxMvM/BLEIQlxnl3MseQ5g==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.0", + "@angular/core": "^17.0.0" + } + }, + "node_modules/ngx-mask": { + "version": "17.0.8", + "resolved": "https://registry.npmjs.org/ngx-mask/-/ngx-mask-17.0.8.tgz", + "integrity": "sha512-zTol/ntrGyBsjkaSt04e/hPmE18TjzmK8+qxU0yyvFiXo5hF8Ut34sgY3NSHAukWAeZVUruS0gVbVOVjW8n8dA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=14.0.0", + "@angular/core": ">=14.0.0", + "@angular/forms": ">=14.0.0" + } + }, + "node_modules/ngx-spinner": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/ngx-spinner/-/ngx-spinner-17.0.0.tgz", + "integrity": "sha512-VWDSvLlCnaWqu0W1L+ybQIRHTbd+GffkX1sWs++iMPXMGVJ2ZCuzW32FHnu+p0regMUHU8r1/rvUcFD0YooJxQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/animations": ">=15.0.0", + "@angular/common": ">=15.0.0", + "@angular/core": ">=15.0.0" + } + }, + "node_modules/ngx-translate-multi-http-loader": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/ngx-translate-multi-http-loader/-/ngx-translate-multi-http-loader-17.0.0.tgz", + "integrity": "sha512-YCq2xEwGiGwuhWHXDoNHVR9TvKEhrVnGFt4WqJjYU220W8yXYKJsoX9f+BOj+sR8ryjOax4wvHy7eCZnIxuIyg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "peerDependencies": { + "@angular/common": ">=13.0.0", + "@angular/core": ">=13.0.0", + "@ngx-translate/core": ">=15.0.0", + "deepmerge-ts": "^5.1.0", + "rxjs": "^7.8.1" + } + }, + "node_modules/ngx-webcam": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/ngx-webcam/-/ngx-webcam-0.4.1.tgz", + "integrity": "sha512-8WoC8GWHaN5tH+4zO0/gfUigVKg/jX7JShAewpumJIgJXFmlKhSPnPjewNNxv7OTQiOOb+5Mh6lhTo52VLlY9A==", + "dependencies": { + "tslib": "^2.3.0" + } + }, + "node_modules/ngx-window-token": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ngx-window-token/-/ngx-window-token-7.0.0.tgz", + "integrity": "sha512-5+XfRVSY7Dciu8xyCNMkOlH2UfwR9W2P1Pirz7caaZgOZDjFbL8aEO2stjfJJm2FFf1D6dlVHNzhLWGk9HGkqA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": ">=13.0.0", + "@angular/core": ">=13.0.0" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "devOptional": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "devOptional": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "devOptional": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "devOptional": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "devOptional": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", + "integrity": "sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==", + "devOptional": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", + "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", + "devOptional": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "devOptional": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "devOptional": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "devOptional": true, + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "devOptional": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz", + "integrity": "sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA==", + "devOptional": true, + "dependencies": { + "@npmcli/redact": "^1.1.0", + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "devOptional": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "bin": { + "opencollective-postinstall": "index.js" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "devOptional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pacote": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "devOptional": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parchment": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-2.0.1.tgz", + "integrity": "sha512-VBKrlEoZCBD+iwoeag0QTtY1Cti+Ma4nLpVYcc/uus/wHhMsPOi5InH3RL1s4aekahPZpabcS2ToKyGf7RMH/g==", + "peer": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "dependencies": { + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "devOptional": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "devOptional": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "devOptional": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "devOptional": true + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.4.0.tgz", + "integrity": "sha512-+AQduEJefrOApE4bV7KRmp3N2JnnyErlVqq4P/jmko4FPz9Z877BCccl/iB3FdrWSUkvbGV9Kan/KllJgat3Vg==", + "dev": true, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "devOptional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "devOptional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/protractor": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", + "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", + "dev": true, + "dependencies": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.1.7", + "yargs": "^15.3.1" + }, + "bin": { + "protractor": "bin/protractor", + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=10.13.x" + } + }, + "node_modules/protractor/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/protractor/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/protractor/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/protractor/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "peer": true, + "dependencies": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-package-json": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.1.tgz", + "integrity": "sha512-8PcDiZ8DXUjLf687Ol4BR8Bpm2umR7vhoZOzNRt+uxD9GpBh/K+CAAALVIiYFknmvlmyg7hM7BSNUXPaCCqd0Q==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "devOptional": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "devOptional": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "devOptional": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", + "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", + "dev": true + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "devOptional": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "devOptional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrule": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.8.1.tgz", + "integrity": "sha512-hM3dHSBMeaJ0Ktp7W38BJZ7O1zOgaFEsn41PDk+yHoEtfLV+PoJt9E9xAlZiWgf/iqEqionN0ebHFZIDAp+iGw==", + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "devOptional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "devOptional": true + }, + "node_modules/safevalues": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/safevalues/-/safevalues-0.3.4.tgz", + "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" + }, + "node_modules/sass": { + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-loader": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.1.1.tgz", + "integrity": "sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==", + "dev": true, + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/saucelabs/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/saucelabs/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/saucelabs/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/sax": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.0.tgz", + "integrity": "sha512-G3nn4N8SRaR9NsCqEUHfTlfTM/Fgza1yfb8JP2CEmzYuHtHWza5Uf+g7nuUQq96prwu0GiGyPgDw752+j4fzQQ==", + "dev": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "dependencies": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/selenium-webdriver/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/selenium-webdriver/node_modules/tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==", + "dev": true, + "dependencies": { + "semver": "^5.3.0" + } + }, + "node_modules/semver-dsl/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "devOptional": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "devOptional": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/showdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "peer": true, + "dependencies": { + "commander": "^9.0.0" + }, + "bin": { + "showdown": "bin/showdown.js" + }, + "funding": { + "type": "individual", + "url": "https://www.paypal.me/tiviesantos" + } + }, + "node_modules/showdown/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sigstore": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", + "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", + "devOptional": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/sign": "^2.3.2", + "@sigstore/tuf": "^2.3.4", + "@sigstore/verify": "^1.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "devOptional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "dev": true, + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "devOptional": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "devOptional": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", + "dev": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "devOptional": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "devOptional": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "devOptional": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "devOptional": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "devOptional": true + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "devOptional": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "devOptional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "devOptional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "devOptional": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "devOptional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "devOptional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "devOptional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "devOptional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "devOptional": true + }, + "node_modules/terser": { + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", + "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "engines": { + "node": "*" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tuf-js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", + "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", + "devOptional": true, + "dependencies": { + "@tufjs/models": "2.0.1", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/turndown": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.1.3.tgz", + "integrity": "sha512-Z3/iJ6IWh8VBiACWQJaA5ulPQE5E1QwvBHj00uGzdQxdRnd8fh1DPqNOJqzQDu6DkOstORrtXzf/9adB+vMtEA==", + "peer": true, + "dependencies": { + "domino": "^2.1.6" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "devOptional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", + "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/undici": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.11.1.tgz", + "integrity": "sha512-KyhzaLJnV1qa3BSHdj4AZ2ndqI0QWPxYzaIOio0WzcEJB9gvuysprJSLtpvc2D9mhR9jPDUk7xlJlZbH2KR5iw==", + "dev": true, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "devOptional": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "devOptional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "optional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "devOptional": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "devOptional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vite": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.7.tgz", + "integrity": "sha512-sgnEEFTZYMui/sTlH1/XEnVNHMujOahPLGMxn1+5sIT45Xjng1Ec1K78jRP15dSmVgg5WBin9yO81j3o9OxofA==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "dependencies": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager": { + "version": "12.1.9", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", + "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", + "dev": true, + "dependencies": { + "adm-zip": "^0.5.2", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "bin": { + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/webdriver-manager/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webdriver-manager/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/webdriver-manager/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/webpack": { + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", + "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zone.js": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.6.tgz", + "integrity": "sha512-vyRNFqofdaHVdWAy7v3Bzmn84a1JHWSjpuTZROT/uYn8I3p2cmo7Ro9twFmYRQDPhiYOV7QLk0hhY4JJQVqS6Q==" + } + } +} diff --git a/ClientApp/staff-db-ui/package.json b/ClientApp/staff-db-ui/package.json new file mode 100644 index 0000000..93a8fd6 --- /dev/null +++ b/ClientApp/staff-db-ui/package.json @@ -0,0 +1,70 @@ +{ + "name": "staffdb", + "version": "14.23.33", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e", + "reinstall:packages": "rm -rf node_modules dist && npm cache clean --force && rm package-lock.json && npm install", + "win_reinstall:packages": "rd /s /q node_modules && npm cache clean --force && del package-lock.json && npm install", + "add_pwa": "ng add @angular/pwa@latest" + }, + "private": true, + "dependencies": { + "@angular/animations": "^17.3.10", + "@angular/cdk": "^16.2.14", + "@angular/common": "^17.3.10", + "@angular/compiler": "^17.3.10", + "@angular/core": "^17.3.10", + "@angular/forms": "^17.3.10", + "@angular/localize": "^17.3.10", + "@angular/material": "^16.2.14", + "@angular/material-moment-adapter": "^16.2.14", + "@angular/platform-browser": "^17.3.10", + "@angular/platform-browser-dynamic": "^17.3.10", + "@angular/pwa": "^17.3.8", + "@angular/router": "^17.3.10", + "@angular/service-worker": "^17.3.10", + "@ngx-translate/core": "^15.0.0", + "@ngx-translate/http-loader": "^8.0.0", + "@sentry/angular": "^8.4.0", + "angular-in-memory-web-api": "^0.17.0", + "devextreme-angular": "~23.2.6", + "exceljs": "^4.4.0", + "file-saver": "^2.0.5", + "jspdf": "^2.5.1", + "moment": "^2.30.1", + "ngx-clipboard": "^16.0.0", + "ngx-device-detector": "^7.0.0", + "ngx-mask": "^17.0.8", + "ngx-spinner": "^17.0.0", + "ngx-translate-multi-http-loader": "^17.0.0", + "ngx-webcam": "^0.4.1", + "rxjs": "^7.8.1", + "zone.js": "^0.14.6" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^17.3.8", + "@angular/cli": "^17.3.8", + "@angular/compiler-cli": "^17.3.10", + "@angular/language-service": "^17.3.10", + "@types/jasmine": "latest", + "@types/node": "latest", + "codelyzer": "latest", + "jasmine-core": "latest", + "jasmine-spec-reporter": "latest", + "karma": "latest", + "karma-chrome-launcher": "latest", + "karma-coverage": "latest", + "karma-jasmine": "latest", + "karma-jasmine-html-reporter": "latest", + "protractor": "latest", + "ts-node": "latest", + "tslint": "latest", + "typescript": "~5.4.5" + } +} diff --git a/ClientApp/staff-db-ui/src/app/app-routing.module.ts b/ClientApp/staff-db-ui/src/app/app-routing.module.ts new file mode 100644 index 0000000..762d9f2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/app-routing.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule, PreloadAllModules } from '@angular/router'; +import { APP_PAGES } from '@app_consts'; +import { ACCOUNT_PAGE, Globals, LOGIN_PAGE } from '@app_core/services/globals'; + +ACCOUNT_PAGE.loadChildren = () => import('@app_modules/app-account/app-account.module').then(m => m.AppAccountModule); + +const routes: Routes = [ + ...APP_PAGES, + { + path: '', + redirectTo: '/' + LOGIN_PAGE.path, + pathMatch: 'full' + } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes, { useHash: true, preloadingStrategy: PreloadAllModules })], + exports: [RouterModule] +}) +export class AppRoutingModule { public globals: Globals; } diff --git a/ClientApp/staff-db-ui/src/app/app.component.html b/ClientApp/staff-db-ui/src/app/app.component.html new file mode 100644 index 0000000..705ccc1 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/app.component.html @@ -0,0 +1,2 @@ + + diff --git a/ClientApp/staff-db-ui/src/app/app.component.scss b/ClientApp/staff-db-ui/src/app/app.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/ClientApp/staff-db-ui/src/app/app.component.spec.ts b/ClientApp/staff-db-ui/src/app/app.component.spec.ts new file mode 100644 index 0000000..e0e2e4f --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/app.component.spec.ts @@ -0,0 +1,27 @@ +import { TestBed, async } from '@angular/core/testing'; +import { AppComponent } from './app.component'; +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + it('should create the app', async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + it(`should have as title 'staffdb'`, async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('ang-material'); + })); + it('should render title in a h1 tag', async(() => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to Angular!'); + })); +}); diff --git a/ClientApp/staff-db-ui/src/app/app.component.ts b/ClientApp/staff-db-ui/src/app/app.component.ts new file mode 100644 index 0000000..700881a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/app.component.ts @@ -0,0 +1,58 @@ +import { Component, inject, OnInit } from '@angular/core'; +import { SwUpdate } from '@angular/service-worker'; +import * as AppCnst from '@app_consts'; +import * as Cnst from '@app_core/consts'; +import * as Utils from '@app_core/utils'; +import { TranslateService } from '@ngx-translate/core'; +import * as AppModule from './app.module'; +import { ENVIRONMENT_TOKEN } from '@app_core/injection-tokens'; +import { Globals } from '@app_core/services/globals'; +import { RepositoryService } from '@app_core/services/http/repository.service'; +import { ServerInfoService } from '@app_core/services/serverinfo.service'; +import { LocaleService } from '@app_core/services/localization/locale.service'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) + + +export class AppComponent implements OnInit { + private environment = inject(ENVIRONMENT_TOKEN); + + constructor( + public globals: Globals, + public repository: RepositoryService, + public translate: TranslateService, + private serverInfoService: ServerInfoService, + private localeService: LocaleService, + private updateService: SwUpdate + + ) { + this.initLangCulture(); + globals.appTitle = AppCnst.APP_TITLE; + Utils.setIndexTitle(globals.appTitle); + globals.appTitleWithVersion = `${AppCnst.APP_TITLE} V.${this.environment.appVersion} (${this.environment.appBuild})`; + globals.appPages = AppCnst.APP_PAGES; + globals.mainPage = AppCnst.APP_PAGES[0]; + this.serverInfoService.defaultServerInfoVisible = false; + } + + + private initLangCulture() { + this.translate.addLangs(AppCnst.SUPPORTED_LANGUAGES); + + const languageFromBrowser: string = navigator.language.split('-')[0]; + const startLanguage: string = Utils.isLanguageSupported(languageFromBrowser, AppCnst.SUPPORTED_LANGUAGES, Cnst.SUPPORTED_LANGUAGES) ? languageFromBrowser : AppCnst.cnst_DefaultLanguage; + const startCulture: string = Utils.isCultureSupported(navigator.language, AppModule.SUPPORTED_CULTURES, Cnst.SUPPORTED_CULTURES) ? navigator.language : AppCnst.cnst_DefaultCulture; + + this.localeService.initLocaleLanguage(startCulture, startLanguage); + } + + + ngOnInit(): void { + this.updateService.checkForUpdate().then((res) => { if (res) { this.updateService.activateUpdate(); window.location.reload(); } }); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/app.module.ts b/ClientApp/staff-db-ui/src/app/app.module.ts new file mode 100644 index 0000000..dfd4540 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/app.module.ts @@ -0,0 +1,144 @@ +import { AppComponent } from './app.component'; +import { BrowserModule } from '@angular/platform-browser'; + +/* Routing */ +import { AppRoutingModule } from './app-routing.module'; + +/* Angular Material */ +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { AngularMaterialModule } from '@app_core/components/angular-material.module'; +import { APPICON4LIVE_TOKEN, APPICON4NAVBAR_TOKEN, APPICON4TEST_TOKEN, ENVIRONMENT_TOKEN, IENVIRONMENT, SUPPORTED_CULTURES_TOKEN, SUPPORTED_LANGUAGES_TOKEN } from '@app_core/injection-tokens'; +import { NgModule, CUSTOM_ELEMENTS_SCHEMA, Injectable } from '@angular/core'; + +/* FormsModule */ +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +/* Components */ +import { LayoutModule } from '@app_core/components/layout/layout.module'; +import { NgxSpinnerModule } from 'ngx-spinner'; + +/* data acess */ +import { HttpInterceptorService } from '@app_core/services/http/http-interceptor.service'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; + +/* Globals */ +import { ErrorStateMatcher, ShowOnDirtyErrorStateMatcher } from '@angular/material/core'; +import { DxFormModule, DxButtonModule, DxTemplateHost, DxTemplateModule, DxChartModule, DxDataGridModule } from 'devextreme-angular'; +import { NgxMaskDirective, NgxMaskPipe, optionsConfig, provideNgxMask } from 'ngx-mask'; +import { Router } from '@angular/router'; +import { ServiceWorkerModule } from '@angular/service-worker'; +import { MessageBoxModule } from '@app_core/components/message-box/message-box.module'; +import { ClipboardModule } from 'ngx-clipboard'; + +/* Localisaton */ +import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { LocaleProvider } from '@app_core/services/localization/locale.provider'; +import { HenselTranslateService } from '@app_core/services/localization/hensel-translate.service'; +import { registerLocaleData } from '@angular/common'; +import { loadMessages } from 'devextreme/localization'; + +import localeDe from '@angular/common/locales/de'; +import localeUs from '@angular/common/locales/en'; +import localeFr from '@angular/common/locales/fr'; +import localeGb from '@angular/common/locales/en-GB'; + +export const SUPPORTED_CULTURES = ['de-DE', 'en-GB', 'en-US', 'fr-FR']; +registerLocaleData(localeDe, 'de-DE'); +registerLocaleData(localeUs, 'en-US'); +registerLocaleData(localeFr, 'fr-FR'); +registerLocaleData(localeGb, 'en-GB'); + +import * as deMessages from 'devextreme/localization/messages/de.json'; +loadMessages(deMessages); + +// import { HammerGestureConfig, HAMMER_GESTURE_CONFIG, HammerModule } from '@angular/platform-browser'; +// AoT requires an exported function for factories +// export class MyHammerConfig extends HammerGestureConfig { +// // tslint:disable-next-line:no-angle-bracket-type-assertion +// overrides = { +// swipe: { direction: Hammer.DIRECTION_ALL }, +// }; +// } + +/* Sentry */ +import { APP_INITIALIZER, ErrorHandler } from '@angular/core'; +import * as Sentry from '@sentry/angular'; +import { SUPPORTED_LANGUAGES } from '@app_consts'; +import { TranslateLoaderProvider } from '@app_core/services/localization/translation-loader.provider'; +import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@app_core/components/angular-material-index'; + +/* important to use mask functionality */ +const maskConfig: optionsConfig = { + validation: false, +}; + + +declare const environment: IENVIRONMENT; +declare const appVersion: string; +declare const appBuild: string; +environment['appVersion'] = appVersion; +environment['appBuild'] = appBuild; + +@Injectable() +export class SentryErrorHandler implements ErrorHandler { + handleError(error) { + Sentry.captureException(error.originalError || error); + } +} + +@NgModule({ + declarations: [ + AppComponent, + ], + imports: [ + HttpClientModule, + BrowserModule, + BrowserAnimationsModule, + AngularMaterialModule, + ReactiveFormsModule, + FormsModule, + DxFormModule, + DxTemplateModule, + DxDataGridModule, + DxChartModule, + DxButtonModule, + MessageBoxModule, + ClipboardModule, + NgxSpinnerModule, + NgxMaskDirective, + NgxMaskPipe, + TranslateModule.forRoot({loader: TranslateLoaderProvider}), + ServiceWorkerModule.register('ngsw-worker.js', { + enabled: true, //environment.production, + // Register the ServiceWorker as soon as the application is stable + // or after 30 seconds (whichever comes first). + registrationStrategy: 'registerWhenStable:30000' + }), + LayoutModule, + AppRoutingModule, // must be the last!!! + ], + providers: [ + DxTemplateHost, + LocaleProvider, + { provide: ENVIRONMENT_TOKEN, useValue: environment }, + { provide: SUPPORTED_LANGUAGES_TOKEN, useValue: SUPPORTED_LANGUAGES}, + { provide: SUPPORTED_CULTURES_TOKEN, useValue: SUPPORTED_CULTURES}, + { provide: APPICON4TEST_TOKEN, useValue: 'assets/icons/develop/dhr-icon-48x48.png'}, + { provide: APPICON4LIVE_TOKEN, useValue: 'assets/icons/production/dhr-icon-48x48.png'}, + { provide: APPICON4NAVBAR_TOKEN, useValue: 'assets/icons/main_48x48.png'}, + { provide: TranslateService, useClass: HenselTranslateService }, + { provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorService, multi: true }, + { provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { floatLabel: 'auto' } }, + { provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher }, + /* Sentry */ + { provide: ErrorHandler, useClass: SentryErrorHandler/*, useValue: Sentry.createErrorHandler({showDialog: false, })*/ }, + { provide: Sentry.TraceService, deps: [Router] }, + { provide: APP_INITIALIZER, useFactory: () => () => {}, deps: [Sentry.TraceService], multi: true }, + provideNgxMask(maskConfig) + ], + bootstrap: [AppComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], +}) + + +export class AppModule { } diff --git a/ClientApp/staff-db-ui/src/app/modules/app-account/app-account-routing.module.ts b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account-routing.module.ts new file mode 100644 index 0000000..466013e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { AppAccountComponent } from './app-account.component'; +import { AuthGuard } from '@app_core/services/authguard'; + + +const routes: Routes = [ + { + path: '', + component: AppAccountComponent, + canActivate: [AuthGuard] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AppAccountRoutingModule { } diff --git a/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.html b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.html new file mode 100644 index 0000000..0c07ff7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.html @@ -0,0 +1,22 @@ + +
+
+ + + +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.scss b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.scss new file mode 100644 index 0000000..f8698ef --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.scss @@ -0,0 +1,9 @@ +.input-webapp{ + float: left; +} + + +.btn{ + margin-left: 10px; + margin-top: 8px; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.ts b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.ts new file mode 100644 index 0000000..e8d66cf --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.component.ts @@ -0,0 +1,16 @@ +import { Component, inject } from '@angular/core'; +import { AccountComponent } from '@app_core/components/account/account.component'; +import { AppDataService } from '@app_services/app.data.service'; + +@Component({ + selector: 'app-account-ext', + templateUrl: 'app-account.component.html', + styleUrls: ['app-account.component.scss'] +}) + +export class AppAccountComponent extends AccountComponent { + public appDataService = inject(AppDataService); + + onClick() { + } +} diff --git a/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.module.ts b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.module.ts new file mode 100644 index 0000000..a72ec7c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/app-account/app-account.module.ts @@ -0,0 +1,29 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { TranslateModule } from '@ngx-translate/core'; +import { DxDataGridModule } from 'devextreme-angular'; +import { DxoSearchPanelModule } from 'devextreme-angular/ui/nested'; +import { AppAccountRoutingModule } from './app-account-routing.module'; +import { AppAccountComponent } from './app-account.component'; +import { AccountModule } from '@app_core/components/account/account.module'; +import { AngularMaterialModule } from '@app_core/components/angular-material.module'; +import { HenselSelectionComponent } from '@app_core/components/hensel-selection/hensel-selection.component'; + + +@NgModule({ + declarations: [AppAccountComponent], + imports: [ + CommonModule, + AppAccountRoutingModule, //must be earlier AccountModule + AccountModule, + AngularMaterialModule, + ReactiveFormsModule, + FormsModule, + DxDataGridModule, + DxoSearchPanelModule, + HenselSelectionComponent, + TranslateModule + ] +}) +export class AppAccountModule { } diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-data.service.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-data.service.ts new file mode 100644 index 0000000..d9fdaa8 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-data.service.ts @@ -0,0 +1,181 @@ +import { Injectable } from '@angular/core'; +import { cnst_LoadedEntitiesExpiresInMs, EN_AppEntities, EN_AppPages, EN_HttpQueriesCount4Page } from '@app_consts'; +import { CoreUser } from '@app_core/models/coreuser'; +import { RepositoryService } from '@app_core/services/http/repository.service'; +import { CorePageService } from '@app_core/services/page.service'; +import { Department, DepartmentFilter } from '@app_models/basedata/department'; +import { DocumentArtToDepartment } from '@app_models/documentart-to-department'; +import { Employee } from '@app_models/employee'; +import { User } from '@app_models/user'; +import { WindreamIndex } from '@app_models/windream-index'; +import { WindreamIndexToWindreamSearchToDepartment } from '@app_models/windream-index-to-windream-search-to-department'; +import { ClientIdFilter, WindreamSearch } from '@app_models/windream-search'; +import { WindreamSearchItem } from '@app_models/windream-search-item'; +import { WindreamSearchItemToWindreamSearchToDepartment } from '@app_models/windream-search-item-to-windream-search-to-department'; +import { WindreamSearchToDepartment, WindreamSearchToDepartmentFilter } from '@app_models/windream-search-to-department'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; + + +@Injectable({ providedIn: 'root' }) + +export class DepartmentDataService extends CorePageService { + protected appPage: EN_AppPages = EN_AppPages.Department; + protected loadImedeately: boolean = true; //load on pening the page + protected get appPageNoQueries() { return EN_HttpQueriesCount4Page.Department; } + + // --- running data + departmentFilter: DepartmentFilter = new DepartmentFilter('DepartmentFullFilter'); + departmentList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(Department, 'Abteilungsliste', EN_AppEntities.Department); + + departmentDetails: AppBaseEntityWrapper; + windreamSearchToDepartmentDetails: AppBaseEntityWrapper; + // tslint:disable-next-line: max-line-length + windreamSearchToDepartmentList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(WindreamSearchToDepartment, 'Windream Suche Kacheln', EN_AppEntities.WindreamSearchToDepartment); + windreamSearchToDepartmentFilter: WindreamSearchToDepartmentFilter = new WindreamSearchToDepartmentFilter('DepartmentFilter'); + // tslint:disable-next-line: max-line-length + windreamSearchItemToWindreamSearchToDepartmentList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(WindreamSearchItemToWindreamSearchToDepartment, 'Windream Suchbausteine', EN_AppEntities.WindreamSearchItemToWindreamSearchToDepartment); + windreamSearchItemToWindreamSearchToDepartmentFilter: WindreamSearchToDepartmentFilter = new WindreamSearchToDepartmentFilter('WindreamSearchToDepartmentFilter'); + windreamSearchItemToWindreamSearchToDepartmentDetails: AppBaseEntityWrapper; + + windreamSearchItemList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(WindreamSearchItem, 'windream suche kacheln attribute', EN_AppEntities.WindreamSearchItem); + windreamIndexToWindreamSearchToDepartmentDetails: AppBaseEntityWrapper; + // tslint:disable-next-line: max-line-length + windreamIndexToWindreamSearchToDepartmentList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(WindreamIndexToWindreamSearchToDepartment, 'Ausgabespalten für Windream Suche', EN_AppEntities.WindreamIndexToWindreamSearchToDepartment); + windreamIndexToWindreamSearchToDepartmentFilter: WindreamSearchToDepartmentFilter = new WindreamSearchToDepartmentFilter('WindreamSearchToDepartmentFilter'); + + windreamSearchList: AppBaseEntityListWrapper = + new AppBaseEntityListWrapper(WindreamSearch, 'Windream Suche Kacheln', EN_AppEntities.WindreamSearch); + + clientIdFilter: ClientIdFilter = new ClientIdFilter('ClientIdFilter'); + + windreamIndexList: AppBaseEntityListWrapper = + new AppBaseEntityListWrapper(WindreamIndex, 'Windream Index', EN_AppEntities.WindreamIndex); + + documentArtToDepartmentListFilter: DepartmentFilter = new DepartmentFilter('DepartmentFilter'); + + documentArtToDepartmentList: AppBaseEntityListWrapper = + new AppBaseEntityListWrapper(DocumentArtToDepartment, 'Dokumentartenliste für Department', EN_AppEntities.DocumentArtToDepartment); + + employeeList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(Employee, 'mitarbeiter', EN_AppEntities.Employee + '/all'); + + selectedDocumentarts: number[] = []; + clpbrdWindreamOutColHint1: string; + clpbrdWindreamOutColHints: string; + clpbrdWindreamOutColList: WindreamIndexToWindreamSearchToDepartment[] = []; + + clpbrdWindreamSearchItemHint1: string; + clpbrdWindreamSearchItemHints: string; + clpbrdWindreamSearchItemList: WindreamSearchItemToWindreamSearchToDepartment[] = []; + + constructor( + private repositoryService: RepositoryService, + ) { + super(); + + this.departmentList.focusedCallBack = this.focusCallBack.bind(this); + this.departmentList.filter = this.departmentFilter; + this.departmentDetails = this.departmentList.createFocusedShadowEntity(AppBaseEntityWrapper.EN_ViewMode); + this.departmentDetails.loadedDataExpiresInMs = cnst_LoadedEntitiesExpiresInMs; + this.baseEntityWrapperWaitLoading = this.departmentDetails; + this.activateRouting4EntityList(this.departmentList); //we are using routing + + this.windreamSearchToDepartmentList.filter = this.windreamSearchToDepartmentFilter; + this.windreamSearchToDepartmentDetails = this.windreamSearchToDepartmentList.createFocusedShadowEntity(); + this.windreamSearchToDepartmentDetails.dontLoadEntity = true; + this.windreamSearchToDepartmentDetails.beforeNewCallBack = this.prepareSearchToDepartment.bind(this); + + this.windreamIndexToWindreamSearchToDepartmentList.filter = this.windreamIndexToWindreamSearchToDepartmentFilter; + this.windreamIndexToWindreamSearchToDepartmentDetails = this.windreamIndexToWindreamSearchToDepartmentList.createFocusedShadowEntity(); + this.windreamIndexToWindreamSearchToDepartmentDetails.dontLoadEntity = true; + + this.windreamSearchItemToWindreamSearchToDepartmentList.filter = this.windreamSearchItemToWindreamSearchToDepartmentFilter; + this.windreamSearchItemToWindreamSearchToDepartmentDetails = this.windreamSearchItemToWindreamSearchToDepartmentList.createFocusedShadowEntity(); + this.windreamSearchItemToWindreamSearchToDepartmentDetails.dontLoadEntity = true; + + this.windreamSearchList.filter = this.clientIdFilter; + this.windreamIndexList.filter = this.clientIdFilter; + this.windreamSearchItemList.filter = this.clientIdFilter; + this.documentArtToDepartmentList.filter = this.documentArtToDepartmentListFilter; + + + this.departmentDetails.detailItems.register(this.windreamSearchToDepartmentList, null, 'departmentId'); + this.departmentDetails.detailItems.register(this.documentArtToDepartmentList, null, 'departmentId', (docarts: DocumentArtToDepartment[]) => { + this.selectedDocumentarts = docarts.map(docart => docart.documentArtId); + }); + this.windreamSearchToDepartmentDetails.detailItems.register(this.windreamIndexToWindreamSearchToDepartmentList, null, 'windreamSearchToDepartmentId'); + this.windreamSearchToDepartmentDetails.detailItems.register(this.windreamSearchItemToWindreamSearchToDepartmentList, null, 'windreamSearchToDepartmentId'); + + this.loadBaseData(); + this.init(); + } + + + loadData() { + super.loadData(); + this.departmentList.load(null, null, () => this.pageLoadingService.updatePageLoadedCounters(this.appPage)); + } + + public loadBaseData() { + super.loadBaseData(this.appPage, 1); + this.employeeList.load(null, null, () => this.pageLoadingService.updatePageLoadedCounters(this.appPage)); + } + + public focusCallBack(focusedItem: Department) { + this.clientIdFilter.clientId = focusedItem?.clientId; + } + + public clearData() { + super.clearData(); + this.departmentFilter.filterReset(); + this.departmentList.clear(); + } + + protected onLoggedInOut(user: CoreUser) { + this.userChanged(new User(user)); + super.onLoggedInOut(user); + } + + private userChanged(user: User) { + if (this.authService.isLoggedIn()) { + this.departmentDetails.canNew = user.isMaster; + this.departmentDetails.canEdit = this.departmentDetails.canNew; + this.departmentDetails.canDelete = this.departmentDetails.canNew; + } + } + + moveUpDown(direction: number, + list: + AppBaseEntityListWrapper + | AppBaseEntityListWrapper + | AppBaseEntityListWrapper + ) { + const curItemIndex: number = list.focusedItemIndex; + if (!(direction < 0 && curItemIndex === 0 || direction > 0 && curItemIndex === list.items.length)) { + const targetItem = list.items[curItemIndex + direction]; + const targetSeq: number = targetItem.seq; + const currentItem = list.focusedItem; + targetItem.seq = currentItem.seq; + currentItem.seq = targetSeq; + targetItem.entityChanged = true; + currentItem.entityChanged = true; + + targetItem.save(this.repositoryService, null, null, null); + currentItem.save(this.repositoryService, null, null, null); + this.sortBySeq(list.items); + } + } + + public sortBySeq(list: WindreamSearchToDepartment[] | WindreamSearchItemToWindreamSearchToDepartment[] | WindreamIndexToWindreamSearchToDepartment[]) { + list.sort((fp1, fp2) => (fp1.seq - fp2.seq)); + } + + + prepareSearchToDepartment(item: WindreamSearchToDepartment) { + const maxSeq = this.windreamSearchToDepartmentList.items.reduce((max: number, _index: WindreamSearchToDepartment) => max > _index.seq ? max : _index.seq, 0); + item.seq = maxSeq + 1; + item.isActive = true; + } + + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.html new file mode 100644 index 0000000..ba9d181 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.html @@ -0,0 +1,100 @@ +
+ + + + + + + + + + + + + + + + + + + + Virtual + +
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.scss new file mode 100644 index 0000000..e0c9031 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.scss @@ -0,0 +1,52 @@ +.departmentDetailsContent{ +// z-index: 10; + // position: relative; //otherwise z-index is not working + padding: 0 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-column-gap: 8px; + grid-template-columns: repeat(2, minmax(1px, 1fr)); // column relationship + grid-template-rows: repeat(5, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships + grid-template-areas: + "input-departmentName input-cost-centre" + "input-departmentType input-headofDepartmentId" + "input-executiveDirectorId input-managingDirectorId" + "input-departmentNameFolder input-adGroupDepartmentName" + "input-clientId input-isVirtual" + ; +} + + +.input-departmentName{ + grid-area: input-departmentName; +} +.input-cost-centre{ + grid-area: input-cost-centre; +} +.input-departmentType{ + grid-area: input-departmentType; +} +.input-headofDepartmentId{ + grid-area: input-headofDepartmentId; +} +.input-executiveDirectorId{ + grid-area: input-executiveDirectorId; +} +.input-managingDirectorId{ + grid-area: input-managingDirectorId; +} +.input-departmentNameFolder{ + grid-area: input-departmentNameFolder; +} +.input-adGroupDepartmentName{ + grid-area: input-adGroupDepartmentName; +} +.input-clientId{ + grid-area: input-clientId; +} +.input-isVirtual{ + grid-area: input-isVirtual; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.spec.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.spec.ts new file mode 100644 index 0000000..d663dca --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DepartmentContentComponent } from './department-content.component'; + +describe('DepartmentContentComponent', () => { + let component: DepartmentContentComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DepartmentContentComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DepartmentContentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.ts new file mode 100644 index 0000000..a39c835 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-content/department-content.component.ts @@ -0,0 +1,53 @@ +import { Component, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core'; +import { Department } from '@app_models/basedata/department'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import { CostCentre } from '@app_models/basedata/cost-centre'; +import { Employee } from '@app_models/employee'; +import { EmployeeDataService } from '@app_modules/employee/employee-data.service'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; +import { NgForm } from '@angular/forms'; + +@Component({ + selector: 'app-department-content', + templateUrl: './department-content.component.html', + styleUrls: ['./department-content.component.scss'] +}) +export class DepartmentContentComponent implements OnInit, AfterViewInit { + @ViewChild('detailForm') detailForm: NgForm; + @Input() departmentDetails: AppBaseEntityWrapper; + + + public get department(): Department { + return this.departmentDetails.entity; + } + + + public get employeeList(): Employee[] { + return this.departmentService.employeeList.items; + } + + + + public get costCentreList(): CostCentre[] { + return this.appDataService.costCentreList.items; + } + + + constructor( + private appDataService: AppDataService, + private departmentService: DepartmentDataService) { } + + ngOnInit() { + } + + ngAfterViewInit(): void { + this.departmentDetails.detailForm = this.detailForm; + } + + depNameWasChanged() { + if (!this.department.departmentName) return; + if (!this.department.departmentNameFolder) this.department.departmentNameFolder = this.department.departmentName; + if (!this.department.adGroupDepartmentName) this.department.adGroupDepartmentName = this.department.departmentName; + } +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.html new file mode 100644 index 0000000..e7ecd6d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.html @@ -0,0 +1,59 @@ +
+ + + + +
+
+ + + + + +
+
+ + + + + + + + + + + +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.scss new file mode 100644 index 0000000..3820531 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.scss @@ -0,0 +1,46 @@ +.DepartmentDetails { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-template-rows: auto repeat(1, minmax(1px, 250px)); // row relationships + grid-template-columns: minmax(1px, 0.7fr) minmax(1px, 0.7fr) minmax(1px, 0.5fr) minmax(1px, 0.5fr) minmax(1px, 1fr); // column relationship + grid-row-gap: 6px; + grid-column-gap: 10px; + grid-template-areas: + 'toolbar toolbar toolbar toolbar toolbar' + 'detail documentArtList windreamSearchList windreamSearchItemList windreamIndexList'; + z-index: 10; + position: relative; //otherwise z-index is not working +} +.WindreamSearchItemList{ + grid-area: windreamSearchItemList; +} + +.WindreamIndexList{ + grid-area: windreamIndexList; +} +.WindreamSearchList{ + grid-area: windreamSearchList; +} +.DetailsContent { + grid-area: detail; +} +.DocumentArtList { + grid-area: documentArtList; +} + +.abstand { + margin-right: 1px !important; +} + +.toolbar { + grid-area: toolbar; +} + +.card { + padding: 12px; + margin: 2px 2px 2px 2px; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.ts new file mode 100644 index 0000000..d8f5228 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-detail.component.ts @@ -0,0 +1,109 @@ +import { Component, OnInit, Input, ChangeDetectorRef, DoCheck, ChangeDetectionStrategy, Output, EventEmitter, ViewChild, ElementRef, AfterViewInit, HostListener } from '@angular/core'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { DepartmentDataService } from '../department-data.service'; +import { WindreamSearchToDepartment } from '@app_models/windream-search-to-department'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { WindreamIndexToWindreamSearchToDepartment } from '@app_models/windream-index-to-windream-search-to-department'; +import { Department } from '@app_models/basedata/department'; +import { WindreamSearchItemToWindreamSearchToDepartment } from '@app_models/windream-search-item-to-windream-search-to-department'; +import { WindreamSearchItem } from '@app_models/windream-search-item'; +import { NgForm } from '@angular/forms'; +import { reduce } from 'rxjs/operators'; +import { AuthorizeService } from '@app_core/services/authorize.service'; +import { PageLoadingService } from '@app_core/services/pageloading.service'; +import { EN_EntityBeforeSaveCallBackResults } from '@app_core/consts'; +import { LoginPopupComponent } from '@app_core/components/login/login-popup/login-popup.component'; + +@Component({ + selector: 'app-department-detail', + templateUrl: './department-detail.component.html', + styleUrls: ['./department-detail.component.scss'], +}) +export class DepartmentDetailComponent implements AfterViewInit { + + @ViewChild('detailForm') detailForm: NgForm; + + @Input() public departmentDetails: AppBaseEntityWrapper; + + public get windreamSearchToDepartmentDetails(): AppBaseEntityWrapper { + return this.departmentDataService.windreamSearchToDepartmentDetails; + } + + constructor( + public departmentDataService: DepartmentDataService, + public authorizeService: AuthorizeService, + private pageLoadingService: PageLoadingService, + ) { + } + public get windreamSearchList(): AppBaseEntityListWrapper { + return this.departmentDataService.windreamSearchToDepartmentList; + } + public get windreamSearchDetails(): AppBaseEntityWrapper { + return this.departmentDataService.windreamSearchToDepartmentDetails; + } + + + public get windreamSearchItemToWindreamSearchToDepartmentList(): AppBaseEntityListWrapper { + return this.departmentDataService.windreamSearchItemToWindreamSearchToDepartmentList; + } + public get windreamSearchItemToWindreamSearchToDepartmentDetails(): AppBaseEntityWrapper { + return this.departmentDataService.windreamSearchItemToWindreamSearchToDepartmentDetails; + } + public get windreamSearchItemList(): AppBaseEntityListWrapper { + return this.departmentDataService.windreamSearchItemList; + } + + + public get windreamIndexList(): AppBaseEntityListWrapper { + return this.departmentDataService.windreamIndexToWindreamSearchToDepartmentList; + } + public get windreamIndexDetails(): AppBaseEntityWrapper { + return this.departmentDataService.windreamIndexToWindreamSearchToDepartmentDetails; + } + + + public get focusedItem(): Department { + return this.departmentDetails.entity; + } + + ngAfterViewInit(): void { + this.departmentDetails.beforeNewCallBack = this.newDepartmentInit.bind(this); + this.departmentDetails.beforeSaveCallBack = this.beforeSaveDepartment.bind(this); + } + + newDepartmentInit(department: Department) { + this.departmentDataService.selectedDocumentarts = []; + department.departmentTypeId = 1; + department.clientId = 24110; + } + + async beforeSaveDepartment(department: Department): Promise { + const maxId: number = this.departmentDataService.departmentList.items.reduce((max, currentItem) => (currentItem.entityId > max ? currentItem.entityId : max), 0); + if (department.isNew()) department.departmentId = -(maxId + 1); + this.departmentDataService.documentArtToDepartmentList.match2KeysArray(department, 'departmentId', this.departmentDataService.selectedDocumentarts, 'documentArtId'); + return EN_EntityBeforeSaveCallBackResults.Ok_Continue; + } + + + public save = () => { //because of calling as callback of cancel + this.pageLoadingService.startSpinner(); + this.departmentDetails.save((department: Department) => this.afterSave(department), null, () => this.pageLoadingService.hideSpinner()); + } + + afterSave(department: Department) { + // this.departmentDetails.loadDetails(this.catalogDataService.departmentCategoryList); + + } + + public cancel = () => { + // this.setCurrentMaster4Subdepartment = null; + this.departmentDetails.cancelWithSave(this.save); + } + + + @HostListener('window:keydown', ['$event']) + keyboardInput(event: any) { + return LoginPopupComponent.LOGIN_IS_SHOWN || this.departmentDetails.shortcutsHandler(event, this.save, this.cancel); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.html new file mode 100644 index 0000000..cd7a5fd --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.html @@ -0,0 +1,21 @@ +
+ + + +
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.scss new file mode 100644 index 0000000..05fa790 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.scss @@ -0,0 +1,19 @@ +.department-documentart { + width: 100%; + height: 100%; + display: grid; + grid-template-columns: minmax(0, 1fr); // column relationship + grid-template-rows: 0 minmax(1px, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships + grid-template-areas: "label" "attributes"; +} + + +.documentart { + grid-area: attributes; + height: 100%; + width: 100%; +} + +.label { + grid-area: label; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.ts new file mode 100644 index 0000000..b8879e1 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-documentart/department-documentart.component.ts @@ -0,0 +1,28 @@ + + +import { Component, OnInit, Input } from '@angular/core'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import { Department } from '@app_models/basedata/department'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; + +@Component({ + selector: 'app-department-documentart', + templateUrl: './department-documentart.component.html', + styleUrls: ['./department-documentart.component.scss'] +}) + +export class DepartmentDocumentartsComponent implements OnInit { + + @Input() public departmentDetails: AppBaseEntityWrapper; + + constructor( + public appDataService: AppDataService, + public departmentDataService: DepartmentDataService, + ) { + } + + ngOnInit() { + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.html new file mode 100644 index 0000000..2234b0c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.html @@ -0,0 +1,35 @@ +
+ +

{{description}} - {{keyItemName}}

+ + +
+ + +
+ + + + +
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.scss new file mode 100644 index 0000000..7eef6e2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.scss @@ -0,0 +1,24 @@ +@import 'popup-base.component'; + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid: ; + height: 100%; // 100% view height + grid-template-rows: auto auto; // row relationships + grid-template-columns: repeat(2, minmax(0, 1fr)); // column relationship + grid-column-gap: 15px; + grid-row-gap: 15px; + grid-template-areas: + 'input-windreamSearch .' + 'buttons buttons' +} + +.input-windreamSearch { + grid-area: input-windreamSearch; +} + +.input-seq { + grid-area: input-seq; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.ts new file mode 100644 index 0000000..b2c00ef --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component.ts @@ -0,0 +1,57 @@ +import { Component, ViewChild } from '@angular/core'; +import { HenselSelectionComponent } from '@app_core/components/hensel-selection/hensel-selection.component'; +import { PopupBaseComponent } from '@app_core/components/popup-base/popup-base.component'; +import { WindreamIndex } from '@app_models/windream-index'; +import { WindreamIndexToWindreamSearchToDepartment } from '@app_models/windream-index-to-windream-search-to-department'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; + +@Component({ + selector: 'app-department-windream-index-popupedit', + templateUrl: './department-windream-index-popupedit.component.html', + styleUrls: ['./department-windream-index-popupedit.component.scss'] +}) +export class DepartmentWindreamIndexPopupeditComponent extends PopupBaseComponent { + + public windreamIndexIds: number[] = []; + @ViewChild('input_windreamIndex') input_windreamIndex: HenselSelectionComponent; + + constructor( + public departmentDataService: DepartmentDataService, + ) { + super(); + this.departmentDataService.windreamIndexList.load(); + } + + + public get windreamIndexList(): WindreamIndex[] { + return this.departmentDataService.windreamIndexList.items; + } + + public get focusedItem(): WindreamIndexToWindreamSearchToDepartment { + return (this._focusedItem); + } + + getNotUsedwindreamIndexes = (dep: WindreamIndex) => { + return !this.list.items.find((item) => item['windreamIndexId'] === dep.entityId); + } + + save = () => { + let maxSeq = this.list.items.reduce((max: number, _index: WindreamIndexToWindreamSearchToDepartment) => max > _index.seq ? max : _index.seq, 0); + // for each selected WindreamIndexIds + this.windreamIndexIds.forEach(windreamIndexId => { + // create new WindreamIndexMap Item + const newWindreamIndex = new WindreamIndexToWindreamSearchToDepartment(); + // calculate highest seq + newWindreamIndex.seq = ++maxSeq; + newWindreamIndex.windreamIndexId = windreamIndexId; + newWindreamIndex.windreamSearchToDepartmentId = this.focusedItem.windreamSearchToDepartmentId; + newWindreamIndex.entityChanged = true; + this.list.items.push(newWindreamIndex); + }); + this.list.save(() => { + this.baseEntityWrapper.resetEditMode(); + this.close(true); + }); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.html new file mode 100644 index 0000000..c71a7da --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.html @@ -0,0 +1,115 @@ +
+ +
+
+
+ + + + + + + +
+
+
+ + + + --> + + + + + + + + + + + + + + + + +
+ {{cell.value | number:'1.0-0':culture}} +
+
+ {{cell.value | number:'1.1-1':culture}} +
+
+ {{cell.value | number:'1.2-2':culture}} +
+
+ {{cell.value | number:'1.3-3':culture}} +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.scss new file mode 100644 index 0000000..192008c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.scss @@ -0,0 +1,23 @@ +.department-windreamsearch-windreamindex{ + width: 100%; + height: 100%; + display: grid; + grid-template-columns: auto minmax(0, 1fr); // column relationship + grid-template-rows: auto minmax(1px, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships + grid-template-areas: "label label" "toolbar grid"; +} + +.grid { + grid-area: grid; + height: 100%; + width: 100%; +} + +.label { + grid-area: label; + // padding-bottom: 6px; +} + +.toolbar { + grid-area: toolbar; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.spec.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.spec.ts new file mode 100644 index 0000000..1e3e321 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DepartmentWindreamIndexComponent } from './department-windream-index.component'; + +describe('DepartmentWindreamIndexComponent', () => { + let component: DepartmentWindreamIndexComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DepartmentWindreamIndexComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DepartmentWindreamIndexComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.ts new file mode 100644 index 0000000..6d0d1bb --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-index/department-windream-index.component.ts @@ -0,0 +1,101 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Department } from '@app_models/basedata/department'; +import { WindreamIndexToWindreamSearchToDepartment } from '@app_models/windream-index-to-windream-search-to-department'; +import { WindreamSearchToDepartment } from '@app_models/windream-search-to-department'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { DepartmentWindreamIndexPopupeditComponent } from './department-windream-index-popupedit/department-windream-index-popupedit.component'; +import { ColumnConfigList } from '@app_core/components/grid-config/columnconfiglist'; +import { MatDialogService } from '@app_core/services/mat-dialog.service'; +import { LocaleService } from '@app_core/services/localization/locale.service'; +import { Globals } from '@app_core/services/globals'; +import { ColumnConfig, EN_SortOrder } from '@app_core/components/grid-config/columnconfig'; + +@Component({ + selector: 'app-department-windream-index', + templateUrl: './department-windream-index.component.html', + styleUrls: ['./department-windream-index.component.scss'] +}) +export class DepartmentWindreamIndexComponent implements OnInit { + @Input() windreamIndexList: AppBaseEntityListWrapper; + @Input() windreamIndexDetails: AppBaseEntityWrapper; + @Input() windreamSearchToDepartmentDetails: AppBaseEntityWrapper; + @Input() departmentDetails: AppBaseEntityWrapper; + + + public get windreamSearchName(): string { + return this.windreamSearchToDepartmentDetails.entity.windreamSearchName; + } + + + public columnConfigList: ColumnConfigList = new ColumnConfigList(); + constructor( + private dialog: MatDialogService, + public departmentDataService: DepartmentDataService, + public localeService: LocaleService, + public globals: Globals, + ) { + } + + ngOnInit() { + this.initColumns(); + } + initColumns() { + let col: ColumnConfig; + col = this.columnConfigList.add('Seq.', 'seq', 2); + col.sortIndex = 0; + col.sortOrder = EN_SortOrder.asc; + col = this.columnConfigList.add('Ausgabespalte', 'objectTypeAttributeSzName', 15); + col = this.columnConfigList.add('Indexname', 'attributeSzColumnName', 15); + this.columnConfigList.recalcWidth(); + } + + addItem() { + this.windreamIndexList.focusedEntityShadowed.new(); + this.windreamIndexList.focusedEntityShadowed.entity.windreamSearchToDepartmentId = this.windreamSearchToDepartmentDetails.entityId; + this.openPopupDialog(this.windreamIndexList.focusedEntityShadowed); + } + + public openPopupDialog(editEntity: AppBaseEntityWrapper) { + this.windreamSearchToDepartmentDetails.keyDownListenerStopped = true; + this.dialog.openDialog(DepartmentWindreamIndexPopupeditComponent, { + baseEntityWrapper: editEntity, + keyItemName: this.windreamSearchToDepartmentDetails.entity.windreamSearchName, + readOnly: !this.departmentDetails.inEditMode, + description: editEntity.entity.entitytitle + (editEntity.entity.entityId === 0 ? ' zuweisen' : ' bearbeiten '), + list: this.windreamIndexList, + }, true, () => this.windreamSearchToDepartmentDetails.keyDownListenerStopped = false); + } + + + private outColKeyItemDescription() { + return `Ausgabespalten für "${this.windreamSearchToDepartmentDetails.entity.windreamSearchName}" Abteilung "${this.departmentDetails.entity.departmentName}"`; + + } + + public copyWindreamOutCols() { + this.departmentDataService.clpbrdWindreamOutColList = this.windreamIndexList.items.slice(); + this.departmentDataService.clpbrdWindreamOutColHint1 = this.outColKeyItemDescription(); + this.departmentDataService.clpbrdWindreamOutColHints = ''; + this.departmentDataService.clpbrdWindreamOutColList.forEach(col => + this.departmentDataService.clpbrdWindreamOutColHints += '\n' + col.objectTypeAttributeSzName); + } + + + public pasteWindreamOutCols() { + this.windreamIndexDetails.confirmMessageBoxYesNo('Übernahme von ' + this.departmentDataService.clpbrdWindreamOutColHint1, this.outColKeyItemDescription() + ' werden mit ' + this.departmentDataService.clpbrdWindreamOutColHint1 + ' überschrieben. Sind Sie sicher?', + () => { + this.windreamIndexList.deleteAll(); + this.windreamIndexList.items.push(...this.departmentDataService.clpbrdWindreamOutColList); + this.windreamIndexList.items.forEach(el => { + el.entityId = 0; + el.entityChanged = true; + el.windreamSearchToDepartmentId = this.windreamSearchToDepartmentDetails.entityId; + }); + this.windreamIndexList.save(); + } + ); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.html new file mode 100644 index 0000000..ccfc9ea --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.html @@ -0,0 +1,34 @@ +
+ +

{{description}} - {{keyItemName}}

+ + +
+ + +
+ + + +
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.scss new file mode 100644 index 0000000..7eef6e2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.scss @@ -0,0 +1,24 @@ +@import 'popup-base.component'; + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid: ; + height: 100%; // 100% view height + grid-template-rows: auto auto; // row relationships + grid-template-columns: repeat(2, minmax(0, 1fr)); // column relationship + grid-column-gap: 15px; + grid-row-gap: 15px; + grid-template-areas: + 'input-windreamSearch .' + 'buttons buttons' +} + +.input-windreamSearch { + grid-area: input-windreamSearch; +} + +.input-seq { + grid-area: input-seq; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.ts new file mode 100644 index 0000000..a715795 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component.ts @@ -0,0 +1,57 @@ +import { Component } from '@angular/core'; +import { PopupBaseComponent } from '@app_core/components/popup-base/popup-base.component'; +import { WindreamSearchItem } from '@app_models/windream-search-item'; +import { WindreamSearchItemToWindreamSearchToDepartment } from '@app_models/windream-search-item-to-windream-search-to-department'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; + +@Component({ + selector: 'app-department-windream-search-item-popupedit', + templateUrl: './department-windream-search-item-popupedit.component.html', + styleUrls: ['./department-windream-search-item-popupedit.component.scss'] +}) +export class DepartmentWindreamSearchItemPopupeditComponent extends PopupBaseComponent { + + public windreamSearchItemIds: number[] = []; + + constructor( + public departmentDataService: DepartmentDataService, + ) { + super(); + this.departmentDataService.windreamSearchItemList.load(); + this.getNotUsedwindreamSearchItems = this.getNotUsedwindreamSearchItems.bind(this); + } + + + public get windreamSearchItemList(): WindreamSearchItem[] { + return this.departmentDataService.windreamSearchItemList.items; + } + + public get focusedItem(): WindreamSearchItemToWindreamSearchToDepartment { + return (this._focusedItem); + } + + getNotUsedwindreamSearchItems(dep: WindreamSearchItem) { + return !this.list.items.find((item) => item['windreamSearchItemId'] === dep.entityId); + } + + + save = () => { + let maxSeq = this.list.items.reduce((max: number, _index: WindreamSearchItemToWindreamSearchToDepartment) => max > _index.seq ? max : _index.seq, 0); + // for each selected WindreamIndexIds + this.windreamSearchItemIds.forEach(windreamSearchItemId => { + // create new WindreamIndexMap Item + const newWindreamItem = new WindreamSearchItemToWindreamSearchToDepartment(); + // calculate highest seq + newWindreamItem.seq = ++maxSeq; + newWindreamItem.windreamSearchItemId = windreamSearchItemId; + newWindreamItem.windreamSearchToDepartmentId = this.focusedItem.windreamSearchToDepartmentId; + newWindreamItem.entityChanged = true; + this.list.items.push(newWindreamItem); + }); + this.list.save(() => { + this.baseEntityWrapper.resetEditMode(); + this.close(true); + }); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.html new file mode 100644 index 0000000..17128fb --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.html @@ -0,0 +1,117 @@ +
+ +
+
+
+ + + + + + + +
+
+
+ + + + --> + + + + + + + + + + + + + + + + +
+ {{cell.value | number:'1.0-0':culture}} +
+
+ {{cell.value | number:'1.1-1':culture}} +
+
+ {{cell.value | number:'1.2-2':culture}} +
+
+ {{cell.value | number:'1.3-3':culture}} +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.scss new file mode 100644 index 0000000..192008c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.scss @@ -0,0 +1,23 @@ +.department-windreamsearch-windreamindex{ + width: 100%; + height: 100%; + display: grid; + grid-template-columns: auto minmax(0, 1fr); // column relationship + grid-template-rows: auto minmax(1px, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships + grid-template-areas: "label label" "toolbar grid"; +} + +.grid { + grid-area: grid; + height: 100%; + width: 100%; +} + +.label { + grid-area: label; + // padding-bottom: 6px; +} + +.toolbar { + grid-area: toolbar; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.spec.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.spec.ts new file mode 100644 index 0000000..030ac44 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { DepartmentWindreamSearchItemComponent } from './department-windream-search-item.component'; + + +describe('DepartmentWindreamIndexComponent', () => { + let component: DepartmentWindreamSearchItemComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [DepartmentWindreamSearchItemComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DepartmentWindreamSearchItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.ts new file mode 100644 index 0000000..ed9faf3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search-item/department-windream-search-item.component.ts @@ -0,0 +1,94 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Department } from '@app_models/basedata/department'; +import { WindreamSearchItemToWindreamSearchToDepartment } from '@app_models/windream-search-item-to-windream-search-to-department'; +import { WindreamSearchToDepartment } from '@app_models/windream-search-to-department'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { DepartmentWindreamSearchItemPopupeditComponent } from './department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component'; +import { ColumnConfigList } from '@app_core/components/grid-config/columnconfiglist'; +import { MatDialogService } from '@app_core/services/mat-dialog.service'; +import { LocaleService } from '@app_core/services/localization/locale.service'; +import { Globals } from '@app_core/services/globals'; +import { ColumnConfig, EN_SortOrder } from '@app_core/components/grid-config/columnconfig'; + +@Component({ + selector: 'app-department-windream-search-item', + templateUrl: './department-windream-search-item.component.html', + styleUrls: ['./department-windream-search-item.component.scss'] +}) +export class DepartmentWindreamSearchItemComponent implements OnInit { + @Input() windreamSearchItemList: AppBaseEntityListWrapper; + @Input() windreamSearchItemDetails: AppBaseEntityWrapper; + @Input() windreamSearchToDepartmentDetails: AppBaseEntityWrapper; + @Input() departmentDetails: AppBaseEntityWrapper; + + public columnConfigList: ColumnConfigList = new ColumnConfigList(); + constructor( + private dialog: MatDialogService, + public departmentDataService: DepartmentDataService, + public localeService: LocaleService, + public globals: Globals, + ) { + } + + ngOnInit() { + this.initColumns(); + } + initColumns() { + let col: ColumnConfig; + col = this.columnConfigList.add('Seq.', 'seq', 2); + col.sortIndex = 0; + col.sortOrder = EN_SortOrder.asc; + col = this.columnConfigList.add('Suchbaustein', 'windreamSearchItemName', 10); + this.columnConfigList.recalcWidth(); + } + + addItem() { + this.windreamSearchItemList.focusedEntityShadowed.new(); + this.windreamSearchItemList.focusedEntityShadowed.entity.windreamSearchToDepartmentId = this.windreamSearchToDepartmentDetails.entityId; + this.openPopupDialog(this.windreamSearchItemList.focusedEntityShadowed); + } + + public openPopupDialog(editEntity: AppBaseEntityWrapper) { + this.windreamSearchToDepartmentDetails.keyDownListenerStopped = true; + this.dialog.openDialog(DepartmentWindreamSearchItemPopupeditComponent, { + baseEntityWrapper: editEntity, + keyItemName: this.windreamSearchToDepartmentDetails.entity._name, + readOnly: !this.departmentDetails.inEditMode, + description: editEntity.entity.entitytitle + (editEntity.entity.entityId === 0 ? ' zuweisen' : ' bearbeiten '), + list: this.windreamSearchItemList, + }, true, () => this.windreamSearchToDepartmentDetails.keyDownListenerStopped = false); + } + + + private outColKeyItemDescription() { + return `Suchfelder für "${this.windreamSearchToDepartmentDetails.entity.windreamSearchName}" Abteilung "${this.departmentDetails.entity.departmentName}"`; + } + + + public copyWindreamOutCols() { + this.departmentDataService.clpbrdWindreamSearchItemList = this.windreamSearchItemList.items.slice(); + this.departmentDataService.clpbrdWindreamSearchItemHint1 = this.outColKeyItemDescription(); + this.departmentDataService.clpbrdWindreamSearchItemHints = ''; + this.departmentDataService.clpbrdWindreamSearchItemList.forEach(col => + this.departmentDataService.clpbrdWindreamSearchItemHints += '\n' + col.windreamSearchItemName); + } + + + public pasteWindreamOutCols() { + this.windreamSearchItemDetails.confirmMessageBoxYesNo('Übernahme von ' + this.departmentDataService.clpbrdWindreamSearchItemHint1, this.outColKeyItemDescription() + ' werden mit ' + this.departmentDataService.clpbrdWindreamSearchItemHint1 + ' überschrieben. Sind Sie sicher?', + () => { + this.windreamSearchItemList.deleteAll(); + this.windreamSearchItemList.items.push(...this.departmentDataService.clpbrdWindreamSearchItemList); + this.windreamSearchItemList.items.forEach(el => { + el.entityId = 0; + el.entityChanged = true; + el.windreamSearchToDepartmentId = this.windreamSearchToDepartmentDetails.entityId; + }); + this.windreamSearchItemList.save(); + } + ); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.html new file mode 100644 index 0000000..4e8e8b3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.html @@ -0,0 +1,37 @@ +
+ +

{{description}} - {{keyItemName}}

+ + + +
+ + +
+ + + + + + +
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.scss new file mode 100644 index 0000000..877b92d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.scss @@ -0,0 +1,20 @@ +@import 'popup-base.component'; + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid: ; + height: 100%; // 100% view height + grid-template-rows: auto auto; // row relationships + grid-template-columns: repeat(2, minmax(0, 1fr)); // column relationship + grid-column-gap: 15px; + grid-row-gap: 15px; + grid-template-areas: + 'input-windreamSearch .' + 'buttons buttons' +} + +.input-windreamSearch { + grid-area: input-windreamSearch; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.spec.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.spec.ts new file mode 100644 index 0000000..574baa9 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DepartmentWindreamSearchPopupeditComponent } from './department-windream-search-popupedit.component'; + +describe('DepartmentWindreamSearchPopupeditComponent', () => { + let component: DepartmentWindreamSearchPopupeditComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DepartmentWindreamSearchPopupeditComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DepartmentWindreamSearchPopupeditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.ts new file mode 100644 index 0000000..99976c2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component.ts @@ -0,0 +1,34 @@ +import { Component } from '@angular/core'; +import { PopupBaseComponent } from '@app_core/components/popup-base/popup-base.component'; +import { WindreamSearch } from '@app_models/windream-search'; +import { WindreamSearchToDepartment } from '@app_models/windream-search-to-department'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; + +@Component({ + selector: 'app-department-windream-search-popupedit', + templateUrl: './department-windream-search-popupedit.component.html', + styleUrls: ['./department-windream-search-popupedit.component.scss'] +}) +export class DepartmentWindreamSearchPopupeditComponent extends PopupBaseComponent { + + constructor( + public departmentDataService: DepartmentDataService, + ) { + super(); + this.departmentDataService.windreamSearchList.load(); + } + + + public get windreamSearchList(): WindreamSearch[] { + return this.departmentDataService.windreamSearchList.items; + } + + public get focusedItem(): WindreamSearchToDepartment { + return (this._focusedItem); + } + + getNotUsedWindreamSearches = (dep: WindreamSearch) => { + return !this.list.items.find((item) => item['windreamSearchId'] === dep.entityId); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.html new file mode 100644 index 0000000..dae5a17 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.html @@ -0,0 +1,113 @@ +
+ +
+
+
+ + + + + + + +
+
+
+ + + + --> + + + + + + + + + + + + + + + +
+ +
+
+ {{cell.value | number:'1.0-0':culture}} +
+
+ {{cell.value | number:'1.1-1':culture}} +
+
+ {{cell.value | number:'1.2-2':culture}} +
+
+ {{cell.value | number:'1.3-3':culture}} +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.scss new file mode 100644 index 0000000..15a776e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.scss @@ -0,0 +1,23 @@ +.department-windreamsearch { + width: 100%; + height: 100%; + display: grid; + grid-template-columns: auto minmax(0, 1fr); // column relationship + grid-template-rows: auto minmax(1px, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships + grid-template-areas: "label label" "toolbar grid"; +} + +.grid { + grid-area: grid; + height: 100%; + width: 100%; +} + +.label { + grid-area: label; + // padding-bottom: 6px; +} + +.toolbar { + grid-area: toolbar; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.spec.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.spec.ts new file mode 100644 index 0000000..8ae40b5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DepartmentWindreamSearchComponent } from './department-windream-search.component'; + +describe('DepartmentWindreamSearchComponent', () => { + let component: DepartmentWindreamSearchComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DepartmentWindreamSearchComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DepartmentWindreamSearchComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.ts new file mode 100644 index 0000000..669dfb2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/department-windream-search.component.ts @@ -0,0 +1,121 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { EN_AppEntities } from '@app_consts'; +import { Department } from '@app_models/basedata/department'; +import { WindreamSearchToDepartment } from '@app_models/windream-search-to-department'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { DepartmentWindreamSearchPopupeditComponent } from './department-windream-search-popupedit/department-windream-search-popupedit.component'; +import { SelectDepartmentPopupComponent } from './select-department-popup/select-department-popup.component'; +import { ColumnConfigList } from '@app_core/components/grid-config/columnconfiglist'; +import { MatDialogService } from '@app_core/services/mat-dialog.service'; +import { RepositoryService } from '@app_core/services/http/repository.service'; +import { LocaleService } from '@app_core/services/localization/locale.service'; +import { Globals } from '@app_core/services/globals'; +import { ColumnConfig, EN_SortOrder } from '@app_core/components/grid-config/columnconfig'; + +@Component({ + selector: 'app-department-windream-search', + templateUrl: './department-windream-search.component.html', + styleUrls: ['./department-windream-search.component.scss'] +}) +export class DepartmentWindreamSearchComponent implements OnInit { + + @Input() windreamSearchList: AppBaseEntityListWrapper; + @Input() departmentDetails: AppBaseEntityWrapper; + + + public columnConfigList: ColumnConfigList = new ColumnConfigList(); + + constructor( + private dialog: MatDialogService, + public departmentDataService: DepartmentDataService, + public repoService: RepositoryService, + public localeService: LocaleService, + public globals: Globals, + ) { + } + + ngOnInit() { + this.initColumns(); + } + + initColumns() { + let col: ColumnConfig; + col = this.columnConfigList.addNumber('Seq.', 'seq', 2); + col.sortIndex = 0; + col.sortOrder = EN_SortOrder.asc; + col = this.columnConfigList.add('Suche Kachel', 'windreamSearchName', 10); + col = this.columnConfigList.addBoolean('Active', 'isActive', 2); + col.cellTemplate = 'checkbox_template'; + this.columnConfigList.recalcWidth(); + } + + addItem() { + this.windreamSearchList.focusedEntityShadowed.new(); + this.windreamSearchList.focusedEntityShadowed.entity.departmentId = this.departmentDetails.entityId; + this.openPopupDialog(this.windreamSearchList.focusedEntityShadowed); + } + + public openPopupDialog(editEntity: AppBaseEntityWrapper) { + this.departmentDetails.keyDownListenerStopped = true; + this.dialog.openDialog(DepartmentWindreamSearchPopupeditComponent, { + baseEntityWrapper: editEntity, + keyItemName: this.departmentDetails.entity.departmentName, + readOnly: !this.departmentDetails.inEditMode, + description: editEntity.entity.entitytitle + (editEntity.entity.entityId === 0 ? ' zuweisen' : ' bearbeiten '), + list: this.windreamSearchList, + }, true, () => this.departmentDetails.keyDownListenerStopped = false); + } + + + public get nameOfDepartment(): string { + return this.departmentDetails.entity.departmentName; + } + + + public changeKeyWS(wsTD: WindreamSearchToDepartment) { + if (this.departmentDetails.inEditMode) { + wsTD.isActive = !wsTD.isActive; + wsTD.entityChanged = true; + wsTD.save(this.repoService, null); + } + } + + + public copyAllTiles() { + this.openSelectDepartmentsPopup(`Wählen Sie Abteilungen, bei welchen alle Suchkacheln von Suchkacheln aus "${this.departmentDetails.entity.departmentName}" ersetzt werden sollen` + , 'content_copy' + , (depIds: number[]) => { + this.repoService.putDataById(EN_AppEntities.DepartmentCopyWindreamTiles, this.departmentDetails.entityId, depIds).subscribe( + () => this.departmentDetails.informationMessageBox('Kopieren von Suchkacheln', `Die Suchkacheln aus "${this.departmentDetails.entity.departmentName}" haben Suchkacheln aus den ausgewählten Abteilungen erfolgreich ersetzt`) + ); + } + ); + } + + + public copyCurrentTile() { + this.openSelectDepartmentsPopup(`Wählen Sie Abteilungen, für welche die Suchkachel "${this.windreamSearchList.focusedItem.windreamSearchName}" aus "${this.departmentDetails.entity.departmentName}" hinzugefügt werden soll` + , 'content_copy' + , (depIds: number[]) => { + this.repoService.putDataById(EN_AppEntities.WindreamSearchToDepartmentCopyWindreamTile, this.windreamSearchList.focusedItemId, depIds).subscribe( + () => this.departmentDetails.informationMessageBox('Kopieren von Suchkacheln', `Die Suchkachel "${this.windreamSearchList.focusedItem.windreamSearchName}" aus "${this.departmentDetails.entity.departmentName}" wurde zu den ausgewählten Abteilungen erfolgreich hinzugefügt`) + ); + } + ); + } + + + public openSelectDepartmentsPopup(text: string, iconanme: string, callBack: (depIds: number[]) => void) { + this.departmentDetails.keyDownListenerStopped = true; + this.dialog.openDialog(SelectDepartmentPopupComponent + , { text: text, iconanme: iconanme } + , true + , (result) => { + if (result && callBack) callBack(result); + this.departmentDetails.keyDownListenerStopped = false; + }); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.html new file mode 100644 index 0000000..c15b83e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.html @@ -0,0 +1,40 @@ +
+

+ {{iconanme}} + Windreameinstellungen übernehmen +

+
+ {{text}} +
+ + +
+ + +
+ + + + +
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.scss new file mode 100644 index 0000000..a28252a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.scss @@ -0,0 +1,21 @@ +@import 'popup-base.component'; + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid: ; + height: 100%; // 100% view height + grid-template-rows: auto auto auto; // row relationships + grid-template-columns: repeat(2, minmax(0, 1fr)); // column relationship + grid-column-gap: 15px; + grid-row-gap: 15px; + grid-template-areas: + 'text text' + 'input-departments input-departments' + 'buttons buttons' +} + +.input-departments { + grid-area: input-departments; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.ts new file mode 100644 index 0000000..729485e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-detail/department-windream-search/select-department-popup/select-department-popup.component.ts @@ -0,0 +1,25 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA } from '@app_core/components/angular-material-index'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; + +@Component({ + selector: 'app-select-department-popup', + templateUrl: './select-department-popup.component.html', + styleUrls: [ './select-department-popup.component.scss'] +}) + +export class SelectDepartmentPopupComponent { + + public selectedDepartments: number[] = []; + public text: string; + public iconanme: string; + + constructor( + public departmentDataService: DepartmentDataService, + @Inject(MAT_DIALOG_DATA) data: any + ) { + this.text = data.text; + this.iconanme = data.iconanme; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.html new file mode 100644 index 0000000..db76289 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.html @@ -0,0 +1,24 @@ + + + + + + + + +
+ + + + +
+ +
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.scss new file mode 100644 index 0000000..85d3855 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.scss @@ -0,0 +1,49 @@ +.filterCardContainer { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-column-gap: 15px; + grid-template-rows: repeat(1, auto); // row relationships + grid-template-columns: repeat(5, minmax(0, 1fr)) auto; // column relationship + grid-template-areas: + "filterDepartment . . . . filterButtons" +} + +// @media screen and (max-width:1024px) { +// .woassays { +// font-size: 1vw; +// } +// } + +.filterDepartment { + grid-area: filterDepartment; +} + +.filterButtons { + grid-area: filterButtons; + margin-left: auto; +} + +// .filterBtn { +// font-size: 1vw; //scales buttons caption depended from the current view port resolution +// } + +.card { + padding: 10px; + margin: 2px 2px 0px 2px; +} + +.filterBtn { + margin-left: 2px; + margin-right: 2px; + margin-right: 1px; + margin-top: 6px; + width: 90px; +} + +// .filterButtons .filterBtn { +// width: unset; +// } diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.ts new file mode 100644 index 0000000..c9538fa --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-filter/department-filter.component.ts @@ -0,0 +1,61 @@ +import * as keycode from '@angular/cdk/keycodes'; +import { AfterViewInit, Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core'; +import { Department, DepartmentFilter } from '@app_models/basedata/department'; +import { DepartmentDataService } from '@app_modules/department/department-data.service'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import * as Cnst from '@app_core/consts'; +import { AuthorizeService } from '@app_core/services/authorize.service'; +import { LoginPopupComponent } from '@app_core/components/login/login-popup/login-popup.component'; + +@Component({ + selector: 'app-department-filter', + templateUrl: './department-filter.component.html', + styleUrls: ['./department-filter.component.scss'], +}) + +export class DepartmentFilterComponent implements OnInit, AfterViewInit { + + constructor( + public departmentDataService: DepartmentDataService, + public appDataService: AppDataService, + public authService: AuthorizeService, + ) { } + @Input() public filterObject: DepartmentFilter; + @Input() departmentDetails: AppBaseEntityWrapper; + @Output() public filterFetch = new EventEmitter(); + + public dropDownAllCaption = Cnst.EN_DropDownConst4Filter.AllCaption; + public dropDownAllValueString = Cnst.EN_DropDownConst4Filter.AllValueString; + public dropDownAllValueInt = Cnst.EN_DropDownConst4Filter.AllValueInt; + public allCaption = Cnst.EN_DropDownConst4Filter.AllCaption; + public allValue: number = Cnst.EN_DropDownConst4Filter.AllValueInt; + public noneCaption = Cnst.EN_DropDownConst4Filter.NoneCaption; + public noneValue = Cnst.EN_DropDownConst4Filter.NoneValueInt; + + ngOnInit() { } + ngAfterViewInit() { } + onFilterClick() { + if (this.departmentDetails.inViewMode) this.filterFetch.emit(); + } + onClearClick() { + this.filterObject.filterReset(); + } + + + @HostListener('window:keydown', ['$event']) + keyboardInput(event: any) { + if (!LoginPopupComponent.LOGIN_IS_SHOWN && !this.departmentDetails.keyDownListenerStopped) { + if (event.ctrlKey) { + switch (event.which) { + case keycode.F: //Ctrl + 'f' + event.stopPropagation(); + this.onFilterClick(); + return false; //processed + } + } + } + return true; //default processing + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.html new file mode 100644 index 0000000..a641df6 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.html @@ -0,0 +1,86 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{cell.value | number:'1.0-0':culture}} +
+
+ {{cell.value | number:'1.1-1':culture}} +
+
+ {{cell.value | number:'1.2-2':culture}} +
+
+ {{cell.value | number:'1.3-3':culture}} +
+
+
+
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.scss new file mode 100644 index 0000000..4393ad5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.scss @@ -0,0 +1,39 @@ +.DepartmentList { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-template-rows: auto minmax(0, 1fr); // row relationships + grid-template-columns: minmax(0, 1fr); // column relationship + grid-row-gap: 7px; + grid-template-areas: + 'filter' + 'grid'; +} + + +.FilterComponent { + grid-area: filter; // grid area: auto height 1fr width + margin: 0 0 0 0; +} + + +.card { + grid-area: grid; + width: 100%; + padding: 0px; + margin: 0; + border-radius: 0px; + box-shadow: none; +} + +.gridDepartment { + position: absolute; // position absolut ist hier zwingend! Die position ist absolut innerhalb mehrerer parent divs und darf sich NICHT über diese hinausstrecken. + height: 100%; + width: 100%; + padding-left: 1px; + padding-right: 1px; + padding-bottom: 1px; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.ts new file mode 100644 index 0000000..9294269 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department-list/department-list.component.ts @@ -0,0 +1,59 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Department } from '@app_models/basedata/department'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import { DepartmentDataService } from '../department-data.service'; +import { ColumnConfigList } from '@app_core/components/grid-config/columnconfiglist'; +import { LocaleService } from '@app_core/services/localization/locale.service'; +import { Globals } from '@app_core/services/globals'; +import { ColumnConfig, EN_SortOrder } from '@app_core/components/grid-config/columnconfig'; + +@Component({ + selector: 'app-department-list', + templateUrl: './department-list.component.html', + styleUrls: ['./department-list.component.scss'] +}) +export class DepartmentListComponent implements OnInit { + @Input() public dataSource: AppBaseEntityListWrapper; + + public columnConfigList: ColumnConfigList = new ColumnConfigList(); + + + constructor( + public departmentDataService: DepartmentDataService, + public appDataService: AppDataService, + public localeService: LocaleService, + public globals: Globals, + ) { + } + + ngOnInit() { + this.initColumns(); + } + + initColumns() { + let col: ColumnConfig; + col = this.columnConfigList.addNumber('Id', 'departmentId', 5); + col = this.columnConfigList.add('Name', 'departmentName', 13); + col.sortIndex = 0; + col.sortOrder = EN_SortOrder.asc; + col.allowHeaderFiltering = true; + col = this.columnConfigList.addNumber('Typ Id', 'departmentTypeId', 5); + col = this.columnConfigList.addNumber('CostCentre Id', 'costCentreId', 5); + col = this.columnConfigList.add('CostCentre', 'costCentre', 10); + col = this.columnConfigList.add('Abteilungsleiter', 'headofDepartment', 18); + col = this.columnConfigList.add('CEO', 'executiveDirector', 18); + col = this.columnConfigList.add('COO', 'managingDirector', 18); + col = this.columnConfigList.add('Folder', 'departmentNameFolder', 13); + col = this.columnConfigList.add('AD-Group Name', 'adGroupDepartmentName', 13); + col = this.columnConfigList.addNumber('Client Id', 'clientId', 5); + col = this.columnConfigList.addBoolean('Virtual', 'isVirtual', 2); + this.columnConfigList.recalcWidth(); + } + + + public loadData() { + this.departmentDataService.loadData(); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department.component.html b/ClientApp/staff-db-ui/src/app/modules/department/department.component.html new file mode 100644 index 0000000..0e19c08 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department.component.html @@ -0,0 +1,7 @@ +
+ + +
diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department.component.scss b/ClientApp/staff-db-ui/src/app/modules/department/department.component.scss new file mode 100644 index 0000000..90683e3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department.component.scss @@ -0,0 +1,22 @@ +.DepartmentComponent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-template-rows: minmax(0, 1fr) auto; // row relationships + grid-template-columns: minmax(0, 1fr); // column relationship + grid-template-areas: 'list''details'; + grid-column-gap: 5px; + grid-row-gap: 5px; +} + +.DepartmentListComponent { + grid-area: list; +} + +.DepartmentDetailsComponent { + grid-area: details; + z-index: 10; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department.component.ts b/ClientApp/staff-db-ui/src/app/modules/department/department.component.ts new file mode 100644 index 0000000..f0d3953 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; +import { DepartmentDataService } from './department-data.service'; + +@Component({ + selector: 'app-department', + templateUrl: './department.component.html', + styleUrls: ['./department.component.scss'] +}) +export class DepartmentComponent implements OnInit { + + constructor( + public departmentDataService: DepartmentDataService + ) { } + + ngOnInit() { + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department.module.ts b/ClientApp/staff-db-ui/src/app/modules/department/department.module.ts new file mode 100644 index 0000000..9bb8f89 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department.module.ts @@ -0,0 +1,57 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { AngularMaterialModule } from '@app_core/components/angular-material.module'; +import { DxButtonModule, DxDataGridModule, DxFileUploaderModule, DxPieChartModule, DxTemplateModule, DxTooltipModule } from 'devextreme-angular'; +import { DepartmentContentComponent } from './department-detail/department-content/department-content.component'; +import { DepartmentDetailComponent } from './department-detail/department-detail.component'; +import { DepartmentDocumentartsComponent as DepartmentDocumentArtComponent } from './department-detail/department-documentart/department-documentart.component'; +import { DepartmentWindreamIndexPopupeditComponent } from './department-detail/department-windream-index/department-windream-index-popupedit/department-windream-index-popupedit.component'; +import { DepartmentWindreamIndexComponent } from './department-detail/department-windream-index/department-windream-index.component'; +import { DepartmentWindreamSearchItemPopupeditComponent } from './department-detail/department-windream-search-item/department-windream-search-item-popupedit.component/department-windream-search-item-popupedit.component'; +import { DepartmentWindreamSearchItemComponent } from './department-detail/department-windream-search-item/department-windream-search-item.component'; +import { DepartmentWindreamSearchPopupeditComponent } from './department-detail/department-windream-search/department-windream-search-popupedit/department-windream-search-popupedit.component'; +import { DepartmentWindreamSearchComponent } from './department-detail/department-windream-search/department-windream-search.component'; +import { SelectDepartmentPopupComponent } from './department-detail/department-windream-search/select-department-popup/select-department-popup.component'; +import { DepartmentFilterComponent } from './department-list/department-filter/department-filter.component'; +import { DepartmentListComponent } from './department-list/department-list.component'; +import { DepartmentComponent } from './department.component'; +import { DepartmentRoutingModule } from './department.routing.module'; +import { HenselSelectionComponent } from '@app_core/components/hensel-selection/hensel-selection.component'; +import { HenselInputComponent } from '@app_core/components/hensel-input/hensel-input.component'; + + +@NgModule({ + declarations: [ + DepartmentComponent, + DepartmentListComponent, + DepartmentDetailComponent, + DepartmentFilterComponent, + DepartmentContentComponent, + DepartmentWindreamSearchComponent, + DepartmentWindreamSearchPopupeditComponent, + DepartmentWindreamSearchItemComponent, + DepartmentWindreamSearchItemPopupeditComponent, + DepartmentWindreamIndexComponent, + DepartmentDocumentArtComponent, + DepartmentWindreamIndexPopupeditComponent, + SelectDepartmentPopupComponent + ], + imports: [ + CommonModule, + DepartmentRoutingModule, + AngularMaterialModule, + DxDataGridModule, + FormsModule, + HenselSelectionComponent, + HenselInputComponent, + DxFileUploaderModule, + DxButtonModule, + DxTooltipModule, + DxTemplateModule, + DxPieChartModule, + ], + providers: [], + exports: [] +}) +export class DepartmentModule { } diff --git a/ClientApp/staff-db-ui/src/app/modules/department/department.routing.module.ts b/ClientApp/staff-db-ui/src/app/modules/department/department.routing.module.ts new file mode 100644 index 0000000..7e2514a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/department/department.routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { DepartmentComponent } from './department.component'; +import { AuthGuard } from '@app_core/services/authguard'; + +const routes: Routes = [ + { + path: '**', + component: DepartmentComponent, + canActivate: [AuthGuard] + }, +]; + + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class DepartmentRoutingModule { } diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/Page1.drawio b/ClientApp/staff-db-ui/src/app/modules/employee/Page1.drawio new file mode 100644 index 0000000..057d656 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/Page1.drawio @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-data.service.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-data.service.ts new file mode 100644 index 0000000..f573dc5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-data.service.ts @@ -0,0 +1,167 @@ +import { Injectable } from '@angular/core'; +import { cnst_LoadedEntitiesExpiresInMs, EN_AppEntities, EN_AppPages, EN_HttpQueriesCount4Page } from '@app_consts'; +import { EN_EntityBeforeSaveCallBackResults } from '@app_core/consts'; +import { CoreUser } from '@app_core/models/coreuser'; +import { RepositoryService } from '@app_core/services/http/repository.service'; +import { UINotifierService } from '@app_core/services/notification/uinotifier.service'; +import { CorePageService } from '@app_core/services/page.service'; +import { Employee, EmployeeFilter, EmployeeFullFilter } from '@app_models/employee'; +import { EmployeeToAttribute } from '@app_models/employee-to-attribute'; +import { EmployeeToDepartment } from '@app_models/employee-to-department'; +import { EmployeeToWebApp } from '@app_models/employee-to-webapp'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; + +import { User } from '@app_models/user'; +import { EmployeeToWebAppFilter, WebAppToDepartment } from '@app_models/webapp-to-department'; +import { WebAppToWebAppAdditionalRole } from '@app_models/webapp-to-webappadditionalrole'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import { AppBaseEntityCallBack } from 'src/app/shared/app.types'; + + +@Injectable({ providedIn: 'root' }) + +export class EmployeeDataService extends CorePageService { + protected appPage: EN_AppPages = EN_AppPages.Employee; + protected get appPageNoQueries() { return EN_HttpQueriesCount4Page.Employee; } + + // --- running data + employeeDetails: AppBaseEntityWrapper; + employeeList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(Employee, 'Mitarbeiterliste', EN_AppEntities.Employee); + employeeFilter: EmployeeFullFilter = new EmployeeFullFilter('EmployeeFullFilter'); + employee2AllFilter: EmployeeFilter = new EmployeeFilter('EmployeeFilter'); + + employee2DepartmentList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(EmployeeToDepartment, 'Abteilungen von Mitarbeiter', EN_AppEntities.EmployeeToDepartment); + + employee2WebAppList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(EmployeeToWebApp, 'Applikationen von Mitarbeiter', EN_AppEntities.EmployeeToWebapp); + + employee2AttributeList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(EmployeeToAttribute, 'Merkmale von Mitarbeiter', EN_AppEntities.EmployeeToAttribute); + + constructor( + private appDataService: AppDataService, + private repositoryService: RepositoryService, + protected uiNotificationsService: UINotifierService + ) { + super(); + + this.employeeList.alwaysFocused = true; + this.employeeList.focusedCallBack = this.focusCallBack.bind(this); + this.employeeList.filter = this.employeeFilter; + + this.employeeDetails = this.employeeList.createFocusedShadowEntity(AppBaseEntityWrapper.EN_ViewMode); + this.employeeDetails.loadedDataExpiresInMs = cnst_LoadedEntitiesExpiresInMs; + + this.activateRouting4EntityList(this.employeeList); //we are using routing + this.baseEntityWrapperWaitLoading = this.employeeDetails; + + this.prepareDetailsList(this.employee2DepartmentList); + this.prepareDetailsList(this.employee2WebAppList); + + this.employeeDetails.detailItems.register(this.employee2DepartmentList, null, 'employeeId', /*() => this.employee2DepartmentList.focuseFirstItem()*/); + this.employeeDetails.detailItems.register(this.employee2WebAppList, null, 'employeeId'); + this.employeeDetails.detailItems.register(this.employee2AttributeList, null, 'employeeId'); + this.employee2WebAppList.batchInsert = false; + this.employee2WebAppList.beforeSaveCallBack = this.beforeSaveEmployee2WebAppList.bind(this); + this.employee2WebAppList.afterInsertCallBack = this.afterInsertEmployee2WebAppList.bind(this); + this.employee2AttributeList.filter = this.employee2AllFilter; + + this.loadBaseData(); + this.init(); + } + + async beforeSaveEmployee2WebAppList(entities: EmployeeToWebApp[]): Promise { + entities.forEach((entity: EmployeeToWebApp) => { + if (entity.entityChanged && !entity.isNew()) this.afterInsertEmployee2WebAppList(entity, null, false); + }); + this.employee2WebAppList.deletedItems.forEach((entity: EmployeeToWebApp) => { + entity.arExtendedDepartmentIdList = []; + entity.arAdditionalRoleIdList = []; + this.afterInsertEmployee2WebAppList(entity, null, false); + }); + return EN_EntityBeforeSaveCallBackResults.Ok_Continue; + } + + + afterInsertEmployee2WebAppList(entity: EmployeeToWebApp, callback?: AppBaseEntityCallBack, reloadEntity = true) { + if (entity) { + const filter = new EmployeeToWebAppFilter('EmployeeToWebAppFilter'); + filter.employeeToWebAppId = entity.employeeToWebAppId; + //to create wrapper not in the constructor we need to pass appLogsService, repositoryService, uiNotificationsService explicetely! + const departmentList = new AppBaseEntityListWrapper(WebAppToDepartment, 'Abteilungen für Mitarbeiterapplikation', EN_AppEntities.WebAppToDepartment, filter, this.appLogsService, this.repositoryService, this.uiNotificationsService); + const addRoleList = + new AppBaseEntityListWrapper(WebAppToWebAppAdditionalRole, 'Zusatzrole für Mitarbeiterapplikation', EN_AppEntities.WebAppToWebAppAdditionalRole, filter, this.appLogsService, this.repositoryService, this.uiNotificationsService); + + this._saveEmployee2WebAppSublists(entity + , departmentList + , 'arExtendedDepartmentIdList' + , 'departmentId' + , (result1) => { + this._saveEmployee2WebAppSublists(entity + , addRoleList + , 'arAdditionalRoleIdList' + , 'webAppAdditionalRoleId' + , (result2) => { if (reloadEntity && (result1 || result2)) entity.load(this.repositoryService, callback); else if (callback) callback(); } + ); + } + ); + } + } + + + private _saveEmployee2WebAppSublists(entity: EmployeeToWebApp, list: AppBaseEntityListWrapper, idListName: string, idName: string, callback?: (entity: boolean) => void) { + let result: boolean = false; + list.load(() => { + if (result = list.match2array(entity, 'employeeToWebAppId', idListName, idName)) { + list.save(() => { if (callback) callback(true); }, (err) => { if (callback) callback(true); }); + } else if (callback) callback(false); + }); + } + + + prepareDetailsList(list: AppBaseEntityListWrapper) { + list.createFocusedShadowEntity(); + list.filter = this.employee2AllFilter; + list.focusedEntityShadowed.dontLoadEntity = true; + list.focusedEntityShadowed.dontUpdateEntityDirectly = true; + list.focusedEntityShadowed.dontInsertEntityDirectly = true; + } + + + loadData() { + super.loadData(); + this.employeeList.load(null, null, () => this.pageLoadingService.updatePageLoadedCounters(this.appPage)); + } + + public loadBaseData() { + super.loadBaseData(EN_AppPages.Login, EN_HttpQueriesCount4Page.Login); + this.appDataService.loadData(() => this.pageLoadingService.updatePageLoadedCounters(EN_AppPages.Login)); + } + + + public focusCallBack(focusedItem: Employee) { + } + + + public clearData() { + super.clearData(); + this.employeeFilter.filterReset(); + this.employeeList.clear(); + } + + + protected onLoggedInOut(user: CoreUser) { + this.userChanged(new User(user)); + super.onLoggedInOut(user); + } + + private userChanged(user: User) { + if (this.authService.isLoggedIn()) { + this.employeeDetails.canNew = user.isMaster; + this.employeeDetails.canEdit = this.employeeDetails.canNew; + this.employeeDetails.canDelete = this.employeeDetails.canNew; + } + // this.globalsService.appPages[EN_AppPages.UserConfig].hidden = !user?.isMaster; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.html new file mode 100644 index 0000000..6578e33 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.html @@ -0,0 +1,20 @@ +
+ + + +
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.scss new file mode 100644 index 0000000..cb3da64 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.scss @@ -0,0 +1,20 @@ +.employee-attribute { + width: 100%; + height: 100%; + display: grid; + grid-template-columns: minmax(0, 1fr); // column relationship + grid-template-rows: auto minmax(1px, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships + grid-template-areas: "label""attributes"; +} + + +.attributes { + grid-area: attributes; + height: 100%; + width: calc(100% - 28px); + margin-left: 28px; +} + +.label { + grid-area: label; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.ts new file mode 100644 index 0000000..2dcf40c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-attribute/employee-attribute.component.ts @@ -0,0 +1,24 @@ + + +import { Component, OnInit, Input } from '@angular/core'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { Employee } from '@app_models/employee'; +import { AppDataService } from '@app_services/app.data.service'; + +@Component({ + selector: 'app-employee-attribute', + templateUrl: './employee-attribute.component.html', + styleUrls: ['./employee-attribute.component.scss'] +}) +export class EmployeeAttributeComponent implements OnInit { + + @Input() public employeeDetails: AppBaseEntityWrapper; + + constructor( + public appDataService: AppDataService, + ) { + } + ngOnInit() { + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.html new file mode 100644 index 0000000..859981b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.html @@ -0,0 +1,147 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Aktiv + + +
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.scss new file mode 100644 index 0000000..71dc6c9 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.scss @@ -0,0 +1,97 @@ + +.employeeDetailsContent { + // z-index: 10; + // position: relative; //otherwise z-index is not working + padding: 0 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-column-gap: 8px; + grid-template-columns: repeat(2, minmax(1px, 1fr)); // column relationship + grid-template-rows: repeat(7, 42px); // auto auto auto auto auto auto auto auto auto; // row relationships + grid-template-areas: + "input-employeeno input-title" + "input-salutation input-position" + "input-firstname input-rang" + "input-lastname input-mobilephoneno" + "input-shortname input-phoneno" + "input-loginname input-mandant" + "input-email input-isActive " + ; +} + +.input-isActive { + + margin-top: 12px; +grid-area: input-isActive; +} +.input-mandant { + grid-area: input-mandant; +} + +.input-employeeno { + grid-area: input-employeeno; +} + +.input-firstname { + grid-area: input-firstname; +} + +.input-lastname { + grid-area: input-lastname; +} + +.input-shortname { + grid-area: input-shortname; +} + +.input-loginname { + grid-area: input-loginname; +} + +.input-email { + grid-area: input-email; +} + +.input-salutation { + grid-area: input-salutation; +} + +.input-title { + grid-area: input-title; +} + +.input-position { + grid-area: input-position; +} + +.input-rang { + grid-area: input-rang; +} + +.input-email { + grid-area: input-email; +} + +.input-mobilephoneno { + grid-area: input-mobilephoneno; +} + +.input-phoneno { + grid-area: input-phoneno; +} + +.check-box { + margin-top: 13px; +} + +.card { + padding: 12px; + margin: 2px 2px 2px 2px; +} + +.abstand { + margin-right: 1px !important; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.ts new file mode 100644 index 0000000..2888af6 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-content/employee-content.component.ts @@ -0,0 +1,33 @@ +import { Component, OnInit, Input, ViewChild, AfterViewInit } from '@angular/core'; +import { NgForm } from '@angular/forms'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import { Employee } from '@app_models/employee'; +import { EmployeeDataService } from '@app_modules/employee/employee-data.service'; +import { AuthorizeService } from '@app_core/services/authorize.service'; +import { Globals } from '@app_core/services/globals'; + +@Component({ + selector: 'app-details-content', + templateUrl: './employee-content.component.html', + styleUrls: ['./employee-content.component.scss'], +}) +export class EmployeeContentComponent implements OnInit, AfterViewInit { + @Input() public employeeDetails: AppBaseEntityWrapper; + @ViewChild('detailForm') detailForm: NgForm; + + constructor( + public appDataService: AppDataService, + public employeeDataService: EmployeeDataService, + public authorizeService: AuthorizeService, + public globals: Globals + ) { } + + ngAfterViewInit(): void { + this.employeeDetails.detailForm = this.detailForm; + } + + ngOnInit() { } + + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.html new file mode 100644 index 0000000..415206d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.html @@ -0,0 +1,94 @@ +
+ +
+
+
+ + + +
+
+
+ + + + --> + + + + + + + + + + + + + + + + + + + +
+ {{cell.value | number:'1.0-0':culture}} +
+
+ {{cell.value | number:'1.1-1':culture}} +
+
+ {{cell.value | number:'1.2-2':culture}} +
+
+ {{cell.value | number:'1.3-3':culture}} +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.scss new file mode 100644 index 0000000..2492105 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.scss @@ -0,0 +1,23 @@ +.employee-department { + width: 100%; + height: 100%; + display: grid; + grid-template-columns: auto minmax(0, 1fr); // column relationship + grid-template-rows: auto minmax(1px, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships + grid-template-areas: "label label" "toolbar grid"; +} + +.grid { + grid-area: grid; + height: 100%; + width: 100%; +} + +.label { + grid-area: label; + // padding-bottom: 6px; +} + +.toolbar { + grid-area: toolbar; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.ts new file mode 100644 index 0000000..98aa67c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.component.ts @@ -0,0 +1,103 @@ + + +import { Component, Input, OnInit } from '@angular/core'; +import { EN_EmployeeRang, EN_EmployeeStatus } from '@app_consts'; +import { Employee } from '@app_models/employee'; +import { EmployeeToDepartment } from '@app_models/employee-to-department'; +import { EmployeeToWebApp } from '@app_models/employee-to-webapp'; +import { EmployeeDataService } from '@app_modules/employee/employee-data.service'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import { EmployeeToDepartmentPopupeditComponent } from './employee-department.popupedit/employee-department.popupedit.component'; +import { MatDialogService } from '@app_core/services/mat-dialog.service'; +import { ColumnConfigList } from '@app_core/components/grid-config/columnconfiglist'; +import { LocaleService } from '@app_core/services/localization/locale.service'; +import { Globals } from '@app_core/services/globals'; +import { ColumnConfig, EN_SortOrder } from '@app_core/components/grid-config/columnconfig'; + +@Component({ + selector: 'app-employee-department', + templateUrl: './employee-department.component.html', + styleUrls: ['./employee-department.component.scss'] +}) + +export class EmployeeDepartmentComponent implements OnInit { + + @Input() employeeDepartmentList: AppBaseEntityListWrapper; + @Input() public employeeDetails: AppBaseEntityWrapper; + + public columnConfigList: ColumnConfigList = new ColumnConfigList(); + + constructor( + private dialog: MatDialogService, + public appDataService: AppDataService, + public employeeDataService: EmployeeDataService, + public localeService: LocaleService, + public globals: Globals, + ) { + } + + get emplDepDetails(): AppBaseEntityWrapper { + return this.employeeDepartmentList.focusedEntityShadowed; + } + + ngOnInit() { + this.initColumns(); + } + + initColumns() { + let col: ColumnConfig; + + if (this.appDataService.showIds) col = this.columnConfigList.addNumber('Id', 'entityId', 7, 0); + + col = this.columnConfigList.add('Name', 'departmentId', 25); + + col = this.columnConfigList.add('Status', 'employeeStatusId', 20); + col.sortIndex = 1; + col.sortOrder = EN_SortOrder.asc; + col = this.columnConfigList.add('Rang', 'rangId', 10); + + this.columnConfigList.recalcWidth(); + } + + addItem() { + this.emplDepDetails.new(); + this.emplDepDetails.entity.employeeId = this.employeeDetails.entityId; + const employeeStatusId = this.employeeDepartmentList.items.find(e2d => e2d.employeeStatusId === EN_EmployeeStatus.MainFunction) ? EN_EmployeeStatus.AdditionalFunction : EN_EmployeeStatus.MainFunction; + this.emplDepDetails.entity.employeeStatusId = employeeStatusId; + this.emplDepDetails.entity.rangId = EN_EmployeeRang.Mitarbeiter; + this.openPopupDialog(this.emplDepDetails); + } + + dblClick(event: any) { + if (!this.employeeDetails.entityIsLoading) this.employeeDepartmentList.focusedEntityShadowed.delayedEdit(event.data['entityId'], this.editItem); + } + + editItem = () => { + this.emplDepDetails.edit(); + this.openPopupDialog(this.emplDepDetails); + } + + public openPopupDialog(editEntity: AppBaseEntityWrapper) { + this.employeeDetails.keyDownListenerStopped = true; + this.dialog.openDialog(EmployeeToDepartmentPopupeditComponent, { + baseEntityWrapper: editEntity, + keyItemName: this.employeeDetails.entity.firstName + ' ' + this.employeeDetails.entity.lastName, + readOnly: !this.employeeDetails.inNotViewMode, + description: (editEntity.entity.entityId === 0 ? 'Neue Abteilung zuweisen' : 'Daten zur Abteilung "' + editEntity.entity.departmentName + '" bearbeiten '), + list: this.employeeDepartmentList, + }, true, () => this.employeeDetails.keyDownListenerStopped = false); + } + + + public deleteDepartment() { + let usedDepartmentIdsStr: string = ''; + this.employeeDataService.employee2WebAppList.items.forEach((e2w: EmployeeToWebApp) => usedDepartmentIdsStr += ',' + e2w.departmentId + ',' + e2w.arExtendedDepartmentIdList); + const usedDepartmentIdsList: string[] = usedDepartmentIdsStr.split(','); + if (usedDepartmentIdsList.indexOf('' + this.emplDepDetails.entity.departmentId) > -1) { + this.emplDepDetails.warningMessageBox(`Löschen von Abteilung <${this.emplDepDetails.entity.departmentName}>`, + 'Die Abteilung kann nicht gelöscht werden, weil sie zu einer Webapplikation zugewiesen ist'); + } else this.emplDepDetails.delete(); + } +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.html new file mode 100644 index 0000000..5f9cf47 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.html @@ -0,0 +1,68 @@ +
+ +

{{description}} - {{keyItemName}}

+ + + +
+ + +
+ + + + + + + + + + + + +
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.scss new file mode 100644 index 0000000..92caaa3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.scss @@ -0,0 +1,28 @@ +@import 'popup-base.component'; + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid: ; + height: 100%; // 100% view height + grid-template-rows: auto auto; // row relationships + grid-template-columns: repeat(3, minmax(0, 1fr)); // column relationship + grid-column-gap: 15px; + grid-row-gap: 15px; + grid-template-areas: + 'input-department input-emplstatus input-rang' + 'buttons buttons buttons' +} + +.input-department { + grid-area: input-department; +} + +.input-emplstatus { + grid-area: input-emplstatus; +} + +.input-rang { + grid-area: input-rang; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.ts new file mode 100644 index 0000000..6ec1f89 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component.ts @@ -0,0 +1,30 @@ +import { Component } from '@angular/core'; +import { PopupBaseComponent } from '@app_core/components/popup-base/popup-base.component'; +import { Department } from '@app_models/basedata/department'; +import { EmployeeToDepartment } from '@app_models/employee-to-department'; +import { AppDataService } from '@app_services/app.data.service'; + +@Component({ + selector: 'app-employee-department-popupedit', + templateUrl: 'employee-department.popupedit.component.html', + styleUrls: ['employee-department.popupedit.component.scss'] +}) + +export class EmployeeToDepartmentPopupeditComponent extends PopupBaseComponent { + + constructor( + public appDataService: AppDataService, + ) { + super(); + } + + + public get focusedItem(): EmployeeToDepartment { + return (this._focusedItem); + } + + getNotUsedDepartments = (dep: Department) => { + return !this.list.items.find((item) => item['departmentId'] === dep.entityId); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.html new file mode 100644 index 0000000..3358f3b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.html @@ -0,0 +1,47 @@ +
+ + + + + +
+
+ + + + + +
+
+ + + + + + +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.scss new file mode 100644 index 0000000..0c1cf7e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.scss @@ -0,0 +1,48 @@ +.EmployeeDetails { + padding: 0; + margin: 0; + overflow: hidden; + display: grid; + width: 100%; + height: 100%; + grid-template-rows: 42px minmax(1px, 168px) minmax(1px, 120px); + grid-template-columns: auto minmax(1px, 1fr) minmax(1px, 1.8fr); + grid-row-gap: 6px; + grid-column-gap: 13px; + grid-template-areas: + 'toolbar department-grid webapps-grid' + 'detail department-grid webapps-grid ' + 'detail attribute-grid webapps-grid'; + z-index: 10; + position: relative; //otherwise z-index is not working +} + + +.DetailsContent { + grid-area: detail; +} + +.DepartmentList { + grid-area: department-grid; +} + +.WebAppList { + grid-area: webapps-grid; +} + +.AttributeList { + grid-area: attribute-grid; +} + +.abstand { + margin-right: 1px !important; +} + +.toolbar { + grid-area: toolbar; +} + +.card { + padding: 12px; + margin: 2px 2px 2px 2px; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.ts new file mode 100644 index 0000000..7954b38 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-detail.component.ts @@ -0,0 +1,71 @@ +import { AfterViewInit, Component, HostListener, Input } from '@angular/core'; +import { LoginPopupComponent } from '@app_core/components/login/login-popup/login-popup.component'; +import { EN_EntityBeforeSaveCallBackResults } from '@app_core/consts'; +import { AuthorizeService } from '@app_core/services/authorize.service'; +import { PageLoadingService } from '@app_core/services/pageloading.service'; +import { Employee } from '@app_models/employee'; +import { EmployeeDataService } from '@app_modules/employee/employee-data.service'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; + +@Component({ + selector: 'app-employee-detail', + templateUrl: './employee-detail.component.html', + styleUrls: ['./employee-detail.component.scss'], +}) +export class EmployeeDetailComponent implements AfterViewInit { + @Input() public employeeDetails: AppBaseEntityWrapper; + + constructor( + public employeeDataService: EmployeeDataService, + public authorizeService: AuthorizeService, + private pageLoadingService: PageLoadingService, + ) { + } + + public get focusedItem(): Employee { + return this.employeeDetails.entity; + } + + ngAfterViewInit(): void { + this.employeeDetails.beforeNewCallBack = this.newEmployeeInit.bind(this); + this.employeeDetails.beforeSaveCallBack = this.beforeSaveEmployee.bind(this); + } + + newEmployeeInit(employee: Employee) { + /* employee.createdOn = new Date(); + employee.createdBy = this.authorizeService.user.userCode; + employee.changedOn = employee.createdOn; + employee.changedBy = employee.createdBy;*/ + } + + async beforeSaveEmployee(employee: Employee): Promise { + this.employeeDataService.employee2AttributeList.match2array(employee, 'employeeId', 'arAttributeIdList', 'employeeAttributeId'); + return EN_EntityBeforeSaveCallBackResults.Ok_Continue; + } + + + public save = () => { //because of calling as callback of cancel + this.pageLoadingService.startSpinner(); + this.employeeDetails.save((employee: Employee) => this.afterSave(employee), null, () => this.pageLoadingService.hideSpinner()); + } + + afterSave(employee: Employee) { + // this.employeeDetails.loadDetails(this.catalogDataService.employeeCategoryList); + + } + + public cancel = () => { + // this.setCurrentMaster4Subemployee = null; + this.employeeDetails.cancelWithSave(this.save); + } + + public add(){ + this.employeeDetails.new(); + this.employeeDetails.entity.isActive = true; + } + @HostListener('window:keydown', ['$event']) + keyboardInput(event: any) { + return LoginPopupComponent.LOGIN_IS_SHOWN || this.employeeDetails.shortcutsHandler(event, this.save, this.cancel); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.html new file mode 100644 index 0000000..6d2c961 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.html @@ -0,0 +1,96 @@ +
+ +
+
+
+ + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ {{cell.value | number:'1.0-0':culture}} +
+
+ {{cell.value | number:'1.1-1':culture}} +
+
+ {{cell.value | number:'1.2-2':culture}} +
+
+ {{cell.value | number:'1.3-3':culture}} +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.scss new file mode 100644 index 0000000..1d9bd55 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.scss @@ -0,0 +1,24 @@ +.employee-webapp { + width: 100%; + height: 100%; + display: grid; + grid-template-columns: auto minmax(0, 1fr); // column relationship + grid-template-rows: auto minmax(1px, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships + // grid-template-areas: "label""toolbar""grid"; + grid-template-areas: "label label" "toolbar grid"; + } + +.grid { + grid-area: grid; + height: 100%; + width: 100%; +} + +.label { + grid-area: label; + // padding-bottom: 6px; +} + +.toolbar { + grid-area: toolbar; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.ts new file mode 100644 index 0000000..8693e5c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.component.ts @@ -0,0 +1,124 @@ + + +import * as keycode from '@angular/cdk/keycodes'; +import { Component, HostListener, Input, OnInit } from '@angular/core'; +import { EN_EmployeeStatus } from '@app_consts'; +import { ColumnConfig, EN_SortOrder } from '@app_core/components/grid-config/columnconfig'; +import { ColumnConfigList } from '@app_core/components/grid-config/columnconfiglist'; +import { Globals } from '@app_core/services/globals'; +import { LocaleService } from '@app_core/services/localization/locale.service'; +import { MatDialogService } from '@app_core/services/mat-dialog.service'; +import { Employee } from '@app_models/employee'; +import { EmployeeToDepartment } from '@app_models/employee-to-department'; +import { EmployeeToWebApp } from '@app_models/employee-to-webapp'; +import { EmployeeDataService } from '@app_modules/employee/employee-data.service'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import { EmployeeToWebAppPopupeditComponent } from './employee-webapp.popupedit/employee-webapp.popupedit.component'; + + +@Component({ + selector: 'app-employee-webapp', + templateUrl: './employee-webapp.component.html', + styleUrls: ['./employee-webapp.component.scss'] +}) + +export class EmployeeWebappComponent implements OnInit { + + public get employeeWebappList(): AppBaseEntityListWrapper { + return this.employeeDataService.employee2WebAppList; + } + + @Input() public employeeDetails: AppBaseEntityWrapper; + + public columnConfigList: ColumnConfigList = new ColumnConfigList(); + + constructor( + private dialog: MatDialogService, + public employeeDataService: EmployeeDataService, + public appDataService: AppDataService, + public localeService: LocaleService, + public globals: Globals, + ) { + } + + ngOnInit() { + this.initColumns(); + } + + initColumns() { + let col: ColumnConfig; + + if (this.appDataService.showIds) col = this.columnConfigList.addNumber('Id', 'entityId', 7, 0); + col = this.columnConfigList.add('Webapp', 'webAppName', 15); + // col = this.columnConfigList.addId('Webapp', 'webAppId', 15); + // col.calculateSortValue = 'webAppName'; + col.sortIndex = 1; + col.sortOrder = EN_SortOrder.asc; + + col = this.columnConfigList.add('Abteilung', 'departmentName', 20); + // col = this.columnConfigList.add('Abteilung', 'departmentId', 20); + // col.calculateSortValue = 'departmentName'; + col = this.columnConfigList.add('Role', 'webAppRoleName', 15); + // col = this.columnConfigList.add('Role', 'webAppRoleId', 15); + // col.calculateSortValue = 'webAppRoleName'; + col = this.columnConfigList.add('Zusatzabteilungen', 'extendedDepartmentNameList', 30); + col = this.columnConfigList.add('Zusatzrolen', 'additionalRoleNameList', 30); + this.columnConfigList.recalcWidth(); + } + + addItem() { + this.employeeWebappList.focusedEntityShadowed.new(); + this.employeeWebappList.focusedEntityShadowed.entity.employeeId = this.employeeDetails.entityId; + if (this.employeeDataService.employee2DepartmentList.items.length > 0) { + let mainDepId: number = 0; + const addDepIds: number[] = []; + let addDepNames = ''; + this.employeeDataService.employee2DepartmentList.items.forEach((e2d: EmployeeToDepartment) => { + if (e2d.employeeStatusId === EN_EmployeeStatus.MainFunction) { + if (mainDepId === 0) mainDepId = e2d.departmentId; + } else { + addDepIds.push(e2d.departmentId); + const depname = this.appDataService.departmentList?.items.find(dep => dep.entityId === e2d.departmentId)?.departmentName; + addDepNames += depname ? depname + ', ' : ''; + } + }); + if (mainDepId > 0) this.employeeWebappList.focusedEntityShadowed.entity.departmentId = mainDepId; + this.employeeWebappList.focusedEntityShadowed.entity.arExtendedDepartmentIdList = addDepIds; + this.employeeWebappList.focusedEntityShadowed.entity.extendedDepartmentNameList = addDepNames.slice(0, -2); + } + this.openPopupDialog(this.employeeWebappList.focusedEntityShadowed); + } + + dblClick(event: any) { + if (!this.employeeDetails.entityIsLoading) this.employeeWebappList.focusedEntityShadowed.delayedEdit(event.data['entityId'], this.editItem); + } + + editItem = () => { + this.employeeWebappList.focusedEntityShadowed.edit(); + this.openPopupDialog(this.employeeWebappList.focusedEntityShadowed); + } + + public openPopupDialog(editEntity: AppBaseEntityWrapper) { + this.employeeDetails.keyDownListenerStopped = true; + this.dialog.openDialog(EmployeeToWebAppPopupeditComponent, { + baseEntityWrapper: editEntity, + keyItemName: this.employeeDetails.entity.firstName + ' ' + this.employeeDetails.entity.lastName, + readOnly: !this.employeeDetails.inNotViewMode || !this.employeeDetails.entity.isActive, + description: (editEntity.entity.entityId === 0 ? 'Neue Webbapp zuweisen' : 'Daten zur Webbapp "' + editEntity.entity.webAppName + '" bearbeiten '), + list: this.employeeWebappList, + }, true, () => this.employeeDetails.keyDownListenerStopped = false); + } + + @HostListener('keydown', ['$event']) + onKeyDown(event: any) { + switch (event. which) { + case keycode.ENTER: + return false; + } + return true; + } + + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.html new file mode 100644 index 0000000..ea5e162 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.html @@ -0,0 +1,113 @@ +
+ +

{{description}} - {{keyItemName}}

+ + + +
+ + +
+ + + + + + + + + + + + + + + + + +
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.scss new file mode 100644 index 0000000..05aa8a2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.scss @@ -0,0 +1,38 @@ +@import 'popup-base.component'; + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid: ; + height: 100%; // 100% view height + grid-template-rows: repeat(3, 42px) auto; // row relationships + grid-template-columns: repeat(2, minmax(1px, 300px)) auto; // column relationship + grid-column-gap: 15px; + grid-row-gap: 15px; + grid-template-areas: + 'input-webapp input-adddepartment input-addrole' + 'input-department input-adddepartment input-addrole' + 'input-role input-adddepartment input-addrole' + 'buttons buttons buttons' +} + +.input-department { + grid-area: input-department; +} + +.input-adddepartment { + grid-area: input-adddepartment; +} + +.input-addrole { + grid-area: input-addrole; +} + +.input-webapp { + grid-area: input-webapp; +} + +.input-role { + grid-area: input-role; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.ts new file mode 100644 index 0000000..a4ca5cf --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component.ts @@ -0,0 +1,70 @@ +import { Component } from '@angular/core'; +import { EN_AppEntities } from '@app_consts'; +import { PopupBaseComponent } from '@app_core/components/popup-base/popup-base.component'; +import { Department } from '@app_models/basedata/department'; +import { WebApp } from '@app_models/basedata/webapp'; +import { WebAppToWebAppRole } from '@app_models/basedata/webapp-to-webapprole'; +import { WebAppAdditionalRole } from '@app_models/basedata/webappadditionalrole '; +import { EmployeeToWebApp } from '@app_models/employee-to-webapp'; +import { EmployeeDataService } from '@app_modules/employee/employee-data.service'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; + +@Component({ + selector: 'app-employee-webapp-popupedit', + templateUrl: 'employee-webapp.popupedit.component.html', + styleUrls: ['employee-webapp.popupedit.component.scss'] +}) + +export class EmployeeToWebAppPopupeditComponent extends PopupBaseComponent { + public webAppRoleList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(WebAppToWebAppRole, 'Applikation Rolenliste', EN_AppEntities.WebAppToWebAppRole); + public additionalRoleList: AppBaseEntityListWrapper = + new AppBaseEntityListWrapper(WebAppAdditionalRole, 'Applikation Rolenliste', EN_AppEntities.WebAppAdditionalRole); + + public departmentIdList: number[] = this.employeeService.employee2DepartmentList.items.map(e2d => e2d.departmentId); + + constructor( + public appDataService: AppDataService, + public employeeService: EmployeeDataService, + ) { + super(); + this.webAppRoleList.filter = this.appDataService.webAppFilter; + this.additionalRoleList.filter = this.appDataService.webAppFilter; + this.loadRoles(); + } + + + loadRoles() { + if (this.focusedItem.webAppId) { + this.appDataService.webAppFilter.webAppId = this.focusedItem.webAppId; + this.webAppRoleList.load(); + if (this.focusedItem.isNew() || this.focusedItem.additionalRoleIdList !== null) this.additionalRoleList.load(); + } else { + this.webAppRoleList.clear(); + this.additionalRoleList.clear(); + } + } + + + public get focusedItem(): EmployeeToWebApp { + return (this._focusedItem); + } + + + getWebapps = (wa: WebApp) => { + return this.focusedItem.entityId !== 0 || !this.list.items.find((item) => item['webAppId'] === wa.entityId) && wa.isActive; + } + + + public filterDepartments = (department: Department) => { + return this.departmentIdList.indexOf(department.departmentId) > -1; + } + + public save = () => { + this.focusedItem.webAppName = this.appDataService.webAppList?.getItemById(this.focusedItem.webAppId)?.webAppName; + this.focusedItem.departmentName = this.appDataService.departmentList?.getItemById(this.focusedItem.departmentId)?.departmentName; + this.focusedItem.webAppRoleName = this.appDataService.roleList?.getItemById(this.focusedItem.webAppRoleId)?.webAppRoleName; + + this.baseEntityWrapper.save(() => this.close(true)); + } +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.html new file mode 100644 index 0000000..6bc825d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.html @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Aktiv + + +
+ + + +
+ +
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.scss new file mode 100644 index 0000000..1ce85f1 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.scss @@ -0,0 +1,77 @@ +.filterCardContainer { + padding: 0; + margin: 0; + overflow: hidden; + display: grid; + width: 100%; + height: 100%; + grid-column-gap: 15px; + grid-template-rows: repeat(1, auto); + grid-template-columns: repeat(8, minmax(0, 1fr)) auto auto; + grid-template-areas: + "filterName filterShortName filterLogin filterDepartment filterWebApp filterAttribute filterEmployeeId filterMandant filterIsActive filterButtons " +} + +// @media screen and (max-width:1024px) { +// .woassays { +// font-size: 1vw; +// } +// } + +.filterIsActive{ + + margin: auto; + grid-area: filterIsActive; +} +.filterMandant { + grid-area: filterMandant; +} +.filterName { + grid-area: filterName; +} + +.filterShortName { + grid-area: filterShortName; +} + +.filterLogin { + grid-area: filterLogin; +} + +.filterWebApp { + grid-area: filterWebApp; +} + +// .filterEmail { +// grid-area: filterEmail; +// } + +.filterDepartment { + grid-area: filterDepartment; +} + +.filterEmployeeId { + grid-area: filterEmployeeId; +} + +.filterAttribute { + grid-area: filterAttribute; +} + +.filterButtons { + grid-area: filterButtons; + margin-left: auto; +} + +// .filterBtn { +// font-size: 1vw; //scales buttons caption depended from the current view port resolution +// } + +.card { + padding: 10px; + margin: 2px 2px 0px 2px; +} + +.filterButtons .filterBtn { + width: unset; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.ts new file mode 100644 index 0000000..8614e7b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-filter/employee-filter.component.ts @@ -0,0 +1,85 @@ +import * as keycode from '@angular/cdk/keycodes'; +import { AfterViewInit, Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core'; +import { Employee, EmployeeFullFilter } from '@app_models/employee'; +import { EmployeeDataService } from '@app_modules/employee/employee-data.service'; +import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import * as Cnst from '@app_core/consts'; +import { ClipboardService } from 'ngx-clipboard'; +import { AuthorizeService } from '@app_core/services/authorize.service'; +import { UINotifierService } from '@app_core/services/notification/uinotifier.service'; +import { LoginPopupComponent } from '@app_core/components/login/login-popup/login-popup.component'; +import { LocaleService } from '@app_core/services/localization/locale.service'; + +@Component({ + selector: 'app-employee-filter', + templateUrl: './employee-filter.component.html', + styleUrls: ['./employee-filter.component.scss'], +}) +export class EmployeeFilterComponent implements OnInit, AfterViewInit { + + constructor( + public employeeDataService: EmployeeDataService, + public appDataService: AppDataService, + public authService: AuthorizeService, + public localeService: LocaleService, + private clipboardService: ClipboardService, + private notifierService: UINotifierService, + ) { } + @Input() public filterObject: EmployeeFullFilter; + @Input() employeeDetails: AppBaseEntityWrapper; + @Input() employeeList: AppBaseEntityListWrapper; + @Output() public filterFetch = new EventEmitter(); + + public dropDownAllCaption = Cnst.EN_DropDownConst4Filter.AllCaption; + public dropDownAllValueString = Cnst.EN_DropDownConst4Filter.AllValueString; + public dropDownAllValueInt = Cnst.EN_DropDownConst4Filter.AllValueInt; + public allCaption = Cnst.EN_DropDownConst4Filter.AllCaption; + public allValue: number = Cnst.EN_DropDownConst4Filter.AllValueInt; + public noneCaption = Cnst.EN_DropDownConst4Filter.NoneCaption; + public noneValue = Cnst.EN_DropDownConst4Filter.NoneValueInt; + + ngOnInit() { + } + ngAfterViewInit() { } + + onFilterClick() { + if (this.employeeDetails.inViewMode) this.filterFetch.emit(); + } + + onClearClick() { + this.filterObject.filterReset(); + this.filterObject.isActive = true; + this.onFilterClick(); + } + + + + + onEmailClick() { + const listEmployeeIds = this.employeeList.items.filter((empl: Employee) => !!empl.email).map((empl: Employee) => empl.entityId); + const listEmails = this.employeeList.items.sort((empl1, empl2) => empl1.lastName.localeCompare(empl2.lastName)).map((empl: Employee) => empl.email).filter(email => !!email); + if (listEmails.length === 0) return; + this.clipboardService.copy(listEmails.join('; ')); + const endung = (listEmails.length > 1 ? 'n' : ''); + this.notifierService.showMessage(`${listEmails.length} Emailadresse${endung} wurde${endung} in die Zwischenablage gespeichert`); + } + + + @HostListener('window:keydown', ['$event']) + keyboardInput(event: any) { + if (!LoginPopupComponent.LOGIN_IS_SHOWN && !this.employeeDetails.keyDownListenerStopped) { + if (event.ctrlKey) { + switch (event.which) { + case keycode.F: //Ctrl + 'f' + event.stopPropagation(); + this.onFilterClick(); + return false; //processed + } + } + } + return true; //default processing + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.html new file mode 100644 index 0000000..7046859 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.html @@ -0,0 +1,86 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{cell.value | number:'1.0-0':culture}} +
+
+ {{cell.value | number:'1.1-1':culture}} +
+
+ {{cell.value | number:'1.2-2':culture}} +
+
+ {{cell.value | number:'1.3-3':culture}} +
+
+
+
+
+
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.scss new file mode 100644 index 0000000..8ec9070 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.scss @@ -0,0 +1,38 @@ +.EmployeeList { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-template-rows: auto minmax(0, 1fr); // row relationships + grid-template-columns: minmax(0, 1fr); // column relationship + grid-row-gap: 7px; + grid-template-areas: + 'filter' + 'grid'; +} + +.FilterComponent { + grid-area: filter; // grid area: auto height 1fr width + margin: 0 0 0 0; +} + + +.card { + grid-area: grid; + width: 100%; + padding: 0px; + margin: 0; + border-radius: 0px; + box-shadow: none; +} + +.gridEmployee { + position: absolute; // position absolut ist hier zwingend! Die position ist absolut innerhalb mehrerer parent divs und darf sich NICHT über diese hinausstrecken. + height: 100%; + width: 100%; + padding-left: 1px; + padding-right: 1px; + padding-bottom: 1px; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.ts new file mode 100644 index 0000000..3464163 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee-list/employee-list.component.ts @@ -0,0 +1,80 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { ColumnConfigList } from '@app_core/components/grid-config/columnconfiglist'; +import { Globals } from '@app_core/services/globals'; +import { LocaleService } from '@app_core/services/localization/locale.service'; +import { Employee } from '@app_models/employee'; +import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper'; +import { AppDataService } from '@app_services/app.data.service'; +import { EmployeeDataService } from '../employee-data.service'; +import { ColumnConfig, EN_Alignment, EN_SortOrder } from '@app_core/components/grid-config/columnconfig'; + +@Component({ + selector: 'app-employee-list', + templateUrl: './employee-list.component.html', + styleUrls: ['./employee-list.component.scss'] +}) +export class EmployeeListComponent implements OnInit { + @Input() public dataSource: AppBaseEntityListWrapper; + // @ViewChild('gridCatalog') dxGrid: DxDataGridComponent; + + public columnConfigList: ColumnConfigList = new ColumnConfigList(); + + + constructor( + public employeeDataService: EmployeeDataService, + public appDataService: AppDataService, + public localeService: LocaleService, + public globals: Globals, + ) { + } + + ngOnInit() { + this.initColumns(); + } + + + initColumns() { + let col: ColumnConfig; + + // col = this.columnConfigList.addNumber('id', 'EmployeeId', 7); + + if (this.appDataService.showIds) col = this.columnConfigList.addNumber('Id', 'entityId', 7, 0); + if (this.appDataService.showIds) col = this.columnConfigList.add('Nr', 'employeeNo', 7); + + col = this.columnConfigList.add('Nachname', 'lastName', 25); + col.sortIndex = 1; + col.sortOrder = EN_SortOrder.asc; + + col = this.columnConfigList.add('Vorname', 'firstName', 15); + col.sortIndex = 2; + col.sortOrder = EN_SortOrder.asc; + + // col = this.columnConfigList.add('Anrede', 'salutation', 10); + col = this.columnConfigList.add('Kürzel', 'shortName', 7); + col = this.columnConfigList.add('Position', 'position', 25); + + col = this.columnConfigList.add('Login', 'loginName', 15); + col = this.columnConfigList.add('Email', 'email', 30); + col = this.columnConfigList.add('Rang', 'rangId', 10); + + col = this.columnConfigList.add('Handynummer', 'mobilePhoneNo', 20); + col = this.columnConfigList.add('Festnetznummer', 'phoneNo', 20); + + + // if (this.appDataService.showIds) col = + col = this.columnConfigList.add('Department', 'departmentNamesList', 30); + col = this.columnConfigList.add('Webapps', 'webappNamesList', 25); + col = this.columnConfigList.add('Merkmale', 'attributeNamesList', 20); + // this.columnConfigList.addNumber('Firma-Id', 'clientId', 7); + col = this.columnConfigList.add('Mandant', 'mandantCode', 15); + col = this.columnConfigList.addBoolean('Aktiv', 'isActive', -50); + col.alignment = EN_Alignment.left; + + this.columnConfigList.recalcWidth(); + } + + + public loadData() { + this.employeeDataService.loadData(); + } +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.html b/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.html new file mode 100644 index 0000000..d04d7c0 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.html @@ -0,0 +1,4 @@ +
+ + +
diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.scss b/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.scss new file mode 100644 index 0000000..c990dc3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.scss @@ -0,0 +1,22 @@ +.EmployeeComponent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-template-rows: minmax(0, 1fr) auto; // row relationships + grid-template-columns: minmax(0, 1fr); // column relationship + grid-template-areas: 'list''details'; + grid-column-gap: 5px; + grid-row-gap: 5px; +} + +.EmployeeListComponent { + grid-area: list; +} + +.EmployeeDetailsComponent { + grid-area: details; + z-index: 10; +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.ts new file mode 100644 index 0000000..26c0382 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; +import { EmployeeDataService } from './employee-data.service'; + +@Component({ + selector: 'app-employee', + templateUrl: './employee.component.html', + styleUrls: ['./employee.component.scss'] +}) +export class EmployeeComponent implements OnInit { + + constructor( + public employeeDataService: EmployeeDataService + ) { } + + ngOnInit() { + } + +} diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee.module.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee.module.ts new file mode 100644 index 0000000..c139822 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee.module.ts @@ -0,0 +1,59 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { FormsModule } from '@angular/forms'; +import { AngularMaterialModule } from '@app_core/components/angular-material.module'; +import { DxButtonModule, DxDataGridModule, DxFileUploaderModule, DxPieChartModule, DxTemplateModule, DxTooltipModule } from 'devextreme-angular'; +import { EmployeeAttributeComponent } from './employee-detail/employee-attribute/employee-attribute.component'; +import { EmployeeContentComponent } from './employee-detail/employee-content/employee-content.component'; +import { EmployeeDepartmentComponent } from './employee-detail/employee-department/employee-department.component'; +import { EmployeeToDepartmentPopupeditComponent } from './employee-detail/employee-department/employee-department.popupedit/employee-department.popupedit.component'; +import { EmployeeDetailComponent } from './employee-detail/employee-detail.component'; +import { EmployeeWebappComponent } from './employee-detail/employee-webapp/employee-webapp.component'; +import { EmployeeToWebAppPopupeditComponent } from './employee-detail/employee-webapp/employee-webapp.popupedit/employee-webapp.popupedit.component'; +import { EmployeeFilterComponent } from './employee-list/employee-filter/employee-filter.component'; +import { EmployeeListComponent } from './employee-list/employee-list.component'; +import { EmployeeComponent } from './employee.component'; +import { EmployeeRoutingModule } from './employee.routing.module'; +import { HenselSelectionComponent } from '@app_core/components/hensel-selection/hensel-selection.component'; +import { HenselInputComponent } from '@app_core/components/hensel-input/hensel-input.component'; +import { NgxMaskDirective, NgxMaskPipe } from 'ngx-mask'; +import { HenselMaskDecimalDirective } from '@app_core/directives/hensel-decimal.directive'; +import { HenselValidator } from '@app_core/validators/hensel-validator.directive'; + + +@NgModule({ + declarations: [ + EmployeeComponent, + EmployeeListComponent, + EmployeeContentComponent, + EmployeeAttributeComponent, + EmployeeDetailComponent, + EmployeeFilterComponent, + EmployeeWebappComponent, + EmployeeDepartmentComponent, + EmployeeToDepartmentPopupeditComponent, + EmployeeToWebAppPopupeditComponent + ], + imports: [ + CommonModule, + EmployeeRoutingModule, + AngularMaterialModule, + DxDataGridModule, + FormsModule, + HenselSelectionComponent, + HenselInputComponent, + HenselMaskDecimalDirective, + HenselValidator, + DxFileUploaderModule, + DxButtonModule, + DxTooltipModule, + DxTemplateModule, + DxPieChartModule, + NgxMaskDirective, + NgxMaskPipe, + ], + providers: [], + exports: [] +}) +export class EmployeeModule { } diff --git a/ClientApp/staff-db-ui/src/app/modules/employee/employee.routing.module.ts b/ClientApp/staff-db-ui/src/app/modules/employee/employee.routing.module.ts new file mode 100644 index 0000000..c97529c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/modules/employee/employee.routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { EmployeeComponent } from './employee.component'; +import { AuthGuard } from '@app_core/services/authguard'; + +const routes: Routes = [ + { + path: '**', + component: EmployeeComponent, + canActivate: [AuthGuard] + }, +]; + + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class EmployeeRoutingModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/app.consts.ts b/ClientApp/staff-db-ui/src/app/shared/app.consts.ts new file mode 100644 index 0000000..4f59b41 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/app.consts.ts @@ -0,0 +1,97 @@ +import { IENVIRONMENT } from '@app_core/injection-tokens'; +import { ACCOUNT_PAGE, IAppPage, LOGIN_PAGE } from '@app_core/services/globals'; + +export const SUPPORTED_LANGUAGES = ['de', 'en']; + +declare const environment: IENVIRONMENT; +export const APP_TITLE: string = environment['APP_TITLE'] ?? 'StaffDB'; +export const cnst_DefaultCulture = environment.culture ?? 'de-DE'; +export const cnst_DefaultLanguage = environment.language ?? 'de'; + +// page description, wich is used for routing as well for preparing routings menus and intern for page loading +export const APP_PAGES: IAppPage[] = [ + { + caption: 'Mitarbeiter', + path: 'employee', + loadChildren: () => import('@app_modules/employee/employee.module').then(m => m.EmployeeModule), + icon: '', + messageCaption: 'Employee', + }, + { + caption: 'Abteilungen', + path: 'departments', + loadChildren: () => import('@app_modules/department/department.module').then(m => m.DepartmentModule), + icon: '', + messageCaption: 'Department', + }, + ACCOUNT_PAGE, + LOGIN_PAGE, +]; + +// named constants to access the arry APP_PAGES + +export const enum EN_AppPages { + Employee = 0, + Department = 1, + Settings = 2, + Login = 3, +} + +// named constants with numbers of http requests of data loading for every page for maintain of spinner + +export const enum EN_HttpQueriesCount4Page { + Employee = 1, + Department = 1, + Login = 10, //no of quires in load stammdata +} + +export function getPageIndex(page: string): number { + return APP_PAGES.findIndex((pg) => pg.path === page); +} + + +export enum EN_AppEntities { + //-- base data entities + Employee = 'employee', + CostCentre = 'costcentre', + Vendor = 'vendor', + EmployeeStatus = 'employeestatus', + Rang = 'rang', + DocumentArt = 'documentart', + Project = 'project', + Department = 'department', + WindreamSearch = 'windreamsearch', + WindreamIndex = 'windreamindex', + WindreamIndexToWindreamSearchToDepartment = 'windreamindextowindreamsearchtodepartment', + WindreamSearchToDepartment = 'windreamsearchtodepartment', + WindreamSearchItemToWindreamSearchToDepartment = 'windreamsearchitemtowindreamsearchtodepartment', + WindreamSearchItem = 'windreamsearchitem', + DocumentArtToDepartment = 'documentarttodepartment', + EmployeeToDepartment = 'employeetodepartment', + EmployeeToWebapp = 'employeetowebapp', + WebApp = 'webapp', + WebAppRole = 'webapprole', + WebAppToDepartment = 'webapptodepartment', + WebAppToWebAppRole = 'webapptowebapprole', + EmployeeAttribute = 'employeeattribute', + EmployeeToAttribute = 'employeetoattribute', + WebAppAdditionalRole = 'webappadditionalrole', + WebAppToWebAppAdditionalRole = 'webapptowebappadditionalrole', + WindreamSearchToDepartmentCopyWindreamTile = 'windreamSearchToDepartment/CopyWindreamTile', + DepartmentCopyWindreamTiles = 'department/copyWindreamTiles', + Subsidiary = 'Subsidiary' +} + + +export enum EN_EmployeeStatus { + MainFunction = 1, + AdditionalFunction = 2, +} + + +export enum EN_EmployeeRang { + Mitarbeiter = 4, +} + + +export const cnst_LoadedEntitiesExpiresInMs = 30000; //30s diff --git a/ClientApp/staff-db-ui/src/app/shared/app.types.ts b/ClientApp/staff-db-ui/src/app/shared/app.types.ts new file mode 100644 index 0000000..ca858dd --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/app.types.ts @@ -0,0 +1,4 @@ +import { BaseEntityCallBack, ErrorCallBack } from '@app_core/models/generics/baseentity'; + +export declare type AppBaseEntityCallBack = BaseEntityCallBack; +export declare type AppErrorCallBack = ErrorCallBack; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/at.svg b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/at.svg new file mode 100644 index 0000000..99f7814 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/at.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/au.svg b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/au.svg new file mode 100644 index 0000000..9ba68fb --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/au.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/de.svg b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/de.svg new file mode 100644 index 0000000..834f82f --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/de.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/fr.svg b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/fr.svg new file mode 100644 index 0000000..a4bded5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/fr.svg @@ -0,0 +1,2 @@ + + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/gb.svg b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/gb.svg new file mode 100644 index 0000000..56487b0 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/gb.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/ko.svg b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/ko.svg new file mode 100644 index 0000000..dbec9be --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/ko.svg @@ -0,0 +1,13 @@ + + +Flag of South Korea + + + + + + + + + + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/my.svg b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/my.svg new file mode 100644 index 0000000..79cebc2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/my.svg @@ -0,0 +1,11 @@ + + +Flag of Malaysia + + + + + + + + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/us.svg b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/us.svg new file mode 100644 index 0000000..c31e895 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/flags/us.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_bright.ico b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_bright.ico new file mode 100644 index 0000000..bc6c2d1 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_bright.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_color.ico b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_color.ico new file mode 100644 index 0000000..d65b48a Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_color.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_color3d.ico b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_color3d.ico new file mode 100644 index 0000000..917acf3 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_color3d.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_red.ico b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_red.ico new file mode 100644 index 0000000..7e7f832 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_red.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_white.ico b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_white.ico new file mode 100644 index 0000000..ff4f496 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/assets/icons/hr-logo_white.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/json/package.json b/ClientApp/staff-db-ui/src/app/shared/core/assets/json/package.json new file mode 100644 index 0000000..8c13a75 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/json/package.json @@ -0,0 +1,54 @@ +{ + "name": "@hensel-recycling/hr-core", + "version": "14.2.3", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e", + "reinstall:packages": "rm -rf node_modules dist && npm cache clean --force && rm package-lock.json && npm install", + "win_reinstall:packages": "rd /s /q node_modules && npm cache clean --force && del package-lock.json && npm install", + "add_pwa": "ng add @angular/pwa@latest" + }, + "peerDependencies": { + "@angular/cdk": "^14.1.0", + "@angular/common": "^14.1.0", + "@angular/core": "^14.1.0", + "@angular/forms": "^14.1.0", + "@angular/material": "^14.1.0", + "@angular/platform-browser-dynamic": "^14.1.0", + "@angular/router": "^14.1.0", + "@angular/service-worker": "^14.1.1", + "@ngx-translate/core": "latest", + "@sentry/angular": "latest", + "angular-in-memory-web-api": "^0.14.0", + "devextreme": "latest", + "devextreme-angular": "latest", + "moment": "latest", + "ngx-device-detector": "^4.0.1", + "ngx-spinner": "^14.0.0", + "ngx-translate-multi-http-loader": "^8.0.2", + "ngx-webcam": "latest", + "rxjs": "latest", + "zone.js": "latest" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.1.0", + "@angular/cli": "^14.1.0", + "@angular/compiler-cli": "^14.1.0", + "@angular/language-service": "^14.1.0", + "@types/node": "latest", + "codelyzer": "latest", + "ng-packagr": "^14.2.0", + "ts-node": "latest", + "tslint": "latest", + "typescript": "^4.8.3" + }, + "keywords": [ + "hr-core" + ], + "author": "itentwicklung@hensel-recycling.com" +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/de.json b/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/de.json new file mode 100644 index 0000000..22588e9 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/de.json @@ -0,0 +1,110 @@ +{ + "core.btn.ok": "Ok", + "core.btn.yes": "Ja", + "core.btn.no": "Nein", + "core.btn.cancel": "Abbrechen", + "core.btn.apply": "Übernehmen", + "core.btn.reset": "Reset", + "core.hint.reset": "Zurücksetzen", + "core.hint.undo": "Änderungen verwerfen", + "core.btn.undo": "Verwerfen", + "core.btn.search": "Suchen", + + "core.dropdown-option.all": "< Alle >", + "core.dropdown-option.none": "< Keine >", + + "core.caption.login": "Login", + "core.caption.hidepassword": "Hide password", + "core.caption.registration": "Anmeldung", + "core.caption.logout": "Logout", + "core.caption.config": "Einstellungen", + "core.caption.version": "Version", + "core.caption.username": "Benutzername", + "core.caption.password": "Passwort", + "core.caption.account": "Konto", + "core.caption.all": "Alle", + "core.caption.none": "Keine", + "core.caption.serverinfo-pollinginterval": "Abstang für Erneuerung von Serverver Info (Sek., 0-nie)", + + "core.msg.saving": "Speichern {{value}}...", + "core.msg.saved": "Gespeichert {{value}}", + "core.msg.loading": "Laden {{value}}...", + "core.msg.loaded": "Geladen {{value}}: {{count}}", + "core.msg.loggedon": "Benutzeranmeldung für {{value}} war erfolgreich", + "core.msg.renewJWT": "Versuche zu verlängern von JWT", + "core.msg.waitingconnecton": "Warte auf Verbindung...", + "core.msg.checkuser": "Benutzer wird überprüft...", + "core.msg.greeting": "Hallo", + "core.msg.update": "Bitte aktualisieren!", + "core.hint.update": "Klicke um die Version zu aktualisieren", + + "core.error.loading": "Fehler beim Laden von {{value}}", + "core.error.saving": "Fehler beim Speichern von {{value}}", + "core.error.deleting": "Fehler beim Löschen von {{value}}", + "core.error.nouserrole": "Keine Benutzerrole ist zugewiesen!", + "core.error.logon": "Anmeldung ist fehlgeschlagen!", + "core.error.logonnotpossible": "{{value}}Anmeldung ist nicht möglich!", + "core.error.disclaimernotconfirmed": "Haftungsausschluss muss bestätigt werden!", + + "core.msgbox.header.cancel": "{{value}}", + "core.msgbox.body.cancel": "Sollen Änderungen gespeichert werden?", + "core.msgbox.header.delete": "{{value}}", + "core.msgbox.body.delete": "Soll {{value}} gelöscht werden?", + "core.msgbox.header.connect": "Verbindungsaufbau", + "core.msgbox.body.connect": "Keine Verbindung zum Server kann aufgebaut werden. Bitte wenden sie sich an IT-Entwicklung", + + "core.grid.nodata": "Keine Daten vorhanden", + "core.hdatepicker.dateoutofrange": "Das Datum ist ausser zulässigem Bereich", + + "core.hensel-selection.nohits": "Keine Treffer gefunden", + "core.hensel-selection.selectedfirst": "Selektierte zuerst", + "core.hensel-selection.processlist": "Liste bearbeiten", + "core.hensel-selection.inputminsybols": "Für Auswahl mind. {{value}} Zeichen eingeben", + + "core.hwebcam.delete": "Foto löschen", + "core.hwebcam.takepicture": "Foto aufnehmen", + + "core.footer.status": "Status", + "core.footer.noconnection": "Keine Verbindung ist vorhanden !!!", + "core.footer.lastloading": "Letzte Datenabruf", + "core.footer.loginexpires": "Anmeldung läuft ab in", + "core.footer.days": "Tag(e)", + "core.footer.hours": "Std.", + "core.footer.mins": "Min.", + "core.footer.secs": "Sek.", + + "core.account.caption.price": "Preis", + "core.account.caption.weight" : "Gewicht", + + "core.caption.date": "Datum", + "core.caption.user": "Benutzer", + "core.caption.role": "Rolle", + "core.caption.myaccount": "Mein Konto", + "core.caption.disclaimer": "Haftungsausschluss", + + "core.caption.addsettings" : "Admineinstellungen", + "core.caption.showstatusbar" : "Statuszeile anzeigen", + "core.caption.showids" : "Ids anzeigen", + "core.caption.language" : "Sprache", + "core.caption.regionformat" : "Regionales Format", + "core.caption.name": "Name", + "core.caption.userloginname": "Benutzername", + + "core.caption.country-ge": "Deutschland", + "core.caption.country-at": "Österrecih", + "core.caption.country-gb": "Grossbritanien", + "core.caption.country-us": "United States", + "core.caption.country-au": "Australien", + "core.caption.country-fr": "Frankreich", + "core.caption.country-kr": "Korea", + "core.caption.country-my": "Malaysia", + + "core.caption.lang-ge": "Deutsch", + "core.caption.lang-at": "Deutsch", + "core.caption.lang-gb": "Englisch", + "core.caption.lang-us": "Englisch", + "core.caption.lang-au": "Englisch", + "core.caption.lang-fr": "Französisch", + "core.caption.lang-kr": "Koreanisch", + "core.caption.lang-my": "Malaiisch" +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/en.json b/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/en.json new file mode 100644 index 0000000..d47f49c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/en.json @@ -0,0 +1,110 @@ +{ + "core.btn.ok": "Ok", + "core.btn.yes": "Yes", + "core.btn.no": "No", + "core.btn.cancel": "Cancel", + "core.btn.apply": "Apply", + "core.btn.reset": "Reset", + "core.hint.reset": "Reset", + "core.hint.undo": "Discard changes", + "core.btn.undo": "Discard", + "core.btn.search": "Search", + + "core.dropdown-option.all": "< All >", + "core.dropdown-option.none": "< None >", + + "core.caption.login": "Login", + "core.caption.hidepassword": "Hide password", + "core.caption.registration": "Log in", + "core.caption.logout": "Logout", + "core.caption.config": "Configuration", + "core.caption.version": "Version", + "core.caption.username": "Username", + "core.caption.password": "Password", + "core.caption.account": "Account", + "core.caption.all": "All", + "core.caption.none": "None", + "core.caption.serverinfo-pollinginterval": "Interval to refresh of Serverver Info (sec., 0-never)", + + "core.msg.saving": "Saving {{value}}...", + "core.msg.saved": "Saved {{value}}", + "core.msg.loading": "Loading {{value}}...", + "core.msg.loaded": "Loaded {{value}}: {{count}}", + "core.msg.loggedon": "Logon for {{value}} succeeded", + "core.msg.renewJWT": "Try to renew JWT", + "core.msg.waitingconnecton": "Waiting connection...", + "core.msg.checkuser": "Check user...", + "core.msg.greeting": "Hello", + "core.msg.update": "Please update!", + "core.hint.update": "Click to update the version", + + "core.error.loading": "Error during loading of {{value}}", + "core.error.saving": "Error during saving of {{value}}", + "core.error.deleting": "Error during deleting of {{value}}", + "core.error.nouserrole": "User is assigned no role!", + "core.error.logon": "Logon failed!", + "core.error.logonnotpossible": "{{value}}Logon is not possible!", + "core.error.disclaimernotconfirmed": "Disclaimer must be confirmed!", + + "core.msgbox.header.cancel": "{{value}}", + "core.msgbox.body.cancel": "Save changes?", + "core.msgbox.header.delete": "{{value}}", + "core.msgbox.body.delete": "Delete {{value}}?", + "core.msgbox.header.connect": "Establish connection", + "core.msgbox.body.connect": "The server connot be connected. Please contact IT-Development", + + "core.grid.nodata": "No data", + "core.hdatepicker.dateoutofrange": "The date is out of range", + + "core.hensel-selection.nohits": "No hits", + "core.hensel-selection.selectedfirst": "Selected first", + "core.hensel-selection.processlist": "Edit list", + "core.hensel-selection.inputminsybols": "For selection input at least {{value}} symbols", + + "core.hwebcam.delete": "Delete picture", + "core.hwebcam.takepicture": "Take picture", + + "core.footer.status": "Status", + "core.footer.noconnection": "No connectoin to the server !!!", + "core.footer.lastloading": "Last Dataloading", + "core.footer.loginexpires": "Login expires in", + "core.footer.days": "Day(s)", + "core.footer.hours": "Hr(s)", + "core.footer.mins": "Min(s)", + "core.footer.secs": "Sec(s)", + + "core.account.caption.price": "Price", + "core.account.caption.weight" : "Weight", + + "core.caption.date": "Date", + "core.caption.user": "User", + "core.caption.role": "Role", + "core.caption.myaccount": "My Account", + "core.caption.disclaimer": "Disclaimer", + + "core.caption.addsettings" : "Admin Settings", + "core.caption.showstatusbar" : "Show Statusbar", + "core.caption.showids" : "Show Ids", + "core.caption.language" : "Language", + "core.caption.regionformat" : "Regional Format", + "core.caption.name": "Name", + "core.caption.userloginname": "Loginname", + + "core.caption.country-ge": "Germany", + "core.caption.country-at": "Austria", + "core.caption.country-gb": "United Kingdom", + "core.caption.country-us": "United States", + "core.caption.country-au": "Australia", + "core.caption.country-fr": "France", + "core.caption.country-kr": "Korea", + "core.caption.country-my": "Malaysia", + + "core.caption.lang-ge": "German", + "core.caption.lang-at": "German", + "core.caption.lang-gb": "English", + "core.caption.lang-us": "English", + "core.caption.lang-au": "English", + "core.caption.lang-fr": "French", + "core.caption.lang-kr": "Korean", + "core.caption.lang-my": "Malay" +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/fr.json b/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/fr.json new file mode 100644 index 0000000..a3ab918 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/assets/translate-core/fr.json @@ -0,0 +1,107 @@ +{ + "core.btn.ok": "Ok", + "core.btn.yes": "Yes", + "core.btn.no": "No", + "core.btn.cancel": "Cancel", + "core.btn.apply": "Accept", + "core.btn.reset": "Reset", + "core.hint.reset": "Reset", + "core.btn.search": "Search", + + "core.dropdown-option.all": "< All >", + "core.dropdown-option.none": "< None >", + + "core.caption.login": "Login", + "core.caption.registration": "Log in", + "core.caption.logout": "Logout", + "core.caption.config": "Configuration", + "core.caption.version": "Version", + "core.caption.username": "Username", + "core.caption.password": "Password", + "core.caption.account": "Account", + "core.caption.all": "All", + "core.caption.none": "None", + "core.caption.serverinfo-pollinginterval": "Interval to refresh of Serverver Info (sec., 0-never)", + + "core.msg.saving": "Saving {{value}}...", + "core.msg.saved": "Saved {{value}}", + "core.msg.loading": "Loading {{value}}...", + "core.msg.loaded": "Loaded {{value}}: {{count}}", + "core.msg.loggedon": "Logon for {{value}} succeeded", + "core.msg.renewJWT": "Try to renew JWT", + "core.msg.waitingconnecton": "Waiting connection...", + "core.msg.checkuser": "Check user...", + "core.msg.greeting": "Hello", + "core.msg.update": "Please update!", + "core.hint.update": "Click to update the version", + + "core.error.loading": "Error during loading of {{value}}", + "core.error.saving": "Error during saving of {{value}}", + "core.error.deleting": "Error during deleting of {{value}}", + "core.error.nouserrole": "User is assigned no role!", + "core.error.logon": "Logon failed!", + "core.error.logonnotpossible": "{{value}}Logon is not possible!", + "core.error.disclaimernotconfirmed": "Disclaimer must be confirmed!", + + "core.msgbox.header.cancel": "Cancelling of processing of {{value}}", + "core.msgbox.body.cancel": "{{value}} was changed. Should changes be saved?", + "core-confirmmsgheader_delete": "Deleting of {{value}}", + "core.msgbox.body.delete": "Should {{value}} be deleted?", + "core-confirmmsgheader_connect": "Establish connection", + "core.msgbox.body.connect": "The server connot be connected. Please contact IT-Development", + + "core.grid.nodata": "No data", + "core.hdatepicker.dateoutofrange": "The date is out of range", + + "core.hensel-selection.nohits": "No hits", + "core.hensel-selection.selectedfirst": "Selected first", + "core.hensel-selection.processlist": "Edit list", + "core.hensel-selection.inputminsybols": "For selection input at least {{value}} symbols", + + "core.hwebcam.takepicture": "Take picture", + "core.hwebcam.delete": "Delete picture", + + "core.footer.status": "Status", + "core.footer.noconnection": "No connectoin to the server !!!", + "core.footer.lastloading": "Last Dataloading", + "core.footer.loginexpires": "Login expires in", + "core.footer.days": "Day(s)", + "core.footer.hours": "Hr(s)", + "core.footer.mins": "Min(s)", + "core.footer.secs": "Sec(s)", + + "core.account.caption.price": "Price", + "core.account.caption.weight" : "Weight", + + "core.caption.date": "Date", + "core.caption.user": "User", + "core.caption.role": "Role", + "core.caption.myaccount": "My Account", + "core.caption.disclaimer": "Disclaimer", + + "core.caption.addsettings" : "Admin Settings", + "core.caption.showstatusbar" : "Show Statusbar", + "core.caption.showids" : "Show Ids", + "core.caption.language" : "Language", + "core.caption.regionformat" : "Regional Format", + "core.caption.name": "Name", + "core.caption.userloginname": "Loginname", + + "core.caption.country-ge": "Germany", + "core.caption.country-at": "Austria", + "core.caption.country-gb": "United Kingdom", + "core.caption.country-us": "United States", + "core.caption.country-au": "Australia", + "core.caption.country-fr": "France", + "core.caption.country-kr": "Korea", + "core.caption.country-my": "Malaysia", + + "core.caption.lang-ge": "German", + "core.caption.lang-at": "German", + "core.caption.lang-gb": "English", + "core.caption.lang-us": "English", + "core.caption.lang-au": "English", + "core.caption.lang-fr": "French", + "core.caption.lang-kr": "Korean", + "core.caption.lang-my": "Malay" +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/account/account-routing.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account-routing.module.ts new file mode 100644 index 0000000..24c9026 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { AuthGuard } from '../../services/authguard'; +import { AccountComponent } from './account.component'; + + +const routes: Routes = [ + { + path: '', + component: AccountComponent, + canActivate: [AuthGuard] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AccountRoutingModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.html new file mode 100644 index 0000000..5b93632 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.html @@ -0,0 +1,86 @@ +
+ + + + + {{'core.caption.myaccount' | translate}} + + + + + + + + + + + + + + + +
+ + +
{{'core.caption.date' | translate}}:
+
{{today | date:'shortDate'}}
+
{{'core.account.caption.weight' | translate}}:
+
{{0.74 | number:'1.3-3'}} kg
+
{{'core.account.caption.price' | translate}}:
+
{{44357.00 | currency:currencySymbol:"symbol":"1.2-2"}}
+
+ +
+
+ + + + {{'core.caption.addsettings' | translate}} + + +
+
+ {{'core.caption.showstatusbar' | translate}} +
+
+ {{'core.caption.showids' | translate}} +
+
+ +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.scss new file mode 100644 index 0000000..eb15301 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.scss @@ -0,0 +1,149 @@ +.ConfigContainer { + width: 100%; + height: 100%; + display: grid; + grid-template-rows: auto auto minmax(0, 1fr); + grid-template-columns: minmax(0, 1fr); + grid-template-areas: + "profile" + "other-settings" + "admin-settings" + ; + overflow: hidden; + grid-gap: 0.9em; +} + +.profile { + grid-area: profile; +} + +.admin-settings { + grid-area: admin-settings; + height: fit-content; +} + +.other-settings { + grid-area: other-settings; +} + +.admin-content{ + display: grid; + grid-template-columns: 250px 1fr; + grid-template-areas: "admin-std admin-custom"; + grid-gap: 0.5em; + column-gap: 2em; + overflow: hidden; +} + +.admin-custom { + grid-area: admin-custom; +} + +.setting-card { + margin-left: 1px; + margin-right: 2px !important; + margin-top: 1px; + margin-bottom: 1px; +} + +.abstand { + margin-bottom: 10px; +} + +.logout { + margin-left: auto; + font-size: large; + padding-right: 15px !important; + padding-left: 15px !important;} + +.logout-icon { + vertical-align: middle; + margin-right: 10px; +} + +.profile-content { + width: 100%; + height: calc(100% - 38px); + display: grid; + grid-template-rows: auto auto auto; + grid-template-columns: 250px auto 1fr; + grid-template-areas: + "user-name culture_section profile-custom" + "user-loginname culture_section profile-custom" + "language culture_section profile-custom"; + overflow: hidden; + grid-gap: 0.5em; + column-gap: 2em; +} + +.profile-custom { + grid-area: profile-custom; +} + +.user-name { + grid-area: user-name; +} + +.user-loginname { + grid-area: user-loginname; +} + +.culture_section { + grid-area: culture_section; + width: 100%; + height: 100%; + display: grid; + grid-template-rows: repeat(4, auto); + grid-template-columns: 1fr 1fr; + grid-template-areas: + "culture culture" + "sample-date-capt sample-date" + "sample-weight-capt sample-weight" + "sample-price-capt sample-price"; + overflow: hidden; + grid-gap: 0.5em; + column-gap: 1em; +} + + +.culture { + grid-area: culture; + width: 250px; +} + +.user-name { + grid-area: user-name; +} + +.sample-date-capt { + grid-area: sample-date-capt; +} + +.sample-date { + grid-area: sample-date; +} + +.sample-weight-capt { + grid-area: sample-weight-capt; +} + +.sample-weight { + grid-area: sample-weight; +} + +.sample-price-capt { + grid-area: sample-price-capt; +} + +.sample-price { + grid-area: sample-price; +} + + +.language { + grid-area: language; +} + +::ng-deep .ConfigContainer .mat-card-header-text { + margin-left: 0px; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.ts new file mode 100644 index 0000000..6854aec --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.component.ts @@ -0,0 +1,80 @@ +import { Component, inject, Inject, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { SUPPORTED_CULTURES_TOKEN, SUPPORTED_LANGUAGES_TOKEN } from '../..//injection-tokens'; +import * as Cnst from '../../consts'; +import { Globals } from '../../services/globals'; +import { CoreUser } from '../../models/coreuser'; +import { AuthorizeService } from '../../services/authorize.service'; +import { RepositoryService } from '../../services/http/repository.service'; +import { LocaleService } from '../../services/localization/locale.service'; +import { ServerInfoService } from '../../services/serverinfo.service'; +import * as Utils from '../../utils'; + +@Component({ + selector: 'app-account', + templateUrl: './account.component.html', + styleUrls: ['./account.component.scss'] +}) +export class AccountComponent implements OnInit { + public noneCaption: string = Cnst.EN_DropDownConst4Filter.NoneCaption; + public noneValue: number = Cnst.EN_DropDownConst4Filter.NoneValueInt; + public webAppIdList: number[] = []; + public usedCultures: Cnst.SupportedCulture[]; + public usedLanguages: Cnst.SupportedLanguage[]; + public today: Date; + public currencySymbol: string; + public get user(): CoreUser { + return this.authService.user; + } + + public globals: Globals = inject(Globals); + protected router: Router = inject(Router); + + public authService: AuthorizeService = inject(AuthorizeService); + public serverInfoService: ServerInfoService = inject(ServerInfoService); + public localeService: LocaleService = inject(LocaleService); + protected repositoryService: RepositoryService = inject(RepositoryService); + protected APP_SUPPORTED_CULTURES: string[] = inject(SUPPORTED_CULTURES_TOKEN); + protected APP_SUPPORTED_LANGUAGES: string[] = inject(SUPPORTED_LANGUAGES_TOKEN); + + + constructor( + ) { + } + + + ngOnInit() { + this.usedLanguages = Cnst.SUPPORTED_LANGUAGES.filter((lang: Cnst.SupportedLanguage) => Utils.isLanguageSupported(lang.langCode, this.APP_SUPPORTED_LANGUAGES)); + this.usedCultures = Cnst.SUPPORTED_CULTURES.filter((cltr: Cnst.SupportedCulture) => Utils.isCultureSupported(cltr.culture, this.APP_SUPPORTED_CULTURES)); + this.today = Utils.today(); + this.currencySymbol = Utils.getCurrencySymbol(this.localeService.currentCulture); + } + + logout() { + this.authService.logout(true); + } + + setLocale(culture: string) { + this.localeService.currentCulture = culture; + this.currencySymbol = Utils.getCurrencySymbol(this.localeService.currentCulture); + this.saveCultureLanguage(); + } + + setLangauge(lang: string) { + this.localeService.currentLanguage = lang; + this.saveCultureLanguage(); + } + + + saveCultureLanguage() { + this.user.culture = this.localeService.currentCulture; + this.user.language = this.localeService.currentLanguage; + this.user.save(this.repositoryService, null, null, null, 'culture'); + } + + + goHome() { + this.router.navigate(['/' + this.globals.mainPage.path]); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.module.ts new file mode 100644 index 0000000..e9f9ec2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/account/account.module.ts @@ -0,0 +1,31 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { AccountRoutingModule } from './account-routing.module'; +import { AccountComponent } from './account.component'; +import { ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { DxDataGridModule } from 'devextreme-angular'; +import { DxoSearchPanelModule } from 'devextreme-angular/ui/nested'; +import { TranslateModule } from '@ngx-translate/core'; +import { AngularMaterialModule } from '../angular-material.module'; +import { HenselSelectionComponent } from '../hensel-selection/hensel-selection.component'; +import { HenselInputComponent } from '../hensel-input/hensel-input.component'; + + +@NgModule({ + declarations: [AccountComponent], + imports: [ + CommonModule, + AccountRoutingModule, + AngularMaterialModule, + ReactiveFormsModule, + FormsModule, + DxDataGridModule, + DxoSearchPanelModule, + HenselSelectionComponent, + HenselInputComponent, + TranslateModule + ], + exports: [AccountComponent] +}) +export class AccountModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/angular-material-index.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/angular-material-index.ts new file mode 100644 index 0000000..c3e96ac --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/angular-material-index.ts @@ -0,0 +1,53 @@ +export { + MatLegacyOptionSelectionChange as MatOptionSelectionChange, + _countGroupLabelsBeforeLegacyOption as _countGroupLabelsBeforeOption, + _getLegacyOptionScrollPosition as _getOptionScrollPosition +} from '@angular/material/legacy-core'; +export { + MatLegacyAutocomplete as MatAutocomplete, + MatLegacyAutocompleteTrigger as MatAutocompleteTrigger, + MatLegacyAutocompleteModule as MatAutocompleteModule +} from '@angular/material/legacy-autocomplete'; +export { MatNativeDateModule } from '@angular/material/core'; +export { MatToolbarModule } from '@angular/material/toolbar'; +export { MatButtonToggleModule } from '@angular/material/button-toggle'; +export { + MatLegacySnackBarModule as MatSnackBarModule, + MatLegacySnackBar as MatSnackBar, + MatLegacySnackBarConfig as MatSnackBarConfig, + MatLegacySnackBarHorizontalPosition as MatSnackBarHorizontalPosition, + MatLegacySnackBarRef as MatSnackBarRef, + MatLegacySnackBarVerticalPosition as MatSnackBarVerticalPosition, + LegacyTextOnlySnackBar as TextOnlySnackBar +} from '@angular/material/legacy-snack-bar'; +export { MatLegacyTabsModule as MatTabsModule } from '@angular/material/legacy-tabs'; +export { MatLegacyMenuModule as MatMenuModule } from '@angular/material/legacy-menu'; +export { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button'; +export { + MatLegacyDialogModule as MatDialogModule, + MatLegacyDialogRef as MatDialogRef, + MatLegacyDialog as MatDialog, + MatLegacyDialogConfig as MatDialogConfig, + MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA + } from '@angular/material/legacy-dialog'; +export { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox'; +export { MatLegacyCardModule as MatCardModule } from '@angular/material/legacy-card'; +export { MatLegacyPaginatorModule as MatPaginatorModule } from '@angular/material/legacy-paginator'; +export { MatLegacyTableModule as MatTableModule } from '@angular/material/legacy-table'; +export { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip'; +export { MatDatepickerModule } from '@angular/material/datepicker'; +export { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select'; +export { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy-input'; +export { + MatLegacyFormFieldModule as MatFormFieldModule, + MatLegacyFormField as MatFormField, + MAT_LEGACY_FORM_FIELD_DEFAULT_OPTIONS as MAT_FORM_FIELD_DEFAULT_OPTIONS +} from '@angular/material/legacy-form-field'; +export { MatGridListModule } from '@angular/material/grid-list'; +export { MatLegacyListModule as MatListModule } from '@angular/material/legacy-list'; +export { MatBadgeModule } from '@angular/material/badge'; +export { MatSidenavModule } from '@angular/material/sidenav'; +export { MatIconModule } from '@angular/material/icon'; +export { MatLegacyRadioModule as MatRadioModule } from '@angular/material/legacy-radio'; +export { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips'; +export { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner'; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/angular-material.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/angular-material.module.ts new file mode 100644 index 0000000..14dd105 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/angular-material.module.ts @@ -0,0 +1,100 @@ +import { NgModule } from '@angular/core'; +/*import { + MatAutocompleteModule, MatBadgeModule, MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatChipsModule, MatDatepickerModule, + MatDialogModule, MatFormFieldModule, MatGridListModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatPaginatorModule, + MatProgressSpinnerModule, MatRadioModule, MatSelectModule, MatSidenavModule, MatSnackBarModule, MatTableModule, MatTabsModule, MatToolbarModule, MatTooltipModule +} from './angular-material-index'; +*/ +import { CommonModule } from '@angular/common'; +import { MatNativeDateModule } from '@angular/material/core'; +import { MatLegacySnackBarModule as MatSnackBarModule } from '@angular/material/legacy-snack-bar'; +import { MatLegacyTabsModule as MatTabsModule } from '@angular/material/legacy-tabs'; +import { MatLegacyMenuModule as MatMenuModule } from '@angular/material/legacy-menu'; +import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; +import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete'; +import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/legacy-dialog'; +import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox'; +import { MatLegacyCardModule as MatCardModule } from '@angular/material/legacy-card'; +import { MatLegacyPaginatorModule as MatPaginatorModule } from '@angular/material/legacy-paginator'; +import { MatLegacyTableModule as MatTableModule } from '@angular/material/legacy-table'; +import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select'; +import { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy-input'; +import { MatLegacyFormFieldModule as MatFormFieldModule } from '@angular/material/legacy-form-field'; +import { MatGridListModule } from '@angular/material/grid-list'; +import { MatLegacyListModule as MatListModule } from '@angular/material/legacy-list'; +import { MatBadgeModule } from '@angular/material/badge'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { MatIconModule } from '@angular/material/icon'; +import { MatLegacyRadioModule as MatRadioModule } from '@angular/material/legacy-radio'; +import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips'; +import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner'; + +@NgModule({ +/* imports: [ + MatSnackBarModule, + MatTabsModule, + MatMenuModule, + CommonModule, + MatButtonModule, + MatToolbarModule, + MatIconModule, + MatSidenavModule, + MatBadgeModule, + MatListModule, + MatGridListModule, + MatFormFieldModule, + MatInputModule, + MatSelectModule, + MatRadioModule, + MatDatepickerModule, + MatNativeDateModule, + MatChipsModule, + MatTooltipModule, + MatTableModule, + MatPaginatorModule, + MatCardModule, + MatCheckboxModule, + MatDialogModule, + MatAutocompleteModule, + MatButtonToggleModule + + // NgxMatSelectSearchModule + ],*/ + exports: [ + MatSnackBarModule, + MatTabsModule, + MatMenuModule, + MatButtonModule, + MatToolbarModule, + MatIconModule, + MatSidenavModule, + MatBadgeModule, + MatListModule, + MatGridListModule, + MatInputModule, + MatFormFieldModule, + MatSelectModule, + MatRadioModule, + MatDatepickerModule, + MatChipsModule, + MatTooltipModule, + MatTableModule, + MatPaginatorModule, + MatCardModule, + MatProgressSpinnerModule, + MatCheckboxModule, + MatDialogModule, + MatAutocompleteModule, + MatButtonToggleModule + // NgxMatSelectSearchModule + ], + providers: [ + MatDatepickerModule, + ] +}) + +export class AngularMaterialModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/grid-config/columnconfig.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/grid-config/columnconfig.ts new file mode 100644 index 0000000..6fa59f9 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/grid-config/columnconfig.ts @@ -0,0 +1,80 @@ +import { Column } from 'devextreme/ui/data_grid'; + +export interface ILookup { + dataSource: any; + valueExpr: string; + displayExpr: string; +} + +export const enum EN_Alignment { + right = 'right', + left = 'left', + center = 'center', +} + +export const enum EN_SortOrder { + asc = 'asc', + desc = 'desc', +} + + +export type Type_FractionDigits = null | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6; +export type Type_Datentyp = string | number | Date; + +export class ColumnConfig { + allowSorting = true; + allowEditing = true; + private _sortIndex: number; + public get sortIndex(): number { + return this._sortIndex; + } + public set sortIndex(value: number) { + this._sortIndex = value; + if (!this.sortOrder) this.sortOrder = EN_SortOrder.asc; + } + sortOrder: EN_SortOrder; + alignment: EN_Alignment; + cellTemplate: string; + visible: boolean = true; + visibleIndex: number; + fixed: boolean = false; + headerCellTemplate: string; + width: string; + name: string; + minWidth: number; + _widthFactor: number = 1; + allowHeaderFiltering: boolean = false; + allowFiltering: boolean = true; + dataType: string; + groupIndex: number; + cssClass: string; + subColumns: ColumnConfig[] = []; + + lookup: ILookup; + format: any; + calculateCellValue: Function; + calculateDisplayValue: Function | string; + calculateGroupValue: Function | string; + calculateSortValue: Function | string; + customizeText: Function | string; + + + public get widthFactor(): number { + return this.groupIndex !== undefined ? 0 : this._widthFactor; + } + + public set widthFactor(v: number) { + this._widthFactor = v; + if (this._widthFactor < 0) this.width = '' + (- this._widthFactor) + 'px'; + else this.width = this._widthFactor + '%'; + } + + + constructor(public caption: string = '', public dataField: string = '', widthFactor: number = 1, fractionDigits?: Type_FractionDigits) { + if (fractionDigits || fractionDigits === 0) { + if (fractionDigits >= 0) this.cellTemplate = 'numberTemplate_' + fractionDigits; + this.alignment = EN_Alignment.right; + } + this.widthFactor = widthFactor; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/grid-config/columnconfiglist.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/grid-config/columnconfiglist.ts new file mode 100644 index 0000000..c511a3e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/grid-config/columnconfiglist.ts @@ -0,0 +1,138 @@ +import { GridExportButtonWidth } from '../../consts'; +import { ColumnConfig, EN_Alignment, EN_SortOrder, Type_FractionDigits } from './columnconfig'; + + +export interface SortInfo { + caption: string; + sortIndex: number; + sortOrder: EN_SortOrder; +} + + +export class ColumnConfigList { + public overHeaders: ColumnConfig[] = []; + private _columns: ColumnConfig[] = []; + public get columns(): ColumnConfig[] { + return this._columns; + } + public set columns(value: ColumnConfig[]) { + this._columns = value; + this.exportWasAdded = false; + } + + public withExport: boolean = true; + public curOverHeader: ColumnConfig; + private exportWasAdded: boolean = false; + + constructor() { + } + + clear() { + this.overHeaders = []; + this.columns = []; + } + + add(caption: string = '', dataField?: string, widthFactor: number = 1): ColumnConfig { + const column: ColumnConfig = new ColumnConfig(caption, dataField, widthFactor); + return this.addColumn(column, dataField === undefined); + } + + addCurrency(caption: string = '', dataField?: string, widthFactor: number = 1, fractionDigits: Type_FractionDigits = 0): ColumnConfig { + const column: ColumnConfig = new ColumnConfig(caption, dataField, widthFactor, fractionDigits); + column.cellTemplate = 'currencyTemnplate_' + fractionDigits; + + return this.addColumn(column, dataField === undefined); + } + + addNumber(caption: string = '', dataField?: string, widthFactor: number = 1, fractionDigits: Type_FractionDigits = 0): ColumnConfig { + if (dataField && dataField.slice(-2) === 'Id') fractionDigits = -1; + const column: ColumnConfig = new ColumnConfig(caption, dataField, widthFactor, fractionDigits); + column.dataType = 'number'; + return this.addColumn(column, dataField === undefined); + } + + addId(caption: string = '', dataField?: string, widthFactor: number = 1, fractionDigits: Type_FractionDigits = -1): ColumnConfig { + const column: ColumnConfig = new ColumnConfig(caption, dataField, widthFactor, fractionDigits); + column.dataType = 'number'; + return this.addColumn(column, dataField === undefined); + } + + addBoolean(caption: string = '', dataField?: string, widthFactor: number = 1): ColumnConfig { + const column: ColumnConfig = new ColumnConfig(caption, dataField, widthFactor); + column.dataType = 'boolean'; + return this.addColumn(column, dataField === undefined); + } + + addDate(caption: string = '', dataField?: string, widthFactor: number = 1): ColumnConfig { + const column: ColumnConfig = new ColumnConfig(caption, dataField, widthFactor); + column.dataType = 'date'; + column.alignment = EN_Alignment.center; + return this.addColumn(column, dataField === undefined); + } + + addDateTime(caption: string = '', dataField?: string, widthFactor: number = 1): ColumnConfig { + const column: ColumnConfig = new ColumnConfig(caption, dataField, widthFactor); + column.dataType = 'datetime'; + column.alignment = EN_Alignment.center; + return this.addColumn(column, dataField === undefined); + } + + private addColumn(column: ColumnConfig, overheader: boolean = false): ColumnConfig { + const arColums: ColumnConfig[] = overheader ? this.overHeaders : this.columns; + if (overheader) { + column.alignment = EN_Alignment.center; + this.curOverHeader = column; + } else { + if (this.curOverHeader) this.curOverHeader.subColumns.push(column); + } + arColums.push(column); + return column; + } + + //autorecalc after each add + recalcWidth(addAdditionalColumnForExport: boolean = true) { //Calculate the weighted width based on the widthFactor. + if (this.withExport && this.columns[this.columns.length - 1].alignment === EN_Alignment.right && !this.exportWasAdded && addAdditionalColumnForExport) { + this.add('', '', -GridExportButtonWidth); //last column for export + } + this.exportWasAdded = true; + + const totalWidthFactor: number = this.columns.reduce((sum, col) => sum + (col.visible && col.widthFactor > 0 ? col.widthFactor : 0), 0); + if (totalWidthFactor === 0) return; + const widthFactor_1percent: number = 100 / totalWidthFactor; //The total value may be max 100%; buffer - 0.01 + + let countPosWidth = 0; + this.columns.forEach(col => { + if (col.visible && col.widthFactor > 0) { + col.widthFactor = this.roundToTwo(col.widthFactor * widthFactor_1percent); + countPosWidth++; + } + }); + const delta = (100 - this.columns.reduce((sum, col) => sum + (col.visible && col.widthFactor > 0 ? col.widthFactor : 0), 0)); + + for (let i = this.columns.length - 1; i >= 0; i--) { + if (this.columns[i].visible && this.columns[i].widthFactor > 0) { + this.columns[i].widthFactor += delta; + break; + } + } + } + + roundToTwo(num: number, places = 2): number { + return Math.round((num + Number.EPSILON) * Math.pow(10, places)) / Math.pow(10, places); + } + + public setSorting(sortInfos: SortInfo[]) { + for (let inx = 0; inx < this.columns.length; inx++) { + const col = Object.assign(new ColumnConfig(), this.columns[inx]); + const sortInfo = sortInfos.find(el => el.caption === col.caption); + if (sortInfo) { + col.sortIndex = sortInfo.sortIndex; + col.sortOrder = sortInfo.sortOrder; + } else { + col.sortIndex = undefined; + col.sortOrder = undefined; + } + this.columns[inx] = col; + } + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.html new file mode 100644 index 0000000..ca3ee3e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.html @@ -0,0 +1,46 @@ +
+ + +
+ +
+ + + + + + + +
+
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.scss new file mode 100644 index 0000000..71a0bdf --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.scss @@ -0,0 +1,282 @@ +@import 'hr-core-consts'; + +.HRD_datetimepicker { + padding-top: 1px; + position: relative; + width: 100%; + height: auto; + // align-items: baseline; + // padding-bottom: 10px; + display: grid; + grid-template-columns: minmax(1px, 1fr); + grid-template-rows: minmax(auto, 0.65em) 1fr; //0.65em //10px + grid-template-areas: "dx-datebox-label""dxDateBox" +} + +.dxDateBox { + grid-area: dxDateBox; + background-color: transparent; + display: block; + // height: 28px; +} + +.dx-icon { + font-size: 24px; +} + +// ::ng-deep .dx-show-clear-button .dx-icon-clear { +// color: #000; +// background-color: white; +// /* background-color: #c2c2c2de; */ +// border-radius: 50%; +// position: absolute; +// top: 50%; +// margin-top: -9px; +// width: 16px; +// height: 16px; +// background-position: 0 0; +// background-size: 16px 16px; +// padding: 0; +// font-size: 10px; +// /* text-align: center; */ +// /* line-height: 10px; */ +// } + +::ng-deep .HRD_datetimepicker .dx-dropdowneditor-button .dx-button-content { + position: absolute; + left: -4px; +} + +::ng-deep .HRD_datetimepicker .dx-state-disabled .dx-dropdowneditor-button .dx-button-content { + height: 100%; + display: table-cell; + color: grey; + background-color: #0000; + -webkit-box-shadow: none; + box-shadow: none; +} +::ng-deep .HRD_datetimepicker .dx-texteditor-input { + height: auto; + padding-top: 6.3px !important; + padding-bottom: 5.1px !important; + margin: 0; + background-color: #0000; + font-size: 14px; + color: unset; +} + + +.dx-state-disabled .dx-widget, +.dx-state-disabled.dx-widget { + opacity: unset; //$hrColor-Alpha_Disabled; + color: rgba(0, 0, 0, $hrColor-Alpha_Disabled); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-touch-callout: none; + cursor: default; + background-image: linear-gradient(to right, rgba(0, 0, 0, .42) 0, rgba(0, 0, 0, .42) 33%, transparent 0); + background-position: bottom; + background-size: 4px 1px; + background-repeat: repeat-x +} + +.dx-datebox-label { + grid-area: dx-datebox-label; + color: rgba(0, 0, 0, 0.54); + top: 1.25em; + left: 0; + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 10px; + pointer-events: none; + // width: 133.33333%; + white-space: nowrap; + display: block; + text-overflow: ellipsis; + overflow: hidden; + cursor: default; + font-stretch: 100%; + font-weight: 400; + text-size-adjust: 100%; + visibility: visible; + +} + +::ng-deep .HRD_datetimepicker .dx-texteditor.dx-state-focused:before { + border-bottom: grey; + border-width: 1px; + outline-width: 0em; + transform: translateY(-1.34375em) scale(.75); +} + +::ng-deep .dx-calendar-cell.dx-calendar-selected-date span, +.dx-calendar-cell.dx-calendar-selected-date.dx-calendar-today span { + color: #fff; + background-color: $hrColor-DarkBlue; + font-weight: 400; +} + +::ng-deep .dx-calendar-navigator .dx-button { + height: 100%; + display: table-cell; + background-color: #0000; + color: $hrColor-DarkBlue; + -webkit-box-shadow: none; + box-shadow: none; +} + +::ng-deep .dx-datebox-wrapper-calendar .dx-button +// ::ng-deep .dx-datebox-wrapper-calendar .dx-timeview-hourarrow +// ::ng-deep .dx-datebox-wrapper-calendar .dx-timeview-minutearrow + { + color: $hrColor-DarkBlue; +} + +::ng-deep .dx-datebox-wrapper-calendar .dx-button-today { + color: $hrColor-Red; +} + + +::ng-deep .dx-datebox-wrapper-calendar .dx-calendar-cell.dx-calendar-today { + font-weight: 900; + color: $hrColor-LightBlue; +} + + + +::ng-deep .dx-show-clear-button .dx-clear-button-area { + width: 16px; + min-width: 16px; + right: -15px; +} + +::ng-deep .dx-calendar-navigator-previous-month.dx-button .dx-icon, +::ng-deep .dx-calendar-navigator-previous-view.dx-button .dx-icon { + color: $hrColor-DarkBlue; +} + +::ng-deep .dx-calendar-navigator-next-month.dx-button .dx-icon, +::ng-deep .dx-calendar-navigator-next-view.dx-button .dx-icon { + color: $hrColor-DarkBlue; +} + +::ng-deep .dx-texteditor.dx-editor-underlined.dx-state-disabled:after, +::ng-deep .dx-texteditor.dx-editor-underlined.dx-state-readonly.dx-state-hover:after, +::ng-deep .dx-texteditor.dx-editor-underlined.dx-state-readonly:after { + border-bottom-style: none; +} + +//------------------------------- +::ng-deep .dx-placeholder { + color: rgba(0, 0, 0, 0.54); + font-size: 14px; +} + +.hs_label_invalid, +::ng-deep .dx-invalid .dx-placeholder, +::ng-deep .hs_label_invalid .dx-placeholder { + color: rgb(244, 67, 54); +} + + + +// ::ng-deep .dx-state-focused .dx-placeholder { +// color: red; +// } + + +::ng-deep .HRD_datetimepicker .dx-state-focused .dx-dropdowneditor-input-wrapper { + padding-bottom: 2px; +} + +::ng-deep .dx-dropdowneditor-input-wrapper, +::ng-deep .dx-state-disabled .dx-dropdowneditor-input-wrapper { + padding-bottom: 1px; +} + +::ng-deep .dx-texteditor.dx-editor-underlined.dx-state-hover:after { + border-bottom: 1px solid rgba(0, 0, 0, .42); +} + +::ng-deep .HRD_datetimepicker .dx-texteditor.dx-editor-underlined.dx-state-focused:after { + border-bottom: 2px solid rgb(120, 183, 229); +} + +::ng-deep .HRD_datetimepicker .dx-texteditor.dx-editor-underlined.dx-invalid:after, +::ng-deep .HRD_datetimepicker .dx-texteditor.dx-editor-underlined.hs_label_invalid:after { + border-bottom-color: rgb(244, 67, 54); +} + + +.dx-invalid.dx-texteditor.dx-state-focused:before { + border: 0px none; +} + +.hs_label { + margin-top: -3px; + // height: 0.84375em; + height: 0.864em; + transform: scale(0.75) perspective(100px) translateZ(0.001px); + // transform: translateY(-1.28125em) scale(0.75) perspective(100px) translateZ(0.001px); + width: 133.33333%; + margin-left: -17%; + font-size: 14px; + overflow: inherit; +} + +// ::ng-deep .dx-state-focused .dx-placeholder { +// width: 133.33333%; +// } + + +.hs_label_focused { + color: rgb(120, 183, 229); +} + + +::ng-deep .HRD_datetimepicker .dx-invalid-message>.dx-overlay-content { + transform: none !important; + padding: 0 !important; + top: 21px !important; + background: white; + font-size: .85em; + color: rgb(244, 67, 54); +} + +::ng-deep .HRD_datetimepicker .dx-icon-close { + font-size: 14px; + font-family: Material Icons; +} + +::ng-deep .HRD_datetimepicker .dx-state-disabled .dx-icon-close { + color: rgba(11, 58, 98, 0.4); +} + +::ng-deep .HRD_datetimepicker .dx-icon-event { + // color: rgba(11, 58, 98, 0.84); //$hrColor-DarkBlue + color: rgba(0, 0, 0, 0.54); + +} + +::ng-deep .HRD_datetimepicker .dx-state-disabled .dx-icon-event { + color: rgba(0, 0, 0, 0.26); +} + +::ng-deep .HRD_datetimepicker .dx-icon-close:before { + content: "\e5cd"; +} + +::ng-deep .HRD_datetimepicker .dx-editor-underlined .dx-texteditor-buttons-container>.dx-button.dx-button-mode-text { + margin: 0; +} + +::ng-deep .HRD_datetimepicker .dx-invalid.dx-texteditor.dx-show-invalid-badge .dx-texteditor-input-container:after { + display: none; +} + + +// ::ng-deep .HRD_datetimepicker .dx-texteditor.dx-editor-underlined .dx-placeholder::before, +// ::ng-deep .HRD_datetimepicker .dx-texteditor.dx-editor-underlined .dx-texteditor-input { +// padding: 5.6px 0 5px; //allign top of dx-input box to mat-input +// } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.spec.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.spec.ts new file mode 100644 index 0000000..06c3571 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HenselDateTimePickerComponent } from './hensel-date-time-picker.component'; + +describe('HenselDateTimePickerComponent', () => { + let component: HenselDateTimePickerComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HenselDateTimePickerComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HenselDateTimePickerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.ts new file mode 100644 index 0000000..8d3c4c6 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.component.ts @@ -0,0 +1,292 @@ +import * as keycode from '@angular/cdk/keycodes'; +import { AfterViewInit, Component, EventEmitter, Inject, Input, LOCALE_ID, OnDestroy, OnInit, Optional, Output, ViewChild } from '@angular/core'; +import { FormControl, FormGroup, NgForm } from '@angular/forms'; +import { DxDateBoxComponent } from 'devextreme-angular'; +import { DisabledDate, dxCalendarOptions } from 'devextreme/ui/calendar'; +import { Subscription } from 'rxjs'; +import { EN_DateFormats } from '../../consts'; +import { HenselTranslateService } from '../../services/localization/hensel-translate.service'; +import { getDateFormat } from '../../utils'; + +export const enum EN_PickerTpe { + date = 1, + datetime = 2 +} + +@Component({ + // tslint:disable-next-line: component-selector + selector: 'hensel-date-time-picker', + templateUrl: './hensel-date-time-picker.component.html', + styleUrls: ['./hensel-date-time-picker.component.scss'], +}) + +export class HenselDateTimePickerComponent implements OnDestroy, AfterViewInit, OnInit { + private defDdateOutOfRangeMessage: string = 'core.hdatepicker.dateoutofrange'; + @ViewChild(DxDateBoxComponent) dateBox: DxDateBoxComponent; + public itemsControl = new FormControl(); + + private _placeholder: string = ''; + public get placeholder(): string { + return this._placeholder + (!!this._placeholder && this.required && ! this.disabled ? ' *' : ''); + } + + @Input() + public set placeholder(value: string) { + this._placeholder = value; + } + + public get date(): Date { + return this.itemsControl.value; + } + + @Input() + public set date(value: Date) { + if (!!value && !(value instanceof Date)) value = new Date(value); + if (this.pickerType === EN_PickerTpe.date) value?.setHours(0, 0, 0, 0); + this.itemsControl.setValue(value); + this.change(value); + } + + @Input() name: string; + private _displayFormat: string = 'datetime'; + public get displayFormat(): string { + return this._displayFormat; + } + @Input() + public set displayFormat(value: string) { + this._displayFormat = value; + this.date = this.date; //to consider date format + this.initCalendarOptions(); + } + + + @Output() public dateChange = new EventEmitter(); + @Input() required: boolean; + @Input() minDate: Date; + @Input() maxDate: Date; + private _canClear: boolean = true; + public get canClear(): boolean { + return this._canClear; + } + @Input() + public set canClear(value: boolean) { + this._canClear = value; + this.btnClear.visible = value; + } + @Input() stepMinute: number = 15; + + + private _disabledDates?: Array | ((data: DisabledDate) => boolean); + public get disabledDates(): Array | ((data: DisabledDate) => boolean) { + return this._disabledDates; + } + @Input() public set disabledDates(value: Array | ((data: DisabledDate) => boolean)) { + this._disabledDates = value; + this.initCalendarOptions(); + } + + private _showWeekNumbers: boolean = true; + public get showWeekNumbers(): boolean { + return this._showWeekNumbers; + } + @Input() public set showWeekNumbers(value: boolean) { + this._showWeekNumbers = value; + this.initCalendarOptions(); + } + + private _showTodayButton: boolean = true; + public get showTodayButton(): boolean { + return this._showTodayButton; + } + @Input() public set showTodayButton(value: boolean) { + this._showTodayButton = value; + this.initCalendarOptions(); + } + + @Input() customValidationMessage: string; + + private _dateOutOfRangeMessage: string = this.defDdateOutOfRangeMessage; + public get dateOutOfRangeMessage(): string { + return this._dateOutOfRangeMessage; + } + + @Input() + public set dateOutOfRangeMessage(value: string) { + this._dateOutOfRangeMessage = !value ? undefined /*this.defDdateOutOfRangeMessage*/ : value; + } + + public get getDisplayFormat(): string { + return this.displayFormat === 'date' ? 'date' : 'datetime'; + } + + public get formControlName(): string { + return 'henselDateTimePickerControl_' + this.name; + } + + public get pickerType(): EN_PickerTpe { + if (this.getDisplayFormat === 'date') { + return EN_PickerTpe.date; + } else { + return EN_PickerTpe.datetime; + } + } + + public get timeIsShown(): boolean { + return this.pickerType === EN_PickerTpe.datetime; + } + + public get parentFormGroup(): FormGroup { + const group = {}; + group[this.formControlName] = this.itemsControl; + return this.parent ? this.parent.form : new FormGroup( + group + ); + } + + private _parent: NgForm; + public get parent(): NgForm { + return this._parent; + } + @Input() + public set parent(value: NgForm) { + this._parent = value; + // if (this._parent && this.required !== undefined && this._selectedItemIds.length ==== 0) this.parent.control.setErrors({ required: true }); + if (!this.parent) this.parent = this._parentForm; + this.itemsControl.markAllAsTouched(); + if (this._parent) { + this.parent.control.addControl(this.formControlName, this.itemsControl); + this.hsRequiredsubscription = this.parent.valueChanges.subscribe(() => { if (!this.isValid) this.parent.control.setErrors({ required: true }); }); + + +/* it is working without special code + this.hsRequiredsubscription = this.parent.valueChanges.subscribe(() => { + if (this.required && this.empty()) this.parent.control.setErrors({ required: true }); + if (!this.empty()) { + if (this.minDate && this.date < this.minDate) this.parent.control.setErrors({ matDatepickerMin: true }); + if (this.maxDate && this.date > this.maxDate) this.parent.control.setErrors({ matDatepickerMax: true }); + } + });*/ + } + } + + private _disabled: boolean = false; + public get disabled(): boolean { + return this._disabled; + } + + @Input() + public set disabled(value: boolean) { + if (value) this.itemsControl.disable(); + else this.itemsControl.enable(); + + this._disabled = value; + } + + private _autofocus: any = false; + public get autofocus(): any { + return this._autofocus; + } + @Input() + public set autofocus(value: any) { + this._autofocus = value; + } + + + public hasFocus: boolean = false; + + public btnClear: any = { + icon: 'close', + stylingMode: 'text', + tabIndex: -1, + onClick: () => { this.date = null; } + }; + + public calendarOptions: dxCalendarOptions = {}; + + private hsRequiredsubscription: Subscription; + + constructor( + public translate: HenselTranslateService, + @Optional() private _parentForm: NgForm, + @Inject(LOCALE_ID) private localeId: string + ) { } + + ngOnInit(): void { + this.initCalendarOptions(); + setTimeout(() => { + if (!this.parent) this.parent = this._parentForm; + }, 0); + } + + initCalendarOptions() { + this.calendarOptions = { + showWeekNumbers: this.showWeekNumbers, + showTodayButton: this.pickerType === EN_PickerTpe.datetime ? false : this.showTodayButton, + disabledDates: this.disabledDates + }; + } + + + isEmpty = () => { + return !(this.date); + } + + + public get pickerDisplayFormat(): string { + return getDateFormat(this.localeId, this.pickerType === EN_PickerTpe.datetime ? EN_DateFormats.DateTime : EN_DateFormats.Date); + } + + + public get isValid() { + return this.isNotEmpty && this.isValidDate(); + } + + change(e) { + if (this.parent?.control) { + this.parent.control.updateValueAndValidity(); + // setTimeout(() => {this.parent.control.updateValueAndValidity();}, 5000); + } + } + + public inputChanged(e) { + this.change(e); + this.date = this.date; //to return date w/o time if type of picker Date + this.dateChange.emit(this.date); + } + + + public get isNotEmpty(): boolean { + // wenn disabled: keine Validation anzeigen (also valid) + // wenn enabled: wenn required: date != null and != undefined + // wenn enabled: wenn nicht required: valid + return this.disabled || (!this.required || !this.isEmpty()) ; + } + + + public isValidDate() { + return this.disabled || !this.customNotValid() && (this.isEmpty() || ((!this.minDate || this.minDate <= this.date) && (!this.maxDate || this.maxDate >= this.date))); + } + + focused(el: any) { + const res = document?.activeElement?.parentElement?.parentElement?.parentElement?.parentElement === el.element.nativeElement; + return res; + } + + + public customNotValid(): boolean { + return !!this.customValidationMessage; + } + + ngAfterViewInit(): void { + const elInput = this.dateBox.instance.field(); // input element + (elInput).autofocus = this.autofocus || (this.autofocus === ''); //wenn set attribute autofocus it is == '' + } + ngOnDestroy(): void { + if (this.hsRequiredsubscription) this.hsRequiredsubscription.unsubscribe(); + } + + doKeyDown(e, tocheck: boolean): void { + if (e.event.keyCode === keycode.ESCAPE && tocheck) e.event.stopPropagation(); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.module.ts new file mode 100644 index 0000000..18800e6 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-date-time-picker/hensel-date-time-picker.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { AngularMaterialModule } from '../angular-material.module'; +import { HenselDateTimePickerComponent } from './hensel-date-time-picker.component'; +import { DxDateBoxModule, DxValidatorModule, DxValidationSummaryModule } from 'devextreme-angular'; +import { TranslateModule } from '@ngx-translate/core'; + + +@NgModule({ + declarations: [HenselDateTimePickerComponent], + imports: [ + CommonModule, + AngularMaterialModule, + FormsModule, + ReactiveFormsModule, + DxDateBoxModule, + DxValidatorModule, + DxValidationSummaryModule, + TranslateModule.forChild() + ], + exports: [HenselDateTimePickerComponent] +}) +export class HenselDateTimePickerModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.html new file mode 100644 index 0000000..c38c7e3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.html @@ -0,0 +1,29 @@ +
+
+ {{caption}} +
+
+ + + + + {{icon}} + +
+
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.scss new file mode 100644 index 0000000..eae15f5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.scss @@ -0,0 +1,110 @@ +@import 'hr-core-consts'; + + +.hensel-dnd { + height: calc(100% - 4px); + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + position: relative; + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-template-rows: auto minmax(0, 1fr); // row relationships + grid-template-columns: minmax(0, 1fr); // column relationship + grid-column-gap: 0px; + grid-template-areas: "caption""dnd" +} + +.dnd-title { + grid-area: caption; + padding-bottom: 10px; +} + +.font-disabled { + color: rgba(0, 0, 0, 0.54) +} + +.font-enabled { + color: rgba(0, 0, 0, 0.87); + font-weight: bold; +} + + +.dnd-upload-container { + grid-area: dnd; + cursor: default; + height: calc(100% - 4px); + border-radius: $hrBorder-radius-big; + background-color: rgba(198, 231, 253, 0.3); +} + +.dnd-upload-container-disabled { + opacity: 0.6; + background-color: transparent; + border: 2px dashed gray; +} + +.dnd-upload-container-disabled-btn { + opacity: 1; + background-color: transparent; + border: 2px dashed gray; +} + +.dnd-upload-container-enabled { + opacity: 0.8; + border: 2px dashed #1C8ADB; +} + +.dnd-upload-container-enabled-btn { + opacity: 1; + border: 2px dashed #1C8ADB; +} + +.dnd-upload-container-enabled:hover { + cursor: pointer; + opacity: 1; +} + + +.dnd-upload-icon { + width: auto; + height: auto; + opacity: inherit; + cursor: inherit; + display: flex; + justify-content: center; + align-items: center; + position: relative; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.dnd-upload-button { + cursor: pointer; +} + + +.overlay { + /* Height & width depends on how you want to reveal the overlay (see JS below) */ + height: calc(100% - 72px); + margin-top: 47px; + margin-bottom: 25px; + width: 0; + position: fixed; + /* Stay in place */ + z-index: 1; + /* Sit on top */ + left: 0; + top: 0; + background-color: #9ecbec; + /* Black fallback color */ + background-color: #9ecbec; + /* Black w/opacity */ + opacity: 0.8; + overflow-x: hidden; + /* Disable horizontal scroll */ + transition: 0.1s; + /* 0.5 second transition effect to slide in or slide down the overlay (height or width, depending on reveal) */ +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.ts new file mode 100644 index 0000000..08dc26b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.component.ts @@ -0,0 +1,111 @@ +import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; + +@Component({ + selector: 'app-hensel-drag-n-drop', + templateUrl: './hensel-drag-n-drop.component.html', + styleUrls: ['./hensel-drag-n-drop.component.scss'] +}) +export class HenselDragNDropComponent implements OnInit { + + @Input() accept: string = '.jpg,.png'; + @Input() multiple: boolean = true; + @Input() caption: string; + @Input() captionClass: string = ''; + @Input() buttonText: string; + @Input() icon: string = 'cloud_upload'; + @Input() iconSizePrc: number = 1; + @Input() onFileUpload: (any) => void; + @Input() title: string; + @Input() button: string = ''; + @Input() disabled: boolean = false; + @Input() uploadAsBase64: boolean = false; + @Input() onStartingUpload: (any) => void; + @Input() onStartingUploadAsync: () => Promise; + @Input() onFinishUpload: () => void; + @ViewChild('fileInput') fileInput: ElementRef; + + public fontSize: string = '100%'; + + + constructor() { + this.readMultipleFiles = this.readMultipleFiles.bind(this); + this.startUpload = this.startUpload.bind(this); + } + + ngOnInit() { + } + + selectFiles() { + if (!this.disabled) this.fileInput.nativeElement.click(); + } + + private uploadFile(file: File, indx: number, lastIndx: number) { + if (file) { + if (this.uploadAsBase64) { + const fr = new FileReader(); // FileReader instance + fr.onload = () => { + const fileBase64: string = fr.result.toString(); + if (this.onFileUpload) this.onFileUpload({ fileBase64: fileBase64, filename: file.name, index: indx, lastIndex: lastIndx }); + /* + const img = new Image(); + img.src = fileBase64; + img.onload = () => { + this.catalogDataService.newImage({ name: file.name, image: fileBase64.split(',')[1] }, img.width, img.height, indx, this.imageGrid); + }; + */ + }; + fr.readAsDataURL(file); //Read file as Binary + } else if (this.onFileUpload) this.onFileUpload(file); + } else { + alert('File not selected or browser incompatible!'); + } + } + + + public async startUpload(files: FileList) { + const _files: FileList = { length: files.length, item: null }; + Object.assign(_files, files); //must save clone of files, bcs orig get lost + if (this.onStartingUploadAsync) await this.onStartingUploadAsync(); + // this.readMultipleFiles(_files); + if (!this.onStartingUpload) this.readMultipleFiles(_files); + else { + const noOfFiles = _files.length; + for (let inx = 0; inx < noOfFiles; inx++) { + if (this.validExtension(_files[inx].name)) { + this.onStartingUpload(() => this.readMultipleFiles(_files)); + return; + } + } + } + } + + + public readMultipleFiles(files: FileList) { + const noOfFiles = files.length; + let startInx: number = 0; + for (let inx = 0; inx < noOfFiles; inx++) { + if (!this.validExtension(files[inx].name)) continue; + // if (startInx === 0 && this.onStartingUpload) this.onStartingUpload(); + this.uploadFile(files[inx], startInx, noOfFiles - 1); + if (!this.multiple) break; + startInx++; + } + if (this.onFinishUpload) this.onFinishUpload(); + } + + validExtension(name: string) { + if (!this.accept) return true; + let exts: string; + if (this.accept.toLowerCase() === 'image/*') exts = ',.jpg,.jpeg,.png,.tiff,.bmp,'; + else exts = ',' + this.accept.replace(' ', '').toLocaleLowerCase() + ','; + const re: RegExp = /(?:\.([^.]+))?$/; + const ext = re.exec(name)[1].toLocaleLowerCase(); + return exts.indexOf(',.' + ext + ',') !== -1; + } + + + calcFontSize(width: number, height: number) { + return ((Math.min(width, height) - 4) / 12 * 100 * this.iconSizePrc).toFixed() + '%'; + + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.module.ts new file mode 100644 index 0000000..a3e74e8 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-drag-n-drop/hensel-drag-n-drop.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { HenselDragNDropComponent } from './hensel-drag-n-drop.component'; +import { HenselDnDDirective } from '../../directives/hensel-dnd.directive'; +import { AngularMaterialModule } from '../../components/angular-material.module'; +import { TranslateModule } from '@ngx-translate/core'; + +@NgModule({ + imports: [ + CommonModule, + AngularMaterialModule, + TranslateModule.forChild(), + HenselDnDDirective + ], + exports: [HenselDragNDropComponent], + declarations: [ + HenselDragNDropComponent, + ] +}) +export class HenselDragNDropModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.html new file mode 100644 index 0000000..a68d7bd --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.html @@ -0,0 +1,77 @@ + + + + + {{label}} + + +
+ {{hint | translate}} +
+
+ {{getIcon()}} + + + + + + + + + + + + {{errorMessageFn(value)}} + +
+ + +
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.scss new file mode 100644 index 0000000..776a27a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.scss @@ -0,0 +1,21 @@ +@import 'hr-core-consts'; +.hs_div { + outline: none; + pointer-events: auto; +} + + +.hs_pointer { + cursor: pointer; +} + + + +::ng-deep .hs_form:has(.material-icons.ng-star-inserted) .mat-form-field-suffix { + bottom: 8px; +} + + +::ng-deep .hs_form.no-placeholder .mat-form-field-infix { + border-top-width: 0px; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.ts new file mode 100644 index 0000000..50db20a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/hensel-input.component.ts @@ -0,0 +1,316 @@ +import { CommonModule } from '@angular/common'; +import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Optional, Output, Self, ViewChild } from '@angular/core'; +import { ControlValueAccessor, FormControl, FormGroup, FormsModule, NgControl, NgForm, ReactiveFormsModule } from '@angular/forms'; +import { TranslateModule } from '@ngx-translate/core'; +import { DxButtonModule, DxDataGridModule, DxTooltipModule } from 'devextreme-angular'; +import { Subscription } from 'rxjs'; +import { HenselTranslateService } from '../../services/localization/hensel-translate.service'; +import { + MatAutocompleteTrigger, MatFormField +} from '../angular-material-index'; +import { AngularMaterialModule } from '../angular-material.module'; +import { NgxMaskDirective, NgxMaskPipe } from 'ngx-mask'; +import { LocaleService } from '@app_core/services/localization/locale.service'; +import { HenselValidator } from '@app_core/validators/hensel-validator.directive'; +import { HenselMaskDecimalDirective } from '@app_core/directives/hensel-decimal.directive'; + + +@Component({ + // tslint:disable-next-line: component-selector + selector: 'hensel-input', + templateUrl: './hensel-input.component.html', + styleUrls: ['./hensel-input.component.scss'], + standalone: true, + imports: [ + CommonModule, + AngularMaterialModule, + FormsModule, + ReactiveFormsModule, + DxButtonModule, + DxTooltipModule, + TranslateModule, + DxDataGridModule, + NgxMaskDirective, + NgxMaskPipe, + HenselValidator, + HenselMaskDecimalDirective + ] +}) + +export class HenselInputComponent implements OnInit, AfterViewInit, OnDestroy { + + @ViewChild(MatAutocompleteTrigger) autocompleteTrigger: MatAutocompleteTrigger; + @ViewChild('cbInput') cbInput: ElementRef; + @ViewChild('hs_matformfield') hsMatFormField: MatFormField; + @ViewChild('hensel_input') hsElementRef: ElementRef; + + private hsRequiredsubscription: Subscription; + private _required: boolean; + public get required(): boolean { + return this._required; + } + @Input() public set required(value: boolean) { + if (typeof (value) === 'string') value = value !== 'false'; + this.setRequired(value); + this.updateParent(); + } + + private _disabled: boolean = false; + public get disabled(): boolean { + return this._disabled; + } + + @Input() public set disabled(value: boolean) { + this.setDisable(typeof (value) === 'string' ? value !== 'false' : value); + } + + @Input() public validate: (val: any) => boolean; + + public _value: any = null; + @Input() public set ngModel(val: any) { + this.setValueInternally(val, true); + this.lastValue = this._value; + } + public get ngModel(): any { + return this.value; + } + + @Output() public get value(): any { + return this._value; + } + + @Output() ngModelChange = new EventEmitter(); + @Input() label: string; + @Input() placeholder: string; + @Input() width: string = '100%'; + @Input() backgroundColor: string = 'inherit'; + + @Input() hint: string; + @Input() type: string = 'text'; + @Input() displayIconFn: (comp: HenselInputComponent) => string; + @Input() id: string = ''; + @Input() name: string = ''; + @Input() public hsClass: string = ''; + @Input() autofocus: any = false; + @Input() maxlength: number; + @Input() readonly: boolean; + @Input() autocomplete: string = ''; + + private _parent: NgForm = null; + public get parent(): NgForm { + return this._parent; + } + + @Input() + public set parent(value: NgForm) { + this._parent = value ?? this._parentForm; + this.hsRequiredsubscription?.unsubscribe(); + this.hsRequiredsubscription = this.parent?.valueChanges.subscribe(() => this.checkRequired()); //take cares about form.invalid, if the component invalid + this.markAsTouchedDirty(); + } + + + private _canClear: boolean = true; + public get canClear(): boolean { + return this._canClear; + } + @Input() public set canClear(value: boolean) { + this._canClear = value; + } + @Input() public defaultValue: any; + @Output() public focus = new EventEmitter(); + @Output() public blur = new EventEmitter(); + @Input() public tabindex: number = 0; + @Input() public errorMessageFn: ((value: any) => string); + + private _title: string = ''; + public get title(): string { + let resTitle = this._title; + // if (!resTitle && this.cbInput?.nativeElement?.clientWidth < this.cbInput?.nativeElement?.scrollWidth) resTitle = this.displayFn(this._value); + return resTitle; + } + @Input() public set title(value: string) { + this._title = value; + } + + //***** Using Mask derictive + @Input() mask: string; + @Input() suffix: string = ''; + @Input() prefix: string = ''; + @Input() decimalMarker: string; + @Input() thousandSeparator: string; + @Input() leadZero: boolean = true; + @Input() separatorLimit: string = '0'; + + + + //***** Using Hensel validator + @Input() greater: number; + @Input() notless: number; + @Input() notgreater: number; + @Input() less: number; + + //***** Using Hensel decimal directive + @Input() henselDecimal: number; + @Input() henselDecimalAllowEmpty: boolean; + + + public itemsControl = new FormControl(); + public hasFocus: boolean = false; + private _lastValue: any; + public get lastValue(): any { + return this._lastValue; + } + public set lastValue(value: any) { + this._lastValue = value; + } + public showInputField: boolean = true; + public initialised: boolean = false; + + private get formGroup(): FormGroup { + return this.parent?.control; + } + + public computedBackgroundColor: string; + + constructor( + public translate: HenselTranslateService, + public localeService: LocaleService, + @Optional() private _parentForm?: NgForm, + // @Self() public ngControl?: NgControl + ) { + } + + ngOnInit() { + setTimeout(() => { + if (!this.parent) this.parent = this._parent; + }, 0); + } + + ngAfterViewInit(): void { + setTimeout(() => { + this.initialised = true; + this.computedBackgroundColor = this.getBackgroundColor(this.hsElementRef.nativeElement); + }, 0); + } + + + private setDisable(value: boolean) { + this._disabled = value; + if (this.disabled) { + this.itemsControl.disable(); + } else this.itemsControl.enable(); + } + + + private setRequired(value: boolean) { + this._required = value; + } + + + private setValueInternally(value: any, externally = false) { + if (value === this._value) return; + this._value = value; + this.itemsControl.setValue(this._value); + if (externally) this.updateParent(); //otherwise if set programatically parent form doesn't change valid status + } + + + getBackgroundColor(htmlElemet: any): string { + const backgroundColor = window.getComputedStyle(htmlElemet, null).getPropertyValue('background-color'); + if (backgroundColor !== 'rgba(0, 0, 0, 0)' || !htmlElemet?.parentElement) return backgroundColor; + else return this.getBackgroundColor(htmlElemet.parentElement); + } + + + checkRequired() { + if (this.requiredError()) this.formGroup?.setErrors({ required: true }); + } + + requiredError(): boolean { + let req = this.required; + return !this.disabled && req !== undefined && req !== false && this.isEmpty(); + } + + + public isEmpty(): boolean { + return !this._value; + } + + + + public takeFocus = () => { //such declaration because of binding + this.hasFocus = true; + this.focus.emit(this); + } + + + public leaveFocus = () => { //such declaration because of binding + this.hasFocus = false; + this.blur.emit(this); + } + + public updateParent() { + //this.formGroup?.updateValueAndValidity(); + } + + + + // public clickClear($event: any) { + // $event.stopPropagation(); + // if (/*this.dropDownState === EN_DropDownState.Opened ||*/ this.lastFilter) { + // setTimeout(() => { + // this.itemsControl.setValue(''); + // this.cbInput?.nativeElement?.focus(); //to call opendropdown after close drop down if minlength>0 + // }, 300); + // } else { + // this.lastValue = this._value; + // if (this.defaultValue !== undefined && this.defaultValue !== null) this.setValueInternally([this.defaultValue]); + // else this.setValueInternally([]); + // this.selectionDone(); + // } + // } + + + ngOnDestroy(): void { + this.hsRequiredsubscription?.unsubscribe(); + } + + getIcon(): string { + if (this.displayIconFn) return this.displayIconFn(this); + return null; + } + + public markAsDirty() { + if (this.hsMatFormField?._control?.ngControl?.control) { + this.hsMatFormField._control.ngControl.control.markAsDirty(); + this.updateParent(); + } + } + + + public markAsTouched() { + if (this.hsMatFormField?._control?.ngControl?.control) { + this.hsMatFormField._control.ngControl.control.markAsTouched(); + this.updateParent(); + } + } + + + public markAsTouchedDirty() { + if (this.hsMatFormField?._control?.ngControl?.control && this.required && this.isEmpty()) { + this.hsMatFormField._control.ngControl.control.markAsTouched(); + this.hsMatFormField._control.ngControl.control.markAsDirty(); + this.updateParent(); + } + } + + onChange(value: any) { + if (value === this.value) return; + this._value = value; + console.log('--',value); + this.updateParent(); + this.ngModelChange.emit(value); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/readme.txt b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/readme.txt new file mode 100644 index 0000000..383e1b1 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-input/readme.txt @@ -0,0 +1,24 @@ +Inputs: +placeholder (String): A placeholder value for your mat-select +selectPlaceholder(String): Placeholder for options filtering +options (Array of objects): Options object to be listed +selectedOptions (Array of Strings): To pre-populate or preselect options +display (String): Property of every option for display in dropdown +value (String): Property of every option to be returned on option selection; +required (Boolean): To make your mat-field required. Default : false; +multiple (Boolean): Able to select multiple or single. Default: true; +disabled (Boolean): To disable the mat-field. default: false; +appearance (String): Appearance of your mat-field. Supported options: 'legacy' | 'standard' | 'fill' | 'outline'; +formControl (String): If you’re using Angular reactive form, bind your formControl with mat-select-autocomplete output +showErrorMsg (Boolean): Whether show error message or not. Default: false; +errorMsg (String): Custom error message. Default: ‘Field is required’ +labelCount (Number): Number of selected options to be shown in display of mat-select. Default: 1. + +Outputs: +selectionChange (EventEmitter): On every option selection, +this event would be emitted. You could capture the selected options values [Array of Strings] from this event param. + +ViewChild: +If you want to toggle mat-select-autocomplete from your own component event, +you need to import MultiselectComponent in the component and take it’s reference as ViewChild element (eg: matSelect). +Now you could trigger this.matSelect.toggle() to toggle the dropdown. \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.html new file mode 100644 index 0000000..9344960 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.html @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + +
+
+ {{ cell.column.caption | translate}} +
+
+ +
+ + + + + +
{{'core.hensel-selection.nohits' | translate}}
+
+ +
+ {{'core.hensel-selection.inputminsybols' | translate: {value: minFilterLength4Search} }} +
+
+ + + + + {{getIcon4Selected()}} + + + +
+
+
+ + + + +
+ +
{{'core.caption.all' | translate}}
+ +
+ + +
{{'core.hensel-selection.selectedfirst' | translate}}
+
+ + +
{{'core.btn.apply' | translate}}
+
+ + +
{{'core.btn.cancel' | translate}}
+
+
+ +
+ +
+ + {{displayIconFn(item.link)}} + {{ item[displayExpr] }} + +
+ {{displayIconFn(item.link)}} + {{ item[displayExpr] }} +
+
+
+
+
+ +
+
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.scss new file mode 100644 index 0000000..5597d4c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.scss @@ -0,0 +1,197 @@ +@import 'hr-core-consts'; + +// (If you use Bootstrap, you'll have to add an override to your css file to make the clear button show in input field) +// input[type=search]::-webkit-search-cancel-button { +// -webkit-appearance: searchfield-cancel-button; +// } + + +// confirm button in drop down layout +.buttonLayoutOk { + cursor: pointer !important; + top: 5px; + right: 5px; + margin-left: 5px; + border-width: 0; +} + +.buttonLayoutCancel { + cursor: pointer !important; + top: 5px; + right: 5px; + margin-left: 5px !important; + border-width: 0; +} + +.cbCheckedFirst { + cursor: pointer !important; + margin-top: 12px; + right: 20px; + margin-left: auto !important; + border-width: 0; + font-size: smaller; + position: relative; +} + +.hs_arrow { + position: relative; + top: 50%; + transform: translate(0%, -50%) !important; +} + +.hs_arrowheader { + cursor: pointer; + float: right; + top: -5px; +} + +.selected { + background-color: rgba(0, 0, 0, .12) !important; + color: $hrColor-LightBlue !important; // #3f51b5; +} + +//set font size and width of drop down window +// ::ng-deep .cdk-overlay-pane { +// width: auto !important; +// min-width: 200px; +// font-size: 14px; +// } + +//******************* +::ng-deep .hs_form .mat-form-field-subscript-wrapper { + z-index: 2; +} + +::ng-deep .hs_form .mat-form-field-infix { + display: flex; //get down array button in the same row +} + +.hs_autocomplete { + padding-right: 0px; + max-height: 300px !important; +} + +::ng-deep .hs_autocomplete .cbCheckedFirst .mat-checkbox-inner-container { + order: 1; +} + +::ng-deep .hs_autocomplete .buttonLayoutOk .dx-icon-check { + font-size: 18px !important; + font-weight: bold !important; + color: green !important; +} + + +//set font size for items of drop down +::ng-deep .hs_autocomplete .mat-option { + font-size: inherit; +} + +::ng-deep .hs_autocomplete .dx-button-content { + padding: 0px !important; +} + +//label's color for the checked checkboxes if changed mark color not used +::ng-deep .hs_autocomplete .mat-option.multi_selected:not(.mat-option-disabled):not(.changedLabelColor) { + //:not(.changed) + color: $hrColor-LightBlue !important; // #78b7e5; +} + +//label's color for the checked checkboxes if changed mark color used (changedLabelColor) +::ng-deep .hs_autocomplete .mat-option.multi_selected.changedLabelColor:not(.mat-option-disabled):not(.changed) { + color: $hrColor-LightBlue !important; // #78b7e5; +} + +//label's color for the changed checkboxes ifused (changedLabelColor) +::ng-deep .hs_autocomplete .mat-option.changed.changedLabelColor:not(.mat-option-disabled) { + color: $hrColor-Green !important; // #78b7e5; +} + +//checked check box filling's color for changed mark if used (changedCBColor) +::ng-deep .hs_autocomplete .mat-option.changed.changedCBColor .mat-checkbox-checked.mat-accent .mat-checkbox-background { + background-color: $hrColor-Green !important; //transparent; //#78b7e5; +} + +// check box frame's color for changed mark if used (changedCBColor) +::ng-deep .hs_autocomplete .mat-option.changed.changedCBColor:not(.mat-option-disabled) .mat-checkbox-frame { + border-color: $hrColor-Green; +} + +/* +//check box's check symbol color/style +::ng-deep .hs_autocomplete mat-option.changed:not(.mat-option-disabled) .mat-checkbox-checkmark-path { + stroke: red !important; + stroke-width: 3 !important; +} +*/ +// ::ng-deep input:read-only{ + +// } + +// ::ng-deep .hs_autocomplete .mat-form-field-underline:read-only { +// border-bottom-style: dotted; +// } + +// outlined symbols in items match to filter +::ng-deep .hs_autocomplete .hs_marked { + background-color: rgba(0, 0, 0, .22); +} + +::ng-deep .hs_grid .dx-datagrid-export-button .dx-icon-export-excel-button:before { + content: "\f001" !important; +} + +::ng-deep .hs_grid .dx-datagrid-export-button .dx-icon-export-excel-button { + font-size: 25px !important; + color: rgba(0, 0, 0, 0.45) !important; +} + +::ng-deep .hs_grid .dx-datagrid-export-button .dx-icon-xlsxfile:before { + content: "\f001" !important; +} + +::ng-deep .hs_grid .dx-datagrid-export-button .dx-icon-xlsxfile { + font-size: 25px !important; + color: rgba(0, 0, 0, 0.45) !important; +} + +::ng-deep .hs_grid .dx-button .dx-button-content { + left: 0px; // -4px; +} + + +.hs_grid_header { + // font-family: inherit !important; + font-size: 14px; + font-weight: normal; +} + +.hs_required .hs_grid_header { + color: red; +} + +::ng-deep .hs_required .dx-datagrid-nodata { + color: red; +} + +.hs_pointer { + cursor: pointer; +} + +.hs_div { + outline: none; + pointer-events: auto; +} + +.zoom { + transform: scale(0.2); +} + +::ng-deep .hs_form:has(.material-icons.ng-star-inserted) .mat-form-field-suffix { + bottom: 8px; +} + + +::ng-deep .hs_form.no-placeholder .mat-form-field-infix { + border-top-width: 0px; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.ts new file mode 100644 index 0000000..8a9992e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/hensel-selection.component.ts @@ -0,0 +1,940 @@ +import { AfterViewInit, Component, ElementRef, EventEmitter, HostListener, Input, OnDestroy, OnInit, Optional, Output, ViewChild } from '@angular/core'; +import * as keycode from '@angular/cdk/keycodes'; +import { FormControl, FormGroup, FormsModule, NgForm, ReactiveFormsModule } from '@angular/forms'; +import { DxButtonModule, DxDataGridComponent, DxDataGridModule, DxTooltipModule } from 'devextreme-angular'; +import { Observable, Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { HenselTranslateService } from '../../services/localization/hensel-translate.service'; +import { + MatAutocomplete, MatAutocompleteTrigger, MatFormField, MatOptionSelectionChange, _countGroupLabelsBeforeOption, + _getOptionScrollPosition +} from '../angular-material-index'; +import { CommonModule } from '@angular/common'; +import { AngularMaterialModule } from '../angular-material.module'; +import { TranslateModule } from '@ngx-translate/core'; + + +const enum EN_DropDownState { + Closed = 0, + Opened = 1, + EmptyFilter = 2, +} + +@Component({ + // tslint:disable-next-line: component-selector + selector: 'hensel-selection', + templateUrl: './hensel-selection.component.html', + styleUrls: ['./hensel-selection.component.scss'], + standalone: true, + imports: [ + CommonModule, + AngularMaterialModule, + FormsModule, + ReactiveFormsModule, + DxButtonModule, + DxTooltipModule, + TranslateModule, + DxDataGridModule + ] +}) + +export class HenselSelectionComponent implements OnInit, AfterViewInit, OnDestroy { + + @ViewChild(MatAutocompleteTrigger) autocompleteTrigger: MatAutocompleteTrigger; + @ViewChild('cbInput') cbInput: ElementRef; + @ViewChild('hs_panel') autocompleteScrollPanel: ElementRef; + @ViewChild('hs_toolbar') autocompleteToolbar: ElementRef; + @ViewChild('hs_matformfield') hsMatFormField: MatFormField; + @ViewChild('grid_hensel') grid_hensel: DxDataGridComponent; + @ViewChild('hensel_selection') hsElementRef: ElementRef; + + // the dataSource of selectable items + public EN_DropDownStateClosed: EN_DropDownState = EN_DropDownState.Closed; + + public _dataSource: any[] = []; + private _origDataSource: any[]; + private currentScrollTop: number = 0; + private hsRequiredsubscription: Subscription; + + private lastDisabled: boolean; + private lastShowSpinner: boolean; + + @Input() public set dataSource(value: any[]) { + this._origDataSource = value; + this.applyCustomFilterAsync(); + } + + @Input() public set reprepareImmedeately(value: boolean) { + if (value) { + this.applyCustomFilterAsync(); + setTimeout(() => { //to avoid change after chek error + this.reprepareImmedeatelyChange.emit(this.reprepareImmedeately); + }); + } + } + public get reprepareImmedeately() { return false; } + @Output() reprepareImmedeatelyChange = new EventEmitter(); + + + private _keyExpr: string; + public get keyExpr(): string { + return this._keyExpr; + } + @Input() public set keyExpr(value: string) { + this._keyExpr = value; + this.applyCustomFilterAsync(); + } + + + private _displayExpr: string; + public get displayExpr(): string { + return this._displayExpr; + } + @Input() public set displayExpr(value: string) { + this._displayExpr = value; + this.applyCustomFilterAsync(); + } + + + private _required: boolean; + public get required(): boolean { + return this._required; + } + @Input() public set required(value: boolean) { + if (typeof (value) === 'string') value = value !== 'false'; + this.setRequired(value); + console.log('**** - Hensel-Sel: ' + this.placeholder + ' set required', value); + this.updateParent(); + } + + private orgRequired: boolean; + + private _disabled: boolean = false; + public get disabled(): boolean { + return this._disabled; + } + + @Input() + public set disabled(value: boolean) { + value = typeof (value) === 'string' ? value !== 'false' : value + if (!this.showSpinner) { + this.setDisable(value); + } + this.lastDisabled = value; + } + + // binding for selected items + private _selectedFirst: boolean = true; + public get selectedFirst(): boolean { + return this._dataSource && this._dataSource.length > 200 || !this.multiSelect ? false : this._selectedFirst; + } + @Input() public set selectedFirst(value: boolean) { + this._selectedFirst = value; + this.itemsControl.setValue(this.lastFilter); + } + + @Input() public validate: (items: any[]) => boolean; + + // ',' delimited & conditions without spaces (space means compare against null) + private _customFilter: string[] = []; + + @Input() public set customFilter(value: string) { + if (!value) this._customFilter = []; + else this._customFilter = value.split(','); + this.applyCustomFilterAsync(); + } + + private _customFilterFn: (item: any) => boolean = null; + + @Input() + public get customFilterFn(): (item: any) => boolean { + return this._customFilterFn; + } + public set customFilterFn(value: (item: any) => boolean) { + this._customFilterFn = value; + this.applyCustomFilterAsync(); + } + + public _selectedItemIds: any[] = []; + @Input() public set selectedItems(val: any[] | any) { + if (val instanceof Array) this.setValueInternally(val.slice(), true); //use copy of array + else this.setValueInternally(val, true); + this.lastSelection = this._selectedItemIds; + // console.log('!!!!!! ' + this.placeholder, val, this._selectedItemIds.length); + } + + public get selectedItems(): any[] | any { + return this._selectedItemIds; + } + + @Output() selectedItemsChange = new EventEmitter(); + @Output() selectedItemsDisplayChange = new EventEmitter(); + @Output() dropDownClosed = new EventEmitter(); + // Name of dataSource + @Input() placeholder: string; + @Input() multiSelect: boolean = true; + @Input() separator: string = ','; + @Input() width: string = '100%'; + @Input() height: string = '200px'; + @Input() displayTemplate: string = ''; //"${filedname}: ${filedname}" + @Input() displayIconFn: (item: any) => string; + @Input() id: string = ''; + @Input() name: string = ''; + @Input() useCloseButton: boolean = true; + @Input() useMarkFiltered: boolean = true; + @Input() useSelFirstButton: boolean = false; + @Input() useCBChangedColor: boolean = true; + private _useResultGrid: boolean = false; + @Input() + public get useResultGrid(): boolean { + return this._useResultGrid; + } + public set useResultGrid(value: boolean) { + this._useResultGrid = value; + } + + @Input() useLabelChangedColor: boolean = true; + @Input() backgroundColor: string = 'inherit'; + public backgroundColor4Grid: string; + + + private _minFilterLength4Search: number = -1; + public get minFilterLength4Search(): number { + let _minFilterLength4Search = 0; + if (this._minFilterLength4Search === 0) { + _minFilterLength4Search = this.getMinFilterLength4Search(this._dataSource.length); + } else { + if (this._minFilterLength4Search > 0) _minFilterLength4Search = this._minFilterLength4Search; + } + return (this._customFilter.length === 0 && !this._customFilterFn) ? _minFilterLength4Search : + Math.min(this.getMinFilterLength4Search(this._dataSource.length), _minFilterLength4Search); + } + + @Input() public set minFilterLength4Search(value: number) { + this._minFilterLength4Search = value; + } + private _sortField: string = null; + private sortDirection: -1 | 1 = 1; + @Input() set sortField(value: string) /*with leading "-" descendent*/ { + this._sortField = value; + if (this._sortField && this._sortField.slice(0, 1) === '-') { + this.sortDirection = -1; + this._sortField = this._sortField.slice(1); + } else this.sortDirection = 1; + this.applyCustomFilterAsync(); + } + get sortField(): string { return this._sortField; } + + public get formControlName(): string { + return 'henselSelectionControl_' + this.name; + } + + + private _parent: NgForm = null; + public get parent(): NgForm { + return this._parent; + } + + @Input() + public set parent(value: NgForm) { + this._parent = value ?? this._parentForm; + this.hsRequiredsubscription?.unsubscribe(); + this.hsRequiredsubscription = this.parent?.valueChanges.subscribe(() => this.checkRequired()); //take cares about form.invalid, if the component invalid + // this.formGroup?.addControl(this. formControlName, this.itemsControl); //if we add control to partner, form get changed event on dropdown + this.markAsTouchedDirty(); + } + + private _newfilter: string; + + public get openWithFilter(): string { + return this._newfilter; + } + + @Input() + public set openWithFilter(newfilter: string) { + this._newfilter = newfilter; + if (this.showSpinner || !this.initialised || !this._origDataSource || this._origDataSource.length === 0) return; //to avoid repeatedly calls during initialising + + if (newfilter !== undefined) { + setTimeout(() => { + this.itemsControl.setValue(newfilter); + if (!!newfilter) this.cbInput?.nativeElement?.focus(); + }); + } + } + + @Input() public hsClass: string = ''; + + @Input() selectionNotFound: (arg: number) => string; + @Input() autofocus: any = false; + + private _canClear: boolean = true; + public get canClear(): boolean { + return this._canClear; + } + @Input() public set canClear(value: boolean) { + this._canClear = value; + } + @Input() public defaultValue: any; + @Output() public focus = new EventEmitter(); + @Input() public tabindex: number = 0; + + private _title: string = ''; + public get title(): string { + let resTitle = this._title; + if (!resTitle && this.cbInput && this.cbInput.nativeElement && this.cbInput.nativeElement.clientWidth < this.cbInput.nativeElement.scrollWidth) { + resTitle = this.displayFn(this._selectedItemIds); + } + return resTitle; + } + + @Input() + public set title(value: string) { + this._title = value; + } + + private _showSpinner: boolean = false; + public get showSpinner(): boolean { + return this._showSpinner; + } + + @Input() + public set showSpinner(value: boolean) { + this.setShowSpinner(value); + this.lastShowSpinner = value; + this.openWithFilter = this.openWithFilter; + } + + private _disabledItems: any[] = []; + public get disabledItems(): any[] { + return this._disabledItems; + } + @Input() + public set disabledItems(value: any[]) { + this._disabledItems = value; + this.applyCustomFilterAsync(); + } + + + public itemsControl = new FormControl(); + + public get displayLength(): number { + return this.displayFn(this._selectedItemIds)?.length; + } + + public hasFocus: boolean = false; + public filteredItems: any[] = []; + public items2filter: Observable; + public selectedItemsGrid: any[] = []; + public selectedAllNonePart: number = 0; //-1 - none, 0 - part, 1 - all + private _dropDownState: EN_DropDownState = EN_DropDownState.Closed; //0-closed, 1-opened, 2-not shown because of empty filter + public get dropDownState(): EN_DropDownState { + return this._dropDownState; + } + public set dropDownState(value: EN_DropDownState) { + if (value === EN_DropDownState.Closed && this._dropDownState !== value) this.dropDownClosed.emit(); + this._dropDownState = value; + } + public lastFilter: string = ''; + private _lastSelectionString: string = ''; + private lastSelectedItemIds: any = ''; + public get lastSelection(): any { + return this._lastSelectionString; + } + public set lastSelection(value: any) { + this.lastSelectedItemIds = value.slice(); + this._lastSelectionString = this.getSelection(value); + } + public startLeaveFocus: boolean = false; + public showInputField: boolean = true; + + public initialised: boolean = false; + private lastActiveItemIndex: number; + + private get formGroup(): FormGroup { + return this.parent?.control; + } + + constructor( + public translate: HenselTranslateService, + @Optional() private _parentForm: NgForm + ) { + this.applyCustomFilterAsync = this.applyCustomFilterAsync.bind(this); + translate.onLangChange.subscribe(() => this.applyCustomFilterAsync()); + } + + ngOnInit() { + //document.getElementById('cbInput').addEventListener('blur', this.closeDropDown); //can be used (blur)="closeDropDown()" in html + //document.getElementById('cbInput').addEventListener('focus', this.openDropDown); + this.items2filter = this.itemsControl.valueChanges.pipe( + // startWith(''), + // debounceTime(300), + map(value => typeof value === 'string' ? value : this.lastFilter), + map(filter => this.applyFilter(filter)), + ); + + this.items2filter.subscribe(() => setTimeout(() => { //over time out - the list must be built + this.applyMarkFiltered(this.lastFilter); + })); + + this.showInputField = !this.useResultGrid; + setTimeout(() => { + if (!this.parent) this.parent = this._parent; + }, 0); + } + + ngAfterViewInit(): void { + if (this.lastShowSpinner === undefined) this.setShowSpinner(true); + setTimeout(() => { + this.initialised = true; + this.applyCustomFilterAsync(); + this.backgroundColor4Grid = this.getBackgroundColor(this.hsElementRef.nativeElement); + }, 0); + } + + + private getMinFilterLength4Search(count: number) { + return count > 5000 ? 4 : (count > 1000 ? 3 : (count > 300 ? 2 : 0)); + } + + + private setShowSpinner(value: boolean) { + //dettimeout interferiert with settimeout in open with filter + setTimeout(() => { //timeout because of ExpressionChangedAfterItHasBeenCheckedError + this._showSpinner = value; + if (value) this.setDisable(true); + else this.setDisable(this.lastDisabled); + this.openWithFilter = this.openWithFilter; + }, 0); + } + + + private setDisable(value: boolean) { + this._disabled = value; + if (this.disabled) { + this.autocompleteTrigger?.closePanel(); + this.itemsControl.disable(); + } else this.itemsControl.enable(); + } + + + private setRequired(value: boolean) { + this._required = value; + } + + + private setValueInternally(value: any[] | any, externally = false) { + + if (!this._selectedItemIds) this._selectedItemIds = []; + if (value instanceof Array) this._selectedItemIds.splice(0, this._selectedItemIds.length, ...value); //we replace here elements of array, otherwise the connected array will not be set w/o emit and values are not reset + // this._selectedItemIds = val; + else { + this._selectedItemIds.splice(0); + if (value) this._selectedItemIds.push(value); + } + + this.updateGrid(); + + // const lastState = this.dropDownState; + // this._dropDownState = EN_DropDownState.Opened; // to update the 1st time the dropdown ?? //results in keyinput delays + this.itemsControl.setValue(this._selectedItemIds); + console.log('**** - Hensel-Sel: ' + this.placeholder + ' set value internaly', value); + if (externally) this.updateParent(); //otherwise if set programatically parent form doesn't change valid status + // this._dropDownState = lastState; + } + + + getBackgroundColor(htmlElemet: any): string { + const backgroundColor = window.getComputedStyle(htmlElemet, null).getPropertyValue('background-color'); + if (backgroundColor !== 'rgba(0, 0, 0, 0)' || !htmlElemet?.parentElement) return backgroundColor; + else return this.getBackgroundColor(htmlElemet.parentElement); + } + + public checkInSelected(val: any) { + return this._selectedItemIds.indexOf(val[this.keyExpr]) >= 0; + } + + public checkChanged(val: any) { + const isSelected = this.checkInSelected(val); + const wasSelected = this.lastSelectedItemIds.indexOf(val[this.keyExpr]) >= 0; + // tslint:disable-next-line: no-bitwise + return isSelected ^ wasSelected; + } + + // @HostListener('window:keydown', ['$event']) - if not commented we get delay in keyinput for other input fields + public onKeyDown = (event?: KeyboardEvent): boolean => { + // tslint:disable-next-line: deprecation + if (event.keyCode === keycode.ENTER && this.multiSelect) { + this.selectionDone(); + event.stopPropagation(); + return false; //no further processing + } + return true; //default processing + } + + @HostListener('keydown', ['$event']) + public inputFilter(event?: KeyboardEvent) { + // tslint:disable-next-line: deprecation + if (event.keyCode === keycode.ENTER || event.keyCode === keycode.TAB && !this.multiSelect) //return + { + if (this.filteredItems.length === 1) this.toggleSelection(this.filteredItems[0]); + if (!this.multiSelect) this.cbInput.nativeElement.blur(); + // tslint:disable-next-line: deprecation + if (event.keyCode === keycode.ENTER) { + event.stopPropagation(); + return false; //was processed + } else return true; + // tslint:disable-next-line: deprecation + } else if (event.keyCode === keycode.UP_ARROW || event.keyCode === keycode.DOWN_ARROW) { + if (this.multiSelect) this.autocompleteTrigger.autocomplete._keyManager.setActiveItem(null); + else { + if (this.lastActiveItemIndex !== undefined) { + // tslint:disable-next-line: deprecation + this.autocompleteTrigger.autocomplete._keyManager.setActiveItem((this.lastActiveItemIndex + (event.keyCode === keycode.UP_ARROW ? -1 : 1) + this._dataSource.length) % this._dataSource.length); + } + this.lastActiveItemIndex = undefined; + this.scrollToOption(); + } + event.stopPropagation(); + return false; //was processed + } else if (event.keyCode !== keycode.TAB && event.keyCode !== keycode.ESCAPE && !this.lastFilter + || event.keyCode === keycode.ESCAPE && this.lastFilter) { //otherwise is cleared with tab + this.itemsControl.setValue(''); //clear filter if it was empty + } + return true; //default processing + } + + itemSelectedByKeyboard(event: MatOptionSelectionChange) { + if (event.isUserInput && this.autocompleteTrigger.autocomplete._keyManager.activeItem) this.toggleSelection(this.filteredItems[this.autocompleteTrigger.autocomplete._keyManager.activeItemIndex]); + } + + private displayItem(item: any, init: boolean = false): string { + if (init) { + const caption = this.translate.instant(item[this.displayExpr]); + if (this.displayTemplate) return this.displayTemplate.replace(/\${(.*?)}/g, (found: string, fldname: string) => item[fldname] ?? '').replace('', item[this.keyExpr] ?? '').replace('', caption); + else return caption; + } else return item[this.displayExpr]; + } + + checkRequired() { + if (this.requiredError()) this.formGroup?.setErrors({ required: true }); + } + + requiredError(): boolean { + let req = this.required; + if (this.dropDownState !== EN_DropDownState.Closed) req = this.orgRequired; + return !this.disabled && req !== undefined && req !== false && this.isEmpty(); + } + + + public applyFilter(filter: string): any[] { + + this.lastFilter = filter; + if (this.dropDownState !== EN_DropDownState.Closed) { + + if (filter.length < this.minFilterLength4Search) this.filteredItems.splice(0); + else + if (filter.length > 0) { + const _filter = filter.toLowerCase(); + this.filteredItems = this._dataSource.filter(item => this.displayItem(item).toLowerCase().indexOf(_filter) >= 0); + } else this.filteredItems = this._dataSource.slice(); + + if (this.selectedFirst) { + this.filteredItems.sort((item1, item2) => { + let retval: number = 0; + if (this.selectedFirst) retval = this.checkInSelected(item2) - this.checkInSelected(item1); + if (retval === 0 && this._sortField) retval = !item1[this._sortField] ? -1 : this.compare2items(item1, item2); + return retval; + } + ); + } + + const noSelectedInList: number = this.isEmpty() ? 0 : this.filteredItems.filter(item => this._selectedItemIds.indexOf(item[this.keyExpr]) >= 0).length; + this.selectedAllNonePart = noSelectedInList === 0 ? -1 : (noSelectedInList === this.filteredItems.length ? 1 : 0); + + //no close event is called if filter empty, but drop down is closed - therefore we set status manuelly + if (this.dropDownState === EN_DropDownState.Opened && this.filteredItems.length === 0) this.dropDownState = EN_DropDownState.EmptyFilter; + } + return this.filteredItems; + } + + + public displayFn = (value: any[] | string): (string | undefined) => { //such declaration because of binding + let displayValue: string = ''; + if (Array.isArray(value)) { + // value.forEach((key, index) => displayValue += (index === 0 ? '' : this.separator + ' ') + this._dataSource.find(op => op[this.keyExpr] === key)[this.displayExpr]); + if (this._dataSource) { + value.forEach(vl => { + const item = this._dataSource.find((it) => it[this.keyExpr] === vl); + if (item) { + displayValue += this.separator + ' ' + this.displayItem(item); + } else if (this.selectionNotFound) displayValue += this.separator + ' ' + this.selectionNotFound(vl); + }); + /* + this._dataSource.forEach((item, index) => { + if (value.indexOf(item[this.keyExpr]) >= 0) { + displayValue += this.separator + ' ' + this.displayItem(item); + } + });*/ + } + displayValue = displayValue.slice(this.separator.length + 1); + } else displayValue = value; + + return displayValue; + } + + + private prepareDataSource() { + if (this._customFilter.length > 0) { + this._dataSource = this._origDataSource.filter(item => { + return !this._customFilter.some(filterToken => { //_customFilter tokens are connected with && condition + let tokens: string[] = filterToken.split('!='); + if (tokens.length === 2) { + if (tokens[1] === ' ') return (item[tokens[0]] === null); + return !('' + item[tokens[0]] !== tokens[1]); + } + tokens = filterToken.split('='); + if (tokens.length === 2) { + return !('' + item[tokens[0]] === tokens[1]); + } + tokens = filterToken.split('<'); + if (tokens.length === 2) { + if (!Number.isNaN(Number(item[tokens[0]])) && !Number.isNaN(Number(tokens[1]))) { + return !(Number(item[tokens[0]]) < Number(tokens[1])); + } else return !('' + item[tokens[0]] < tokens[1]); + } + tokens = filterToken.split('>'); + if (tokens.length === 2) { + if (!Number.isNaN(Number(item[tokens[0]])) && !Number.isNaN(Number(tokens[1]))) { + return !(Number(item[tokens[0]]) > Number(tokens[1])); + } else return !('' + item[tokens[0]] > tokens[1]); + } + tokens = filterToken.split('<='); + if (tokens.length === 2) { + if (!Number.isNaN(Number(item[tokens[0]])) && !Number.isNaN(Number(tokens[1]))) { + return !(Number(item[tokens[0]]) <= Number(tokens[1])); + } else return !('' + item[tokens[0]] <= tokens[1]); + } + tokens = filterToken.split('>='); + if (tokens.length === 2) { + if (!Number.isNaN(Number(item[tokens[0]])) && !Number.isNaN(Number(tokens[1]))) { + return !(Number(item[tokens[0]]) >= Number(tokens[1])); + } else return !('' + item[tokens[0]] >= tokens[1]); + } + return false; + }); + }); + } else this._dataSource = this._origDataSource.slice(); + if (this.customFilterFn) this._dataSource = this._dataSource.filter(item => this.customFilterFn(item)); + } + + + private async applyCustomFilterAsync() { + if (!this.initialised || !this._origDataSource) return; //to avoid repeatedly calls during initialising + + const dataSourceWasEmpty = !this._dataSource?.length; + this.prepareDataSource(); + + if (!this.displayExpr) this._displayExpr = 'display'; + + if (this._sortField === '*') this._sortField = this.displayExpr; + + this._dataSource = this._dataSource.map((item, index, arr) => { + if (this._sortField && this._sortField !== this.displayExpr && this._sortField !== this.keyExpr) { + return Object({ + [this.keyExpr]: item[this.keyExpr], + [this.displayExpr]: this.displayItem(item, true), + [this.sortField]: this._sortField ? item[this._sortField] : '', + link: item, + disabled: this.disabledItems.indexOf(item[this.keyExpr]) > -1 + }); + } else { + return Object({ + [this.keyExpr]: item[this.keyExpr], + [this.displayExpr]: this.displayItem(item, true), + link: item, + disabled: this.disabledItems.indexOf(item[this.keyExpr]) > -1 + }); + } + }); + + //checks if the passed value for the selection in the filtered selection list, if not - delete + let selWasChanged: boolean = false; + if (this._dataSource.length > 0 || !dataSourceWasEmpty) { //w/o checking dataSourceWasNotEmpty after deleting the dataSource, selected value is kept + const filterIds = this._dataSource.map(item => item[this.keyExpr]); + for (let inx = this._selectedItemIds.length - 1; inx >= 0; inx--) { + if (filterIds.indexOf(this._selectedItemIds[inx]) === -1) { + if (!this.selectionNotFound) { + this._selectedItemIds.splice(inx, 1); + selWasChanged = true; + } + } + } + } + + + if (this._sortField) this._dataSource.sort((item1, item2) => this.compare2items(item1, item2)); + + console.log('**** - Hensel-Sel: ' + this.placeholder + ' current id=', this._selectedItemIds, 'lenght=', this._dataSource.length, ' wasempty=', !dataSourceWasEmpty, 'waschanged=', selWasChanged); + this.itemsControl.setValue(this._selectedItemIds); + + this.updateGrid(); + + if (this._origDataSource.length > 0 && this.lastShowSpinner === undefined) this.setShowSpinner(false); //if was not set explicetely + else this.openWithFilter = this.openWithFilter; //only in else, bcs is set in setShowSpinner(false) + + if (selWasChanged) { + console.log('**** - Hensel-mark ' + this.placeholder + ' indirect changed'); + setTimeout(() => this.updateParent()); + } + this.markAsTouchedDirty(); + } + + + updateGrid() { + if (this.useResultGrid) { + if (this._dataSource && this._selectedItemIds && this._selectedItemIds.length > 0) { + this.selectedItemsGrid = this._dataSource.filter((item: any) => this._selectedItemIds.indexOf(item[this.keyExpr]) >= 0); + } else this.selectedItemsGrid = []; + } + } + + + compare2items = (item1, item2): number => { + if (item1[this._sortField]) { + if (typeof (item1[this._sortField]) === 'number') return (item1[this._sortField] - item2[this._sortField]) * this.sortDirection; + else return item1[this._sortField].localeCompare(item2[this._sortField]) * this.sortDirection; + } else return 0; + } + + + private applyMarkFiltered(filter: string) { + if (!this.useMarkFiltered || this.dropDownState !== EN_DropDownState.Opened) return; + const inputTexts = this.autocompleteScrollPanel.nativeElement.getElementsByClassName('item'); + if (!inputTexts) return; + for (let index = 0; index < Math.min(this.filteredItems.length, inputTexts.length); index++) { + const iconHtmlInd = inputTexts[index].innerHTML.indexOf(''); + const iconHtml = iconHtmlInd < 0 ? '' : inputTexts[index].innerHTML.slice(0, iconHtmlInd + 11); + if (filter === '') inputTexts[index].innerHTML = iconHtml + this.displayItem(this.filteredItems[index]); + else { //inputTexts[index].innerHTML = this.filteredItems[index][this.displayExpr].replace(filter, '' + filter + ''); + inputTexts[index].innerHTML = iconHtml + this.displayItem(this.filteredItems[index]).replace( + new RegExp(filter + '(?!([^<]+)?<)', 'gi'), '$&'); + } + } + } + + + public itemClicked(event: Event, item: any) { + event.stopPropagation(); + this.toggleSelection(item); + } + + + public toggleSelection(item: any) { + if (item.disabled) return; + if (!this.multiSelect) this._selectedItemIds = []; + if (!this.checkInSelected(item)) { + this._selectedItemIds.push(item[this.keyExpr]); + } else { + const i = this._selectedItemIds.indexOf(item[this.keyExpr]); + this._selectedItemIds.splice(i, 1); + } + + if (!this.minFilterLength4Search) { + //show the complete list again (multiselect), after checking an option + //is not working if we have limitations for search + this.lastFilter = ''; + this.itemsControl.setValue(this.lastFilter); + } + + if (!this.multiSelect) { + this.itemsControl.setValue(this.displayFn(this._selectedItemIds)); + this.selectionDone(); + } else this.itemsControl.setValue(this._selectedItemIds); + + } + + + + public isEmpty(): boolean { + return this._selectedItemIds.length === 0; + } + + + public openDropDown = () => { //such declaration because of binding + if (this.disabled) return; + if (this.dropDownState === EN_DropDownState.Closed) {//if is opened at the first time + if (this.multiSelect) window.addEventListener('keydown', this.onKeyDown, { once: true } as AddEventListenerOptions /*fires one time and is removed*/); + this.orgRequired = this.required; + if (!this.isEmpty()) this.setRequired(false); + this.lastSelection = this._selectedItemIds; + if (!this.multiSelect && this._selectedItemIds.length > 0) { + setTimeout(() => { + this.lastActiveItemIndex = this._dataSource.findIndex(item => item[this.keyExpr] === this._selectedItemIds[0]); + this.autocompleteTrigger.autocomplete._keyManager.setActiveItem(this.lastActiveItemIndex); + this.scrollToOption(); + }, 0); + } + } + if (this.filteredItems.length > 0) this.dropDownState = EN_DropDownState.Opened; + else { + if (this.dropDownState === EN_DropDownState.Opened && this.autocompleteTrigger.panelOpen) this.autocompleteTrigger.closePanel(); + this.dropDownState = EN_DropDownState.EmptyFilter; + } + this.itemsControl.setValue(this.lastFilter); // important the order, must be after setting of dropDownIsOpened + } + + + scrollToOption() { + const autocomplete: MatAutocomplete = this.autocompleteTrigger.autocomplete; + const index = autocomplete._keyManager.activeItemIndex || 0; + const labelCount = _countGroupLabelsBeforeOption(index, autocomplete.options, autocomplete.optionGroups); + if (index === 0 && labelCount === 1) { + // If we've got one group label before the option and we're at the top option, + // scroll the list to the top. This is better UX than scrolling the list to the + // top of the option, because it allows the user to read the top group's label. + autocomplete._setScrollTop(0); + // this.autocompleteScrollPanel.nativeElement.scrollTop = 0; + } else if (index > -1 && autocomplete.panel) { + const panelheight = autocomplete.panel.nativeElement.offsetHeight - (this.autocompleteToolbar?.nativeElement.offsetHeight || 0); + const itemHeight = (autocomplete.options.first)?._element?.nativeElement?.offsetHeight || 30; + this.currentScrollTop = _getOptionScrollPosition((index + labelCount) * itemHeight, itemHeight, this.currentScrollTop, panelheight); + autocomplete._setScrollTop(this.currentScrollTop); + // this.autocompleteScrollPanel.nativeElement.scrollTop = this.currentScrollTop; + } + } + + + public closeDropDown = () => { //such declaration because of binding + this.currentScrollTop = 0; + if (this.hasFocus && this.dropDownState === EN_DropDownState.EmptyFilter) return; //the input box is still focused + + setTimeout(() => { + this.lastFilter = ''; + }); //timeout is needed to avoid open/close drop down effect after click out of component + this.setValueInternally(this.lastSelectedItemIds); + this.dropDownState = EN_DropDownState.Closed; + this.setRequired(this.orgRequired); + if (this.multiSelect) window.removeEventListener('keydown', this.onKeyDown, { once: true } as AddEventListenerOptions /*fires one time and is removed*/); + } + + + public takeFocus = () => { //such declaration because of binding + this.startLeaveFocus = false; + this.hasFocus = true; + this.openDropDown(); + this.focus.emit(this); + } + + + public leaveFocus = () => { //such declaration because of binding + this.hasFocus = false; + if (this.dropDownState !== EN_DropDownState.EmptyFilter) return; //reset the last value if searched string was not matched + this.startLeaveFocus = true; + setTimeout(() => { //gives time to cancel closeDropdown if the clear button is focused + if (this.startLeaveFocus) this.closeDropDown(); + this.startLeaveFocus = false; + }); + } + + public setAll(completed: boolean) { + if (completed) this.selectAll(); + else this.deselectAll(); + } + + + public selectAll() { + this.setValueInternally(this._selectedItemIds.concat(this.filteredItems.map(item => item[this.keyExpr]).filter(item => this._selectedItemIds.indexOf(item) === -1))); + } + + + public deselectAll() { + const filterIds = this.filteredItems.map(item => item[this.keyExpr]); + this.setValueInternally(this._selectedItemIds.filter(id => filterIds.indexOf(id) === -1)); + } + + + public getSelection(val: any[]): string { + return val.sort((a, b) => a - b).join(); + } + + + public updateParent() { + this.formGroup?.updateValueAndValidity(); + } + + + public selectionDone() { + const curSelection = this.getSelection(this._selectedItemIds); + if (this.lastSelection !== curSelection) { + if (this.validate && !this.validate(this._selectedItemIds)) return; + this.lastSelection = this._selectedItemIds; + console.log('**** - Hensel-Sel: ' + this.placeholder + ' selection done'); + this.updateParent(); + this.selectedItemsChange.emit(this.multiSelect ? this._selectedItemIds.slice() : (this._selectedItemIds.length > 0 ? this._selectedItemIds[0] : null)); + this.selectedItemsDisplayChange.emit(this.displayFn(this._selectedItemIds)); + } + this.autocompleteTrigger.closePanel(); + } + + + public clickClear($event: any) { + $event.stopPropagation(); + if (/*this.dropDownState === EN_DropDownState.Opened ||*/ this.lastFilter) { + setTimeout(() => { + this.itemsControl.setValue(''); + this.cbInput?.nativeElement?.focus(); //to call opendropdown after close drop down if minlength>0 + }, 300); + } else { + this.lastSelection = this._selectedItemIds; + if (this.defaultValue !== undefined && this.defaultValue !== null) this.setValueInternally([this.defaultValue]); + else this.setValueInternally([]); + this.selectionDone(); + } + } + + + clickArrow(event?: any) { + if (this.disabled) return; + this.showInputField = true; + setTimeout(() => { this.cbInput?.nativeElement?.focus(); }, 0); + if (event) event.cancel = true; + } + + ngOnDestroy(): void { + if (this.hsRequiredsubscription) this.hsRequiredsubscription.unsubscribe(); + } + + getIcon4Selected(): string { + if (this.displayIconFn) return this.displayIconFn(this._dataSource.find(_item => _item[this.keyExpr] === this._selectedItemIds[0])?.link); + return null; + } + + public markAsDirty() { + if (this.hsMatFormField?._control?.ngControl?.control) { + this.hsMatFormField._control.ngControl.control.markAsDirty(); + console.log('**** - Hensel-mark ' + this.placeholder + ' as dirty'); + this.updateParent(); + } + } + + + public markAsTouched() { + if (this.hsMatFormField?._control?.ngControl?.control) { + this.hsMatFormField._control.ngControl.control.markAsTouched(); + console.log('**** - Hensel-mark ' + this.placeholder + ' as touched'); + this.updateParent(); + } + } + + + public markAsTouchedDirty() { + if (this.hsMatFormField?._control?.ngControl?.control && this.required && this.isEmpty()) { + this.hsMatFormField._control.ngControl.control.markAsTouched(); + this.hsMatFormField._control.ngControl.control.markAsDirty(); + console.log('**** - Hensel-mark ' + this.placeholder + ' as touched/dirty'); + this.updateParent(); + } + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/readme.txt b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/readme.txt new file mode 100644 index 0000000..383e1b1 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-selection/readme.txt @@ -0,0 +1,24 @@ +Inputs: +placeholder (String): A placeholder value for your mat-select +selectPlaceholder(String): Placeholder for options filtering +options (Array of objects): Options object to be listed +selectedOptions (Array of Strings): To pre-populate or preselect options +display (String): Property of every option for display in dropdown +value (String): Property of every option to be returned on option selection; +required (Boolean): To make your mat-field required. Default : false; +multiple (Boolean): Able to select multiple or single. Default: true; +disabled (Boolean): To disable the mat-field. default: false; +appearance (String): Appearance of your mat-field. Supported options: 'legacy' | 'standard' | 'fill' | 'outline'; +formControl (String): If you’re using Angular reactive form, bind your formControl with mat-select-autocomplete output +showErrorMsg (Boolean): Whether show error message or not. Default: false; +errorMsg (String): Custom error message. Default: ‘Field is required’ +labelCount (Number): Number of selected options to be shown in display of mat-select. Default: 1. + +Outputs: +selectionChange (EventEmitter): On every option selection, +this event would be emitted. You could capture the selected options values [Array of Strings] from this event param. + +ViewChild: +If you want to toggle mat-select-autocomplete from your own component event, +you need to import MultiselectComponent in the component and take it’s reference as ViewChild element (eg: matSelect). +Now you could trigger this.matSelect.toggle() to toggle the dropdown. \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.html new file mode 100644 index 0000000..9c5919a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.html @@ -0,0 +1,36 @@ +
+ + + + + + + + + + + + + +
+ + +
+ + image_not_supported + +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.scss new file mode 100644 index 0000000..333d055 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.scss @@ -0,0 +1,83 @@ +@import 'hr-core-consts'; + + +.btn-question-picture { + width: 160px; + height: 50px; + background-color: white; + color: $hrColor-DarkBlue; +} + +.webcam-grid { + height: 100%; + width: 100%; + display: grid; + position: relative; + grid-template-rows: auto minmax(0, 1fr); + grid-template-columns: 0px auto minmax(0, 1fr); + grid-template-areas: + ". webcam-container snapshot ." + ". arrow-take-picture btn-delete ."; + grid-gap: 15px; +} + + + +.no-photo-icon { + // font-size: 250px; + opacity: 20%; +} + +.snapshot { + margin-left: 35px; + grid-area: snapshot; +} + +.webcam_button_icons{ + padding-right: 5px; +} + + +.webcam-container { + grid-area: webcam-container; +} + +.btn-delete { + margin-left: 35px; + grid-area: btn-delete; + width: 160px; + height: 50px; + background-color: white; + color: $hrColor-DarkBlue; +} + +.snapshot, +.webcam-container { + padding: 2px; + // margin-left: 4px; +} + +.arrow-take-picture { + grid-area: arrow-take-picture; + width: 160px; + height: 50px; + background-color: white; + color: $hrColor-DarkBlue; +} + +.DeleteButton { + // color: $hrColor-Green; + // color: $hrColor-DarkBlue; + // position: absolute; + // top: 0px; + // left: 100%; + // transform: translate(-40px); + position: absolute; + top: 12px; + right: 20px; +} + +.DeleteIcon { + font-size: 40px; + color: white; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.ts new file mode 100644 index 0000000..1979d6e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.component.ts @@ -0,0 +1,58 @@ +import { Component, EventEmitter, Input, OnDestroy, Output, ViewChild } from '@angular/core'; +import { WebcamComponent, WebcamImage } from 'ngx-webcam'; +import { Observable, Subject } from 'rxjs'; +import { HenselTranslateService } from '../../services/localization/hensel-translate.service'; + +@Component({ + // tslint:disable-next-line:component-selector + selector: 'hensel-webcam', + templateUrl: 'hensel-webcam.component.html', + styleUrls: ['hensel-webcam.component.scss'], +}) + +export class HenselWebcamComponent implements OnDestroy { + @ViewChild(WebcamComponent) webCam: WebcamComponent; + @Output() public pictureTaken = new EventEmitter(); + @Input() public picture: string; + @Input() public canDelete: boolean = true; + @Input() public disabled: boolean = false; + @Input() public size: number = 250; + + + public videoOptions: MediaTrackConstraints = { + width: { ideal: this.size }, // must be same size + height: { ideal: this.size }, // must be same size (look html) TODO: Input width/height + }; + + public get isInitialized(): boolean { + return this.webCam?.videoInitialized ?? false; + } + + // webcam snapshot trigger + private trigger: Subject = new Subject(); + + + constructor( + public translate: HenselTranslateService, + ) {} + + // tslint:disable-next-line:use-life-cycle-interface + ngOnInit() {} + + public triggerSnapshot(): void { + this.trigger.next(); + } + + + public processSnapshot(webcamImage: WebcamImage): void { + this.pictureTaken.emit(webcamImage); + } + + public get triggerObservable(): Observable { + return this.trigger.asObservable(); + } + + + ngOnDestroy(): void { + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.module.ts new file mode 100644 index 0000000..882c62c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/hensel-webcam/hensel-webcam.module.ts @@ -0,0 +1,27 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { AngularMaterialModule } from '../angular-material.module'; +import { DxButtonModule, DxTooltipModule, DxDataGridModule } from 'devextreme-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { HenselWebcamComponent } from './hensel-webcam.component'; +import { WebcamModule } from 'ngx-webcam'; + + + +@NgModule({ + declarations: [HenselWebcamComponent], + imports: [ + CommonModule, + AngularMaterialModule, + FormsModule, + ReactiveFormsModule, + DxButtonModule, + DxTooltipModule, + WebcamModule, + TranslateModule.forChild(), + DxDataGridModule + ], + exports: [HenselWebcamComponent] +}) +export class HenselWebcamModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.html new file mode 100644 index 0000000..3e6c1ee --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.html @@ -0,0 +1,75 @@ +
+ +
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.scss new file mode 100644 index 0000000..a695c9f --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.scss @@ -0,0 +1,80 @@ +@import 'hr-core-consts'; + +.divFooter { + background-color: $hrColor-DarkBlue; + // position: absolute; + flex-direction: row; + box-sizing: border-box; + // display: flex; + // top: 8em; + width: 100%; //99.4%; + padding: 5px; + // margin: 0 5px 0 5px; + font-size: 10px; + font-weight: 500; + text-align: left; + border-radius: $hrBorder-radius-small $hrBorder-radius-small; +} + +.divFooter>a, span { + color: white; +} + +.data { + padding-left: 5px; + padding-right: 10px !important; + color: $hrColor-LightBlueMain !important; +} + +.data1 { + padding-left: 5px !important; + padding-right: 2px !important; + color: $hrColor-LightBlueMain !important; +} + +/* + * ---------------------------------------- + * animation slide-top + * ---------------------------------------- + */ +/* +.slide-top { + -webkit-animation: slide-top 0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; + animation: slide-top 0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; + animation-delay: 3s; +} + +@-webkit-keyframes slide-top { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 50% { + -webkit-transform: translateY(-50px); + transform: translateY(-50px); + } + + 100% { + -webkit-transform: translateY(-102px); + transform: translateY(-102px); + } +} + +@keyframes slide-top { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 50% { + -webkit-transform: translateY(-50px); + transform: translateY(-50px); + } + + 100% { + -webkit-transform: translateY(-102px); + transform: translateY(-102px); + } +} +*/ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.ts new file mode 100644 index 0000000..585cff7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/footer/footer.component.ts @@ -0,0 +1,64 @@ +import { HttpClient } from '@angular/common/http'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Globals } from '../../../services/globals'; +import { AuthorizeService } from '../../../services/authorize.service'; +import { ServerInfoService } from '../../../services/serverinfo.service'; +import { now } from '../../../utils'; + +const + second = 1000, + minute = second * 60, + hour = minute * 60, + day = hour * 24; + +@Component({ + selector: 'app-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'] +}) + +export class FooterComponent implements OnInit, OnDestroy { + counter: any; + + days: number; + hours: number; + mins: number; + secs: number; + public package_json; + public coreVersion: string; + public devextremeVersion: string; + + constructor( + public globals: Globals, + public serverInfoService: ServerInfoService, + public authService: AuthorizeService, + private http: HttpClient + ) { + this.counter = setInterval(() => this.updateTimer(), 1000); + } + + updateTimer = () => { + if (!this.authService.useJWT || !this.authService.HR_JWT) return; + let distance = this.authService.HR_JWT?.expiresAt?.valueOf() - now(); + if (distance < -3 * second) return; + if (distance < 0) distance = 0; + + this.days = Math.floor(distance / day); + this.hours = this.days > 0 ? 0 : Math.floor((distance % day) / hour); + this.mins = this.days > 0 || this.hours > 1 ? 0 : Math.floor((distance % hour) / minute); + this.secs = this.days > 0 || this.hours > 0 || this.mins > 1 ? 0 : Math.floor((distance % minute) / second); + } + + ngOnInit() { + this.http.get('../../../assets/json/package.json').subscribe((data) => { + this.package_json = data; + this.coreVersion = this.package_json?.version; + this.devextremeVersion = !this.package_json?.peerDependencies || !this.package_json?.peerDependencies['devextreme-angular'] ? undefined : this.package_json?.peerDependencies['devextreme-angular'] + this.devextremeVersion = this.devextremeVersion ?? this.package_json?.dependencies['devextreme-angular']; + }); + } + + ngOnDestroy(): void { + clearInterval(this.counter); + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/favicon.ico b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/favicon.ico new file mode 100644 index 0000000..d65b48a Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/favicon.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.html new file mode 100644 index 0000000..1039d82 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.html @@ -0,0 +1,33 @@ + + + + + + + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.scss new file mode 100644 index 0000000..25d5847 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.scss @@ -0,0 +1,58 @@ +@import 'hr-core-consts'; + +a { + text-decoration: none; + color: white; +} + +a:hover, +a:active { + color: $hrColor-LightBlue; +} + + +.selected { + color: $hrColor-LightBlue; +} + +.navigation-icon { + margin: -3px; +} + +.navigation-items { + list-style-type: none; + padding: 0; + margin: 0; +} + +::ng-deep .ng-star-inserted { + margin-right: 0px !important; +} + +.ng-star-inserted-item { + margin-right: 15px !important; + ; +} + +.restarticon { + color: white; + vertical-align: middle; + cursor: pointer; +} + +a:hover .restarticon { + color: $hrColor-LightBlue; +} + +.redcolor { + color: red; +} + +.nav-icon { + color: inherit; + vertical-align: text-top; +} + +.router-bar { + margin-left: auto; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.ts new file mode 100644 index 0000000..a2183a5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/header/header.component.ts @@ -0,0 +1,44 @@ +import { Component, EventEmitter, inject, Input, OnInit, Output } from '@angular/core'; +import { ACCOUNT_PAGE, Globals, IAppPage, LOGIN_PAGE } from '../../../services/globals'; +import { APPICON4NAVBAR_TOKEN, APPICON4TEST_TOKEN } from '../../../injection-tokens'; +import { AuthorizeService } from '../../../services/authorize.service'; +import { HenselTranslateService } from '../../../services/localization/hensel-translate.service'; +import { ServerInfoService } from '../../../services/serverinfo.service'; + +@Component({ + selector: 'app-header', + templateUrl: './header.component.html', + styleUrls: ['./header.component.scss'] +}) + +export class HeaderComponent implements OnInit { + @Input() public title: string; + @Output() public sidenavToggle = new EventEmitter(); + + public pageLogin: IAppPage = LOGIN_PAGE; + public pageAccount: IAppPage = ACCOUNT_PAGE; + private cnst_AppIcon4Navbar = inject(APPICON4NAVBAR_TOKEN); + private cnst_AppIcon4Test = inject(APPICON4TEST_TOKEN); + public get navBarIconPath(): string { + return this.serverInfoService.isLive() ? this.cnst_AppIcon4Navbar : this.cnst_AppIcon4Test; + } + + constructor( + public globals: Globals, + public authService: AuthorizeService, + public serverInfoService: ServerInfoService, + public translate: HenselTranslateService, + ) { } + + ngOnInit() { + } + + public onToggleSidenav = () => { + this.sidenavToggle.emit(); + } + + refreshPage() { + window.location.reload(); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.html new file mode 100644 index 0000000..8c806e7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.html @@ -0,0 +1,14 @@ +
+ + + + + + +
+ +
+ +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.scss new file mode 100644 index 0000000..9168305 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.scss @@ -0,0 +1,56 @@ +mat-sidenav-container, +mat-sidenav-content, +mat-sidenav { + height: 100%; +} + +mat-sidenav { + width: 300px; +} + +main { + padding: 5px; +} + +.layout-wrapper { + height: 100%; +} + +.flex-wrapper { + height: 100%; +} + +.HeaderMainFooterComponent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid + width: 100%; // 100 % view width (hardware screen) + height: 100%; // 100% view height + grid-template-areas: + 'head' + 'main' + 'foot'; // 3 Rows + grid-template-rows: auto minmax(0, 1fr) auto; // row relationships + grid-template-columns: minmax(0, 1fr); // column relationship +} + +.HeaderComponent { + margin: 0 5px 0 5px; // padding around the header +// padding: 5px; // padding around the header + top: 0; // component + padding = top line + left: 0; // component + padding = left line + right: 0; // component + padding = right line + // ==> with these 3 informations we knew that the component will be stretched at the top of the view + grid-area: head; // grid area: auto height 1fr width +} + +.MainComponent { + grid-area: main; + overflow: hidden; +} + +.FooterComponent { + grid-area: foot; + margin: 0 5px 0 5px; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.ts new file mode 100644 index 0000000..bf39d57 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'app-layout', + templateUrl: './layout.component.html', + styleUrls: ['./layout.component.scss'] +}) +export class LayoutComponent implements OnInit { + @Input() title: string; + constructor() { } + + ngOnInit() { + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.module.ts new file mode 100644 index 0000000..e24926b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/layout.module.ts @@ -0,0 +1,21 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { AngularMaterialModule } from '../angular-material.module'; +import { TranslateModule } from '@ngx-translate/core'; +import { FooterComponent } from './footer/footer.component'; +import { HeaderComponent } from './header/header.component'; +import { LayoutComponent } from './layout.component'; +import { SidenavListComponent } from './sidenav-list/sidenav-list.component'; + +@NgModule({ + declarations: [LayoutComponent, FooterComponent, HeaderComponent, SidenavListComponent], + imports: [ + CommonModule, + AngularMaterialModule, + TranslateModule.forChild(), + RouterModule, + ], + exports: [LayoutComponent, FooterComponent, HeaderComponent, SidenavListComponent] +}) +export class LayoutModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.html new file mode 100644 index 0000000..faa89fa --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.html @@ -0,0 +1,14 @@ + + + + {{page.icon}} + {{page.caption | translate}} + {{'core.caption.logout'| translate}} ({{authService.userName}}) + + + + + menu_open + + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.scss new file mode 100644 index 0000000..19681d0 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.scss @@ -0,0 +1,23 @@ +@import 'hr-core-consts'; + +a { + text-decoration: none; + color: white; +} + +a:hover { + color: $hrColor-LightBlue; +} + +a:hover.selected { + color: white; +} + +.nav-caption { + display: inline-block; + padding-left: 6px; +} + +.selected { + background-color: $hrColor-LightBlue !important; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.ts new file mode 100644 index 0000000..3e60d7d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/layout/sidenav-list/sidenav-list.component.ts @@ -0,0 +1,29 @@ +import { Component, OnInit, Output, EventEmitter, Input, Inject } from '@angular/core'; +import { AuthorizeService } from '../../../services/authorize.service'; +import { Globals, IAppPage, LOGIN_PAGE } from '../../../services/globals'; + +@Component({ + selector: 'app-sidenav-list', + templateUrl: './sidenav-list.component.html', + styleUrls: ['./sidenav-list.component.scss'] +}) +export class SidenavListComponent implements OnInit { + @Input() title: string; + @Output() sidenavClose = new EventEmitter(); + + public pageLogin: IAppPage = LOGIN_PAGE; + public listPages: IAppPage[] = this.globals.appPages; + + constructor( + public authService: AuthorizeService, + public globals: Globals + ) { } + + ngOnInit() { + } + + public onSidenavClose = () => { + this.sidenavClose.emit(); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.html new file mode 100644 index 0000000..72a0975 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.html @@ -0,0 +1,69 @@ +
+ {{overHeader}} +

{{header}}

+ + + + + + + + + + + + + + + + +
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.scss new file mode 100644 index 0000000..ca36e9c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.scss @@ -0,0 +1,94 @@ +@import 'hr-core-consts'; + +.PopupContainer { + width: 330px; + padding-top: 4px; + padding-left: 20px; + padding-right: 20px; + padding-bottom: 10px; + font-size: 14px; +} + +@media only screen and (max-width: 520px) { + .PopupContainer { + width: calc(100% - 40px); + } +} + +.messageOverHeader { + // color: rgba(0, 0, 0, 0.4); + color: $hrColor-DarkBlue; + display: block; + height: 0px; + top: -15px; + left: -25px; + position: relative; +} + +.login-header { + color: $hrColor-DarkBlue; + font-size: 30px; + margin: 30px 0; + font-weight: bold; +} + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid: ; + height: 100%; // 100% view height + grid-template-rows: auto auto auto auto; // row relationships + grid-template-columns: minmax(0, 1fr); // column relationship + grid-column-gap: 15px; + grid-template-areas: + 'login-name' + 'login-password' + 'login-btn-block' + 'login-error' +} + +.messageBoxHeader { + text-align: center; +} + +.mat-stroked-button.mat-accent { + color: white; + background: $hrColor-DarkBlue; +} + + +.login-error { + padding: 16px; + color: $hrColor-Error; + background-color: $hrColor-LightBlue; + // border-radius: $hrBorder-radius-small; + // border: 1px solid; + border-color: $hrColor-DarkBlue; +} + +.login-btn-block { + margin-top: 20px; + grid-area: login-btn-block; +} + + +.login-name { + grid-area: login-name; +} + +.login-password { + grid-area: login-password; +} + +.spinner { + margin-top: -140px; + margin-left: 35%; + z-index: 10; +} + + +.mat-stroked-button[disabled] { + background-color: rgba(0, 0, 0, 0.26); + color: rgba(0, 0, 0, 0.46); +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.ts new file mode 100644 index 0000000..11c336b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-popup/login-popup.component.ts @@ -0,0 +1,70 @@ +import { AfterViewInit, Component, Inject, OnDestroy, ViewChild } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { Globals } from '../../../services/globals'; +import { ENVIRONMENT_TOKEN, IENVIRONMENT } from '../../../injection-tokens'; +import { AuthorizeService } from '../../../services/authorize.service'; +import { HenselTranslateService } from '../../../services/localization/hensel-translate.service'; +import { MAT_DIALOG_DATA, MatDialogRef } from '../../../components/angular-material-index'; +import { HenselInputComponent } from '@app_core/components/hensel-input/hensel-input.component'; + + +@Component({ + selector: 'app-login-popup', + templateUrl: 'login-popup.component.html', + styleUrls: ['login-popup.component.scss'], +}) + +export class LoginPopupComponent implements AfterViewInit, OnDestroy { + public static LOGIN_IS_SHOWN: boolean = false; + public overHeader: string; + public header: string; + public errorMsg: string; + public hide: boolean = true; + public authorizationService: AuthorizeService; + private userSubscription: Subscription; + public showSpinner: boolean = false; + + constructor( + public dialogRef: MatDialogRef, + public globals: Globals, + public translate: HenselTranslateService, + @Inject(MAT_DIALOG_DATA) data: any, + @Inject(ENVIRONMENT_TOKEN) public environment: IENVIRONMENT + ) { + this.overHeader = this.globals.appTitleWithVersion; + this.header = translate.instant('core.caption.registration'); + this.errorMsg = data.errorMsg; + this.authorizationService = data.authorizationService; + this.userSubscription = this.authorizationService.loginAction$.subscribe((resultObject) => { + this.showSpinner = false; + if (resultObject.result) this.close(); + else { + this.errorMsg = resultObject.errMsg; + } + }); + } + + + ngAfterViewInit(): void { + LoginPopupComponent.LOGIN_IS_SHOWN = true; + } + + + close() { + this.dialogRef.close(); + } + + + ngOnDestroy() { + this.userSubscription.unsubscribe(); + LoginPopupComponent.LOGIN_IS_SHOWN = false; + // if (!this.authorizationService.isLoggedIn()) this.authorizationService.loginPopup(); - is not realy needed + } + + login(loginname: string, passw: string) { + if (!loginname || !passw) return; + this.showSpinner = true; + this.authorizationService.login(loginname, passw); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-routing.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-routing.module.ts new file mode 100644 index 0000000..c03dafa --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { LoginComponent } from './login.component'; + + +const routes: Routes = [ + { + path: '**', + component: LoginComponent, + // canActivate: [AuthGuard], + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) + +export class LoginRoutingModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.html new file mode 100644 index 0000000..ecef1ea --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.html @@ -0,0 +1,32 @@ + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.scss new file mode 100644 index 0000000..2b6ba2c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.scss @@ -0,0 +1,52 @@ +@import 'hr-core-consts'; + +.login-wrapper { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding: 0; + margin: 0; + overflow: visible; + display: grid; + grid-column-gap: 15px; + grid-row-gap: 0; + grid-template-columns: repeat(1, minmax(0, auto)); + grid-template-rows: auto repeat(1, minmax(0, 1fr)); + grid-template-areas: + "login-header" + "login-body" +} + +.login-body { + grid-area: login-body; +} + + +.login-header { + grid-area: login-header; + color: $hrColor-DarkBlue; + font-size: 30px; + text-align: center; + margin: 0; +} + +.box { + margin: 2px; + padding: 50px; + width: auto; + border-radius: $hrBorder-radius-big; + max-width: 330px; +} + + +.sub-box { + display: flex; + justify-content: center; + width: auto; +} + +.mat-stroked-button.mat-accent { + color: white; + background: $hrColor-DarkBlue; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.spec.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.spec.ts new file mode 100644 index 0000000..7cb1f3c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginComponent } from './login.component'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [LoginComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.ts new file mode 100644 index 0000000..1bee0cf --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.component.ts @@ -0,0 +1,95 @@ +import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { interval, Subscription } from 'rxjs'; +import { Globals } from '../../services/globals'; +import { ServerInfo } from '../../models/serverinfo'; +import { AppLogsService } from '../../services/applogs.service'; +import { AuthorizeService } from '../../services/authorize.service'; +import { HenselTranslateService } from '../../services/localization/hensel-translate.service'; +import { UINotifierService } from '../../services/notification/uinotifier.service'; +import { PageLoadingService } from '../../services/pageloading.service'; +import { ServerInfoService } from '../../services/serverinfo.service'; +import { LoginPopupComponent } from './login-popup/login-popup.component'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.scss'], +}) + +export class LoginComponent implements OnInit, OnDestroy, AfterViewInit { + + public title: string; + private userLoginSubscription: Subscription; + public serverInfo: ServerInfo; + private returnUrl: string; + private connectionReadySubscription: Subscription; + private checkLoginPopupSubscription: Subscription; + constructor( + public translate: HenselTranslateService, + private globals: Globals, + private serverInfoService: ServerInfoService, + private routerService: Router, + public authorizationService: AuthorizeService, + private appLogsService: AppLogsService, + private uiNotifier: UINotifierService, + private route: ActivatedRoute, + protected pageLoadingService: PageLoadingService, + + ) { + this.title = this.globals.appTitle; + this.userLoginSubscription = this.authorizationService.loginAction$.subscribe((resultObject) => { + if (resultObject.result) { + if (!this.globals.isTheMainPage(this.returnUrl) && this.authorizationService.isLoggedUserChanged()) this.returnUrl = '/' + globals.mainPage.path; + const path = this.returnUrl; //'/' + globals.mainPage.path + this.appLogsService.dlog('After login goto ' + path); + this.routerService.navigate([path]); + } else { + if (this.authorizationService.loginStatus !== this.authorizationService.EN_LoginStatus_Password) { + this.authorizationService.loginPopup(resultObject.errMsg); //show popup only if automatically authorization failed + } + } + }); + } + + + ngOnInit(): void { + this.connectionReadySubscription = this.serverInfoService.connectionReady.subscribe((si: ServerInfo) => { + if (si) { + this.serverInfo = si; + this.doLogin(); + } + }); + + this.checkLoginPopupSubscription = interval(500).subscribe(() => { + if (this.serverInfo + && !this.authorizationService.isLoggedIn() + && this.authorizationService.loginStatus !== this.authorizationService.EN_LoginStatus_Unknown + && !LoginPopupComponent.LOGIN_IS_SHOWN) { + this.doLogin(); + } + }); + } + + ngAfterViewInit() { } + + private doLogin() { + this.returnUrl = this.route.snapshot.queryParams['returnUrl']; + this.appLogsService.dlog('show login', this.authorizationService.user); + if (!this.returnUrl) this.returnUrl = '/' + this.globals.mainPage.path; + + if (this.authorizationService.loginStatus === this.authorizationService.EN_LoginStatus_Unknown) { //first time is called + this.authorizationService.login(); + } else { + this.serverInfoService.serverInfoVisible = this.serverInfoService.defaultServerInfoVisible || this.serverInfoService.serverInfoVisible; + this.authorizationService.loginPopup(null, true /* clears last used login and calls logout$ event */); + } + } + + ngOnDestroy() { + this.userLoginSubscription?.unsubscribe(); + this.connectionReadySubscription?.unsubscribe(); + this.checkLoginPopupSubscription?.unsubscribe(); + + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.module.ts new file mode 100644 index 0000000..15c9281 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/login/login.module.ts @@ -0,0 +1,25 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { LoginRoutingModule } from './login-routing.module'; +import { LoginComponent } from './login.component'; +import { AngularMaterialModule } from '../angular-material.module'; +import { LoginPopupComponent } from './login-popup/login-popup.component'; +import { FormsModule } from '@angular/forms'; +import { TranslateModule } from '@ngx-translate/core'; +import { HenselInputComponent } from '../hensel-input/hensel-input.component'; + +@NgModule({ + declarations: [LoginComponent, LoginPopupComponent], + imports: [ + CommonModule, + LoginRoutingModule, + AngularMaterialModule, + FormsModule, + HenselInputComponent, + TranslateModule.forChild() + ], + exports: [LoginComponent] +}) + +export class LoginModule { +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.html new file mode 100644 index 0000000..36936e1 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.html @@ -0,0 +1,23 @@ +
+ + {{overHeader}} +

{{header}}

+ + info + warning + error_outline + contact_support + {{message}} + +
+ +
+
+
diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.scss new file mode 100644 index 0000000..0ba08c1 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.scss @@ -0,0 +1,237 @@ +@import 'hr-core-consts'; + +.PopupContainer { + max-width: 500px; +} + +.large .PopupContainer { + max-width: 600px; +} + +.buttonClose { + font-size: 16px; + cursor: pointer; + text-align: center; + margin-left: auto; + float: right; +} + + +.messageOverHeader { + // color: rgba(0, 0, 0, 0.4); + color: $hrColor-DarkBlue; + display: block; + height: 0px; + top: -20px; + left: -15px; + position: relative; +} + +.large .messageOverHeader { + font-size: initial; +} + +.large .messageBoxHeader { + font-size: x-large; +} + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; + height: 100%; + grid-template-columns: auto minmax(0, 1fr); + grid-template-rows: auto auto; + grid-column-gap: 15px; + grid-row-gap: 20px; + grid-template-areas: + 'icon message' + 'buttons buttons' +} + +.icon { + grid-area: icon; + font-size: 65px; + // float: left; + // padding: 10px 10px 0px 10px; +} + +.large .icon { + font-size: 80px; +} + +.infoIcon { + color: $hrColor-DarkBlue; +} + +.errorIcon { + color: red; +} + + +.warningIcon { + color: $hrColor-DarkBlue; +} + + +.message { + grid-area: message; + font-size: larger; + overflow-wrap: break-word; + max-width: 100%; + margin: auto; + margin-left: 0; + white-space: pre-wrap; +} + +.large .message { + font-size: large; +} + +.buttons1 { + grid-area: buttons; + padding: 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; + height: auto; + grid-template-rows: auto; + grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-column-gap: 30px; + grid-template-areas: + '. btn1 .' +} + + +.buttons2 { + grid-area: buttons; + padding: 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; + height: auto; + grid-template-rows: auto; + grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-column-gap: 30px; + grid-template-areas: + '. btn1 btn2 .' +} + + +.buttons3 { + grid-area: buttons; + padding: 0; // no extra padding -> padding is calculated in the child comp + margin-left: 0px; + margin-top: 10px; + margin-right: 0px; + margin-bottom: 0px; + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; + height: auto; + grid-template-rows: auto; + grid-template-columns: minmax(0, 1fr) repeat(3, minmax(0, 2fr)) minmax(0, 1fr); + grid-column-gap: 30px; + grid-template-areas: + '. btn1 btn2 btn3 .' +} + + +.btn1 { + grid-area: btn1; +} + +.btn2 { + grid-area: btn2; +} + +.btn3 { + grid-area: btn3; +} + + +.large .btn, +.large .new-btn { + font-size: medium; +} + +.new-buttons1 { + grid-area: buttons; + padding: 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; + height: auto; + grid-template-rows: auto; + grid-column-gap: 10px; + grid-template-columns: repeat(3, 1fr); + grid-template-areas: + '. . btn1' +} + +.new-buttons2 { + grid-area: buttons; + padding: 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; + height: auto; + grid-template-rows: auto; + grid-column-gap: 10px; + grid-template-columns: repeat(4, 1fr); + grid-template-areas: + '. . btn1 btn2' +} + + +.new-buttons3 { + grid-area: buttons; + padding: 0; // no extra padding -> padding is calculated in the child comp + margin-left: 0px; + margin-top: 10px; + margin-right: 0px; + margin-bottom: 0px; + overflow: hidden; // overflow hidden => all "to big" child components are hidden + height: auto; + display: grid; + grid-template-rows: auto; + grid-column-gap: 10px; + grid-template-columns: repeat(5, 1fr); + grid-template-areas: + '. . btn1 btn2 btn3' +} + +@media only screen and (max-width: 600px) { + .new-buttons1 { + grid-template-columns: 0.5fr 1fr 0.5fr; + grid-template-areas: + '. btn1 .' + } +} + +@media only screen and (max-width: 600px) { + .new-buttons3 .mat-button, + .new-buttons3 .mat-fab, + .new-buttons3 .mat-flat-button, + .new-buttons3 .mat-icon-button, + .new-buttons3 .mat-mini-fab, + .new-buttons3 .mat-raised-button, + .new-buttons3 .mat-stroked-button { + font-size: 3v; + } + + .new-buttons2 { + grid-template-columns: repeat(2, 1fr); + grid-template-areas: + 'btn1 btn2' + } + + .new-buttons3 { + grid-template-columns: repeat(3, 1fr); + grid-template-areas: + 'btn1 btn2 btn3' + } +} + + +// ::ng-deep .mat-button-focus-overlay { background-color: inherit; } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.ts new file mode 100644 index 0000000..92a47c8 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.component.ts @@ -0,0 +1,85 @@ +import * as keycode from '@angular/cdk/keycodes'; +import { AfterViewInit, Component, HostListener, Inject, ViewChild } from '@angular/core'; +import { NgForm } from '@angular/forms'; +import * as Cnst from '../../consts'; +import { Globals, IMessageBoxButton, IMessageBoxData } from '../../services/globals'; +import { HenselTranslateService } from '../../services/localization/hensel-translate.service'; +import { MAT_DIALOG_DATA, MatDialogRef } from '../angular-material-index'; + +const enum EN_MessageBoxInterfaceType { + old = '', + new = 'new-' +} + +@Component({ + // tslint:disable-next-line: component-selector + selector: 'hr-message-box', + templateUrl: 'message-box.component.html', + styleUrls: ['message-box.component.scss'], +}) + +export class MessageBoxComponent implements AfterViewInit { + @ViewChild('popupForm') detailForm: NgForm; + + public description: string; + public readOnly: boolean = false; + public messageBoxInterfaceType: EN_MessageBoxInterfaceType = EN_MessageBoxInterfaceType.new; + + public overHeader: string; + public header: string; + public message: string; + public buttons: IMessageBoxButton[]; + public cancelButtonIdx: number; + public defaultButtonIdx: number; + public messageType: Cnst.EN_LogType; + + constructor( + public dialogRef: MatDialogRef, + public translate: HenselTranslateService, + public globals: Globals, + @Inject(MAT_DIALOG_DATA) data: IMessageBoxData + ) { + this.overHeader = this.translate.translateString(data.overHeader); + this.header = this.translate.translateString(data.header); + this.message = this.translate.translateString(data.message); + this.buttons = data.buttons; + this.messageType = data.type; + if (this.buttons.length === 1) { + this.buttons[0].default = true; + this.buttons[0].cancel = true; + } + this.buttons.forEach((btn: IMessageBoxButton, index: number) => { + if (btn.default) this.defaultButtonIdx = index; + if (btn.cancel) this.cancelButtonIdx = index; + if (!btn.code) btn.code = 0; + }); + } + + ngAfterViewInit(): void { + setTimeout(() => document.getElementById('btn' + (this.defaultButtonIdx + 1))?.focus()); + } + + close(code: number) { + this.dialogRef.close(code); + } + + btnClick(btn: IMessageBoxButton) { + this.close(btn?.code || 0); + } + + + @HostListener('window:keydown', ['$event']) + popupKeyboardInput(event: any) { + switch (event.which) { + case keycode.ESCAPE: + event.stopPropagation(); + this.btnClick(this.buttons[this.cancelButtonIdx]); + return false; + case keycode.ENTER: + event.stopPropagation(); + this.btnClick(this.buttons[this.defaultButtonIdx]); + return false; + } + return true; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.module.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.module.ts new file mode 100644 index 0000000..2404f05 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/message-box/message-box.module.ts @@ -0,0 +1,21 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { AngularMaterialModule } from '../angular-material.module'; +import { TranslateModule } from '@ngx-translate/core'; +import { MessageBoxComponent } from './message-box.component'; +import { MatDialogModule } from '../angular-material-index'; + + +@NgModule({ + declarations: [MessageBoxComponent], + imports: [ + CommonModule, + AngularMaterialModule, + MatDialogModule, + FormsModule, + TranslateModule.forChild(), + ], + exports: [MessageBoxComponent], +}) +export class MessageBoxModule { } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.html b/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.html new file mode 100644 index 0000000..244bae6 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.html @@ -0,0 +1,29 @@ + diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.scss b/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.scss new file mode 100644 index 0000000..6904b86 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.scss @@ -0,0 +1,66 @@ +// .PopupContainer { +// // padding: 20px; +// } + + +.buttonLayoutCancel { + font-size: 16px; + cursor: pointer; + text-align: center; + margin-left: auto; + float: right; +} + + +.HeaderInfo { + font-size: 16px; + margin-left: -5px; +} + + +.PopupContent { + padding: 0 0 0; // no extra padding -> padding is calculated in the child comp + margin: 0; // see above + overflow: hidden; // overflow hidden => all "to big" child components are hidden + display: grid; // we define a grid: ; + height: 100%; // 100% view height + grid-template-rows: auto auto; // row relationships + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); // column relationship + grid-column-gap: 15px; + grid-template-areas: + 'field1 field2' + 'buttons buttons' +} + +.buttons { + grid-area: buttons; + padding: 0; + margin: 0; + overflow: hidden; + display: grid; + height: 100%; + grid-template-rows: auto; + grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-column-gap: 30px; + grid-template-areas: + 'empty1 btnsave btncancel empty2' +} + + +.btnSave { + margin-top: 10px; + grid-area: btnsave; +} + +.btnCancel { + margin-top: 10px; + grid-area: btncancel; +} + +.field1 { + grid-area: field1; +} + +.field2 { + grid-area: field2; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.ts b/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.ts new file mode 100644 index 0000000..29229a7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/components/popup-base/popup-base.component.ts @@ -0,0 +1,91 @@ +import * as keycode from '@angular/cdk/keycodes'; +import { AfterViewInit, Component, HostListener, inject, Inject, QueryList, ViewChild, ViewChildren } from '@angular/core'; +import { NgForm } from '@angular/forms'; +import { Globals } from '../../services/globals'; +import { BaseEntity } from '../../models/generics/baseentity'; +import { BaseEntityWrapper } from '../../models/generics/baseentity.wrapper'; +import { BaseEntityListWrapper } from '../../models/generics/baseentitylist.wrapper'; +import { MAT_DIALOG_DATA, MatDialogRef, MatFormField } from '../angular-material-index'; + + +@Component({ + selector: 'app-popup-base', + templateUrl: 'popup-base.component.html', + styleUrls: ['popup-base.component.scss'], +}) + +export class PopupBaseComponent implements AfterViewInit { + @ViewChild('popupForm') detailForm: NgForm; + @ViewChildren(MatFormField) materialInputFields: QueryList; + + public description: string; + public readOnly: boolean = false; + + public keyItemName: string; + public baseEntityWrapper: BaseEntityWrapper; + + protected _focusedItem: BaseEntity; + public get focusedItem(): BaseEntity { + return this._focusedItem; + } + public set focusedItem(value: BaseEntity) { + this._focusedItem = value; + } + + public list: BaseEntityListWrapper; + + public data = inject(MAT_DIALOG_DATA); + public globals = inject(Globals); + public dialogRef = inject(MatDialogRef); + private lastDetailForm; + + constructor( + ) { + this.save = this.save.bind(this); + this.baseEntityWrapper = this.data.baseEntityWrapper; + this.keyItemName = this.data.keyItemName; + this.description = this.data.description; + this.readOnly = this.data.readOnly; + this.list = this.data.list; + this._focusedItem = this.baseEntityWrapper?.entity; + } + + ngAfterViewInit(): void { + this.lastDetailForm = this.baseEntityWrapper.detailForm; + this.baseEntityWrapper.detailForm = this.detailForm; + // this.baseEntityWrapper.entityWasChanged = false; //!!!, if set false we cannot control that form could be opened already ready to save + const self = this; + setTimeout(() => { //to avoid ExpressionChangedAfterItHasBeenCheckedError + //mark as changed, otherwise required mat-form-field does not get class "mat-form-field-invalid" as should because of required + self.materialInputFields.forEach(matField => matField._control.ngControl.control.markAsDirty()); + // self.hsInputFields.forEach(hs => hs.markAsDirty()); + }, 0); + + } + + close(result: any) { + this.baseEntityWrapper.detailForm = this.lastDetailForm; + this.dialogRef.close(result); + } + + @HostListener('window:keydown', ['$event']) + popupKeyboardInput(event: any) { + if (!this.baseEntityWrapper.keyDownListenerStopped) { + switch (event.which) { + case keycode.ESCAPE: // ESC + event.stopPropagation(); + this.cancel(); + return false; + } + } + return true; + } + + cancel() { + this.baseEntityWrapper.cancelWithSave(this.save, () => this.close(false)); + } + + save() { + this.baseEntityWrapper.save(() => this.close(true)); + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/consts.ts b/ClientApp/staff-db-ui/src/app/shared/core/consts.ts new file mode 100644 index 0000000..4cfc222 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/consts.ts @@ -0,0 +1,140 @@ +import { formatDate } from '@angular/common'; +import { ɵDEFAULT_LOCALE_ID } from '@angular/core'; +import * as moment_ from 'moment'; + +export const cnst_IP_ADDRESS_SOURCE_URL = 'https://api.ipify.org/?format=json'; +export const cnst_HEADER_KEY_LOGINNAME = 'Loginname'; +export const cnst_LoginAuth_URL = 'LoginWithAuthorization'; +export const cnst_LoginJWT_URL = 'LoginWithJWT'; +export const cnst_LoginPassw_URL = 'LoginWithNameAndPassword'; +export const cnst_JWT_Expired = 'Benutzerauthentifizierung ist abgelaufen!'; +export const cnst_CANCEL_ERROR = 'cancel_error'; +export const cnst_ErrorCode4Unauthorized = 401; + +export enum EN_AppColors { + returnRequestColor = 'green', + startRequestColor = 'blue', + + showSpinnerColor = 'gray', + hideSpinnerColor = 'red', +} + + +export const DATE_FORMATS = { + parse: { + dateInput: 'DD.MM.YYYY', + }, + display: { + dateInput: 'DD.MM.YYYY', + monthYearLabel: 'MMM YYYY', + dateA11yLabel: 'LL', + monthYearA11yLabel: 'MMMM YYYY', + monthShortName: 'MMM', + date4WebAPI: 'yyyy-MM-dd', + dateTime4JSON: 'yyyy-MM-ddTHH:mm:ss.SSS', + dateFormat: 'dd.MM.yyyy', + dateTimeFormat: 'dd.MM.yyyy HH:mm', + dateFormatHensel: 'd MMM YYYY', + momentFormat: { + date4WebAPI: 'YYYY-MM-DD', + dateTime4JSON: 'YYYY-MM-DDTHH:mm:ss.SSS', + dateFormat: 'DD.MM.YYYY', + dateTimeFormat: 'DD.MM.YYYY HH:mm', + }, + timeFormat: 'HH:mm', + }, +}; + + + +//Date format for dates in Web API +// Values for All/None in filter drop down list +export const enum EN_DropDownConst4Filter { + AllCaption = 'core.dropdown-option.all', + AllValueString = '*', + AllValueInt = 0, + NoneCaption = 'core.dropdown-option.none', + NoneValueString = '_', + NoneValueInt = -1 +} + + +export const enum EN_EntityEditingStates { + View = 0, + Edit = 1, + New = 2, + EditKey = 3, + Idle = 4 +} + +export const enum EN_EntityBeforeSaveCallBackResults { + Ok_Continue = 0, + Ok_Break = 1, + Error_Continue = 2, + Error_Break = 3 +} + +export const enum EN_Error { + Save = 'Saving unsucceeded' +} + +export enum EN_LogType { + message = 'Message', + warning = 'Warning', + error = 'Error', + confirmation = 'Question', + guid_message = 'HTTPtiming', + + debug_message = 'Debug', +} + +export enum EN_LoginStatus { + unknown = 0, + loginWithNameAndPassword = 1, + jwt = 2, + windowsAuthorizatoin = 3 +} + +export enum EN_DateFormats { + WebAPI = 0, + Date = 1, + DateTime = 2, + JSON = 3 +} + +Date.prototype.toJSON = function () { return formatDate(this, DATE_FORMATS.display.dateTime4JSON, ɵDEFAULT_LOCALE_ID /* does not matter a culture, we are using explicit date format*/); }; + +moment_.fn.toJSON = function () { return this.format(DATE_FORMATS.display.momentFormat.dateTime4JSON); }; + +export const GridExportButtonWidth = 21; + +export interface SupportedCulture { + culture: string; + country: string; + languageName: string; + flag?: string; +} + + +export interface SupportedLanguage { + langCode: string; + languageName: string; +} + +export const SUPPORTED_CULTURES: SupportedCulture[] = [ + {culture: 'de-DE', country: 'core.caption.country-ge', languageName: 'core.caption.lang-ge'}, + {culture: 'de-AT', country: 'core.caption.country-at', languageName: 'core.caption.lang-at'}, + {culture: 'en-GB', country: 'core.caption.country-gb', languageName: 'core.caption.lang-gb'}, + {culture: 'en-US', country: 'core.caption.country-us', languageName: 'core.caption.lang-us'}, + {culture: 'en-AU', country: 'core.caption.country-au', languageName: 'core.caption.lang-au'}, + {culture: 'fr-FR', country: 'core.caption.country-fr', languageName: 'core.caption.lang-fr'}, + {culture: 'en-MY', country: 'core.caption.country-my', languageName: 'core.caption.lang-my'}, + // {culture: 'ko-KR', country: 'core.caption.country-kr', languageName: 'core.caption.lang-kr'}, +]; + +export const SUPPORTED_LANGUAGES: SupportedLanguage[] = [ + {langCode: 'de', languageName: 'core.caption.lang-ge'}, + {langCode: 'en', languageName: 'core.caption.lang-us'}, + {langCode: 'fr', languageName: 'core.caption.lang-fr'}, + // {langCode: 'ko', languageName: 'core.caption.lang-kr'}, +]; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/0_base-dir.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/0_base-dir.scss new file mode 100644 index 0000000..d5b4c8c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/0_base-dir.scss @@ -0,0 +1,6 @@ +/*====================================== + BASE-DIRECTORY +======================================*/ + +@import 'hr-typography.scss'; +@import 'hr-spacing.scss'; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-core-consts.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-core-consts.scss new file mode 100644 index 0000000..618e430 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-core-consts.scss @@ -0,0 +1,47 @@ +/*==================================== + CI-COLORS +======================================*/ +$hrColor-DarkBlue: #0b3a62; +$hrColor-LightBlueMain: #76a9cb; +$hrColor-LightBlue: #78b7e5; +$hrColor-DarkGrey: #3c3c3b; +$hrColor-LightGrey: #878787; +$hrColor-Green: #76b82a; +$hrColor-Red: #B22222; +$hrColor-Error: #e71010; +$hrColor-Orange: #FF4500; +$hrColor-Alpha_Disabled: 0.8; +$hrColor-Link: #0180b9; + +/*==================================== + BORDER +======================================*/ +//radius +$hrBorder-radius-small: 4px; +$hrBorder-radius-middle: 8px; +$hrBorder-radius-big: 10px; + +//style +$hr-Border-style: solid; + +//border-color +$hr-Border-color: $hrColor-LightGrey; + +/*==================================== + Typography +======================================*/ +$hr-Fonts-small: 10px; +$hr-Fonts-medium: 15px; +$hr-Fonts-big: 30px; + +/*==================================== + Miscellaneous +======================================*/ +//positiv cell output +::ng-deep .cell_positive_balance { + color: $hrColor-Green; +} +//negativ cell output +::ng-deep .cell_negative_balance { + color: $hrColor-Red; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-core.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-core.scss new file mode 100644 index 0000000..5233474 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-core.scss @@ -0,0 +1,10 @@ +/*====================================== + BASE-IMPORT +======================================*/ + +//Import all DIR @ once +@import 'hr-core-consts.scss'; +@import '../3-vendor/3_vendor-dir.scss'; +@import '0_base-dir.scss'; +@import '../1-components/1_components_dir.scss'; +@import '../2-helpers/2_helper-dir.scss'; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-spacing.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-spacing.scss new file mode 100644 index 0000000..99ac738 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-spacing.scss @@ -0,0 +1,43 @@ +/*===================================== + GLOBAL +======================================*/ +//margins, overflows or padding stylings +.summarySum { + overflow: inherit; +} + +.summaryAvg { + overflow: inherit; +} + +.summaryPercent { + overflow: inherit; +} + +.summarySumOdd { + overflow: visible; +} + +/*==================================== + BUTTON +======================================*/ +.btn_spacing { + margin-right: 10px; +} + +/*==================================== + Angular specific +======================================*/ +::ng-deep .ng-star-inserted { + margin-right: 0px !important; +} + +.ng-star-inserted-item { + margin-right: 15px !important; +} + + +//Number alligment +.number { + text-align: right !important; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-typography.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-typography.scss new file mode 100644 index 0000000..9c927c3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/0-base/hr-typography.scss @@ -0,0 +1,47 @@ +@import 'hr-core-consts.scss'; +/*===================================== + TYPOGRAPHY +======================================*/ +// Acitve link styling for navbar +a { + text-decoration: none; + color: white; +} + +a:hover, +a:active { + color: $hrColor-LightBlue; +} + +a:hover.selected { + color: white; +} + +.selected { + color: $hrColor-LightBlue; +} + +/*=========================================================================================================================*/ + +// Sum styling before and after +.summarySum::before { + // content: "\2211\0020"; //summ symbol+space + font-size: larger; +} + +.summaryAvg::before { + content: "\2300\0020"; //avg symbol+space + font-size: 17px; + zoom: 1.4; + vertical-align: top; +} + +.summarySumOdd::before { + content: "\2211\0020"; //summ symbol+space + font-size: larger; +} + +.summaryPercent::after { + content: "\0025"; //space+% symbol + font-size: larger; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/1_components_dir.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/1_components_dir.scss new file mode 100644 index 0000000..8513cf7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/1_components_dir.scss @@ -0,0 +1,10 @@ +/*==================================== + COMPONENTS-DIRECTORY +======================================*/ + +@import 'hr-grids.scss'; +@import 'hr-toolbars.scss'; +@import 'hr-button.scss'; +@import 'hr-checkbox.scss'; +@import 'hr-additional.scss'; +@import 'hr-badge.scss'; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-additional.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-additional.scss new file mode 100644 index 0000000..fa6257e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-additional.scss @@ -0,0 +1,35 @@ +/*==================================== + HR-ADDITIONAL +======================================*/ + +.datePicker { + border-bottom: 1px dotted gray; +} + +.hensel-notifier { + background-color: rgba(0, 0, 0, 0.4); + // color: rgba(0, 0, 0, 0.7); + color: rgba(255, 255, 255, 1); + // color: $hrColor-DarkBlue; +} + +.mat-calendar-next-button::after, +.mat-calendar-previous-button::after { + margin: 7.5px !important; +} + + +.messageBoxHeader { + font-size: large !important; + font-weight: bold !important; + margin-bottom: 0px !important; + padding: 0 0 10px 0 !important; +} + +.glowButton { + box-shadow: 0 5px 20px orangered !important; +} + +.mat-sidenav { + --mat-sidenav-container-background-color: white; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-badge.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-badge.scss new file mode 100644 index 0000000..6c8dcaf --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-badge.scss @@ -0,0 +1,192 @@ +[hr-badge-after], +[hr-badge-before] { + --badge-offset-x: calc(0px - var(--badge-size) / 3); + --badge-offset-y: calc(0px - var(--badge-size) / 3); + --badge-size: 1.5rem; + --circle-size: 2rem; + --dot-offset: 0.5rem; + --dot-size: 0.5rem; + + --badge-bottom: initial; + --badge-background-color: hsl(195, 100%, 30%); + --badge-border-radius: 0; + --badge-color: hsl(195, 100%, 99%); + --badge-display: inline-flex; + --badge-font-size: 0.625rem; + --badge-font-weight: 700; + --badge-hight: auto; + --badge-left: initial; + --badge-padding: 0; + --badge-position: static; + --badge-right: initial; + --badge-top: initial; + --badge-text-transform: uppercase; + --badge-width: initial; + + position: relative; +} + +[hr-badge-after]:not([hr-badge-after=""])::after { + content: attr(hr-badge-after); +} + +[hr-badge-font-size]:not([hr-badge-font-size=""]) { + --badge-font-size: attr(hr-badge-font-size); +} + +[hr-badge-before]:not([hr-badge-before=""])::before { + content: attr(hr-badge-before); +} + +[hr-badge-after]:not([hr-badge-after=""])::after, +[hr-badge-before]:not([hr-badge-before=""])::before { + align-items: center; + background: var(--badge-background-color) !important; + border-radius: var(--badge-border-radius); + bottom: var(--badge-bottom); + box-shadow: var(--bxsh); + box-sizing: border-box; + color: var(--badge-color); + display: var(--badge-display); + font-size: var(--badge-font-size); + font-weight: var(--badge-font-weight); + height: var(--badge-hight); + justify-content: center; + left: var(--badge-left); + padding: var(--badge-padding); + position: var(--badge-position); + right: var(--badge-right); + text-decoration: none; + text-transform: var(--badge-text-transform); + top: var(--badge-top); + width: var(--badge-width); +} + +/* MODIFIERS */ +[hr-badge-after-type*="badge"]::after, +[hr-badge-before-type*="badge"]::before { + --badge-border-radius: var(--badge-size); + --bxsh: 0 0 0 2px rgba(255, 255, 255, 0.5); + --badge-hight: var(--badge-size); + --badge-padding: 0; + --badge-position: absolute; + --badge-width: var(--badge-size); +} +[hr-badge-after-type*="circle"], +[hr-badge-before-type*="circle"]{ + align-items: center; + display: flex; +} +[hr-badge-after-type*="circle"]::after, +[hr-badge-before-type*="circle"]::before { + --badge-border-radius: 50%; + --badge-font-weight: 400; + --badge-hight: var(--circle-size); + // --badge-position: relative; + // --badge-top: -0.75em; + --badge-text-transform: initial; + --badge-width: var(--circle-size); +} +[hr-badge-after-type*="circle"]::after, +[hr-badge-after-type*="pill"]::after { + margin-inline-start: 1ch; +} +[hr-badge-before-type*="circle"]::before, +[hr-badge-before-type*="dot"]::before, +[hr-badge-before-type*="pill"]::before { + margin-inline-end: 1ch; +} +[hr-badge-after-type*="dot"]::after, +[hr-badge-before-type*="dot"]::before { + --badge-border-radius: 50%; + --badge-display: inline-block; + --badge-font-size: 50%; + --badge-hight: var(--dot-size); + --badge-padding: 0; + --badge-position: relative; + --badge-top: -1px; + --badge-width: var(--dot-size); +} +[hr-badge-after-type*="dot"]::after, +[hr-badge-before-type*="dot"]::before { + content: "" !important; +} +[hr-badge-after-type*="pill"]::after, +[hr-badge-before-type*="pil"]::before { + --badge-border-radius: 1rem; + --badge-padding: 0.25rem 0.75rem; + --badge-position: relative; + --badge-top: -1px; +} + +/* COLORS */ +[hr-badge-after-type*="blue"]::after, +[hr-badge-before-type*="blue"]::before { + --badge-background-color: #007acc; +} +[hr-badge-after-type*="darkgray"]::after, +[hr-badge-before-type*="darkgray"]::before { + --badge-background-color: #706e6b; + --badge-color: #fff; +} +[hr-badge-after-type*="green"]::after, +[hr-badge-before-type*="green"]::before { + --badge-background-color: #04844b; +} +[hr-badge-after-type*="lightgray"]::after, +[hr-badge-before-type*="lightgray"]::before { + --badge-background-color: #ecebea; + --badge-color: #080707; +} +[hr-badge-after-type*="orange"]::after, +[hr-badge-before-type*="orange"]::before { + --badge-background-color: #ffb75d; + --badge-color: #080707; +} + +[hr-badge-after-type*="red"]::after, +[hr-badge-before-type*="red"]::before { + --badge-background-color: #ff0900;//#c23934; +} + +/* POSITION */ +[hr-badge-after-type*="top"]::after, +[hr-badge-before-type*="top"]::before { + --badge-bottom: auto; + --badge-position: absolute; + --badge-top: var(--dot-offset); +} +[hr-badge-after-type*="right"]::after, +[hr-badge-before-type*="right"]::before { + --badge-left: auto; + --badge-position: absolute; + --badge-right: var(--dot-offset); +} +[hr-badge-after-type*="bottom"]::after, +[hr-badge-before-type*="bottom"]::before { + --badge-bottom: var(--dot-offset); + --badge-position: absolute; + --badge-top: auto; +} +[hr-badge-after-type*="left"]::after, +[hr-badge-before-type*="left"]::before { + --badge-position: absolute; + --badge-right: auto; + --badge-left: var(--dot-offset); +} +[hr-badge-after-type*="badge"][hr-badge-after-type*="top"]::after, +[hr-badge-before-type*="badge"][hr-badge-before-type*="top"]::before { + --badge-top: var(--badge-offset-y); +} +[hr-badge-after-type*="badge"][hr-badge-after-type*="right"]::after, +[hr-badge-before-type*="badge"][hr-badge-before-type*="right"]::before { + --badge-right: var(--badge-offset-x); +} +[hr-badge-after-type*="badge"][hr-badge-after-type*="bottom"]::after, +[hr-badge-before-type*="badge"][hr-badge-before-type*="bottom"]::before { + --badge-bottom: var(--badge-offset-y); +} +[hr-badge-after-type*="badge"][hr-badge-after-type*="left"]::after, +[hr-badge-before-type*="badge"][hr-badge-before-type*="left"]::before { + --badge-left: var(--badge-offset-x); +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-button.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-button.scss new file mode 100644 index 0000000..73f55fa --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-button.scss @@ -0,0 +1,11 @@ +/*===================================== + HR-BUTTON +======================================*/ +.filterButtons .filterBtn { + margin-left: 2px; + // margin-right: 1px; + margin-top: 6px; + padding-right: 5px !important; + padding-left: 5px !important; + width: 90px; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-checkbox.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-checkbox.scss new file mode 100644 index 0000000..c20bd75 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-checkbox.scss @@ -0,0 +1,9 @@ +/*===================================== + Checkboxes +======================================*/ + +.hr-check-box { + margin-top: 13px; + float: right; + text-align: right; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-grids.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-grids.scss new file mode 100644 index 0000000..a1b1e69 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-grids.scss @@ -0,0 +1,3 @@ +/*===================================== + Grid's +======================================*/ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-toolbars.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-toolbars.scss new file mode 100644 index 0000000..4b37489 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/1-components/hr-toolbars.scss @@ -0,0 +1,32 @@ +/*===================================== + Toolbar's +======================================*/ + +//--- tool bar settings +.mat-toolbar { + --mat-toolbar-title-text-weight: 500; + --mat-toolbar-title-text-size: 20px; +} + +.toolbar-button-row { + display: table; +} + +.toolbar-button-row button { + display: table-cell; + margin-right: 1px !important; +} + +.toolbar-flex-container { + display: flex; + justify-content: space-between; + width: auto; + height: 100%; + padding-top: 1px; + padding-left: 2px; + flex-direction: column; +} + +.toolbar-button-last { + margin-right: 0 !important; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/2-helpers/2_helper-dir.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/2-helpers/2_helper-dir.scss new file mode 100644 index 0000000..ee3ba51 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/2-helpers/2_helper-dir.scss @@ -0,0 +1,5 @@ +/*==================================== + HELPER'S-DIRECTORY +======================================*/ + +@import 'hr-functionalities.scss'; \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/2-helpers/hr-functionalities.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/2-helpers/hr-functionalities.scss new file mode 100644 index 0000000..18384c5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/2-helpers/hr-functionalities.scss @@ -0,0 +1,53 @@ +@import '0_base-dir.scss'; +/*===================================== + Functionalities +======================================*/ + +//disable clicks in selected area +.disableClicks { + background-color: rgba(1, 1, 1, 0.4); + // pointer-events: none; + // background: rgba(0, 0, 0, 0.32); + // opacity: 1; + position: fixed; + bottom: 0; + left: 0; + right: 0; + top: 0; + z-index: 3; +} + + +//disable certain/choosen html elements +.HTMLelement_disabled { + pointer-events: none; + cursor: default; + color: rgba(255, 255, 255, 0.6) !important; +} + + +//hover over url turns CI blue +.url:hover { + color: $hrColor-DarkBlue; + cursor: pointer; +} + +.underline { + text-decoration: underline; +} + +.url { + color: $hrColor-Link; + @extend .underline; +} + +.cdk-global-scrollblock { + overflow-y: inherit; +} + +.cdk-overlay-pane { + width: auto !important; + min-width: 200px; + font-size: 14px; + max-width: calc(100vw - 100px) !important; //max-width of popups +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/3_vendor-dir.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/3_vendor-dir.scss new file mode 100644 index 0000000..3235233 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/3_vendor-dir.scss @@ -0,0 +1,10 @@ +/*==================================== + VENDOR'S-DIRECTORY +======================================*/ + +//vendor scss libary imports +@import './external-vendor/indigo-pink.scss'; + +//hr vendor styling imports +@import 'hr-devextreme-styling/3_dx-dir.scss'; +@import 'hr-material-styling/3_mat-dir.scss'; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/external-vendor/indigo-pink.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/external-vendor/indigo-pink.scss new file mode 100644 index 0000000..39e41f5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/external-vendor/indigo-pink.scss @@ -0,0 +1,2918 @@ +.mat-badge-content { + font-weight: 600; + font-size: 12px; + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-badge-small .mat-badge-content { + font-size: 9px +} + +.mat-badge-large .mat-badge-content { + font-size: 24px +} + +.mat-h1, +.mat-headline, +.mat-typography h1 { + font: 400 24px/32px Roboto, "Helvetica Neue", sans-serif; + margin: 0 0 16px +} + +.mat-h2, +.mat-title, +.mat-typography h2 { + font: 500 20px/32px Roboto, "Helvetica Neue", sans-serif; + margin: 0 0 16px +} + +.mat-h3, +.mat-subheading-2, +.mat-typography h3 { + font: 400 16px/28px Roboto, "Helvetica Neue", sans-serif; + margin: 0 0 16px +} + +.mat-h4, +.mat-subheading-1, +.mat-typography h4 { + font: 400 15px/24px Roboto, "Helvetica Neue", sans-serif; + margin: 0 0 16px +} + +.mat-h5, +.mat-typography h5 { + font: 400 11.62px/20px Roboto, "Helvetica Neue", sans-serif; + margin: 0 0 12px +} + +.mat-h6, +.mat-typography h6 { + font: 400 9.38px/20px Roboto, "Helvetica Neue", sans-serif; + margin: 0 0 12px +} + +.mat-body-2, +.mat-body-strong { + font: 500 14px/24px Roboto, "Helvetica Neue", sans-serif +} + +.mat-body, +.mat-body-1, +.mat-typography { + font: 400 14px/20px Roboto, "Helvetica Neue", sans-serif +} + +.mat-body p, +.mat-body-1 p, +.mat-typography p { + margin: 0 0 12px +} + +.mat-caption, +.mat-small { + font: 400 12px/20px Roboto, "Helvetica Neue", sans-serif +} + +.mat-display-4, +.mat-typography .mat-display-4 { + font: 300 112px/112px Roboto, "Helvetica Neue", sans-serif; + letter-spacing: -.05em; + margin: 0 0 56px +} + +.mat-display-3, +.mat-typography .mat-display-3 { + font: 400 56px/56px Roboto, "Helvetica Neue", sans-serif; + letter-spacing: -.02em; + margin: 0 0 64px +} + +.mat-display-2, +.mat-typography .mat-display-2 { + font: 400 45px/48px Roboto, "Helvetica Neue", sans-serif; + letter-spacing: -.005em; + margin: 0 0 64px +} + +.mat-display-1, +.mat-typography .mat-display-1 { + font: 400 34px/40px Roboto, "Helvetica Neue", sans-serif; + margin: 0 0 64px +} + +.mat-bottom-sheet-container { + font: 400 14px/20px Roboto, "Helvetica Neue", sans-serif +} + +.mat-button, +.mat-fab, +.mat-flat-button, +.mat-icon-button, +.mat-mini-fab, +.mat-raised-button, +.mat-stroked-button { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 14px; + font-weight: 500 +} + +.mat-button-toggle { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-card { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-card-title { + font-size: 24px; + font-weight: 500 +} + +.mat-card-header .mat-card-title { + font-size: 20px +} + +.mat-card-content, +.mat-card-subtitle { + font-size: 14px +} + +.mat-checkbox { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-checkbox-layout .mat-checkbox-label { + line-height: 24px +} + +.mat-chip { + font-size: 14px; + font-weight: 500 +} + +.mat-chip .mat-chip-remove.mat-icon, +.mat-chip .mat-chip-trailing-icon.mat-icon { + font-size: 18px +} + +.mat-table { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-header-cell { + font-size: 12px; + font-weight: 500 +} + +.mat-cell, +.mat-footer-cell { + font-size: 14px +} + +.mat-calendar { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-calendar-body { + font-size: 13px +} + +.mat-calendar-body-label, +.mat-calendar-period-button { + font-size: 14px; + font-weight: 500 +} + +.mat-calendar-table-header th { + font-size: 11px; + font-weight: 400 +} + +.mat-dialog-title { + font: 500 20px/32px Roboto, "Helvetica Neue", sans-serif +} + +.mat-expansion-panel-header { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 15px; + font-weight: 400 +} + +.mat-expansion-panel-content { + font: 400 14px/20px Roboto, "Helvetica Neue", sans-serif +} + +.mat-form-field { + font-size: inherit; + font-weight: 400; + line-height: 1.125; + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-form-field-wrapper { + padding-bottom: 1.34375em +} + +.mat-form-field-prefix .mat-icon, +.mat-form-field-suffix .mat-icon { + font-size: 150%; + line-height: 1.125 +} + +.mat-form-field-prefix .mat-icon-button, +.mat-form-field-suffix .mat-icon-button { + height: 1.5em; + width: 1.5em +} + +.mat-form-field-prefix .mat-icon-button .mat-icon, +.mat-form-field-suffix .mat-icon-button .mat-icon { + height: 1.125em; + line-height: 1.125 +} + +.mat-form-field-infix { + padding: .5em 0; + border-top: .84375em solid transparent +} + +.mat-form-field-can-float .mat-input-server:focus+.mat-form-field-label-wrapper .mat-form-field-label, +.mat-form-field-can-float.mat-form-field-should-float .mat-form-field-label { + transform: translateY(-1.34375em) scale(.75); + width: 133.33333% +} + +.mat-form-field-can-float .mat-input-server[label]:not(:label-shown)+.mat-form-field-label-wrapper .mat-form-field-label { + transform: translateY(-1.34374em) scale(.75); + width: 133.33334% +} + +.mat-form-field-label-wrapper { + top: -.84375em; + padding-top: .84375em +} + +.mat-form-field-label { + top: 1.34375em +} + +.mat-form-field-underline { + bottom: 1.34375em +} + +.mat-form-field-subscript-wrapper { + font-size: 75%; + margin-top: .66667em; + top: calc(100% - 1.79167em) +} + +.mat-form-field-appearance-legacy .mat-form-field-wrapper { + padding-bottom: 1.25em +} + +.mat-form-field-appearance-legacy .mat-form-field-infix { + padding: .4375em 0 +} + +.mat-form-field-appearance-legacy.mat-form-field-can-float .mat-input-server:focus+.mat-form-field-label-wrapper .mat-form-field-label, +.mat-form-field-appearance-legacy.mat-form-field-can-float.mat-form-field-should-float .mat-form-field-label { + transform: translateY(-1.28125em) scale(.75) perspective(100px) translateZ(.001px); + -ms-transform: translateY(-1.28125em) scale(.75); + width: 133.33333% +} + +.mat-form-field-appearance-legacy.mat-form-field-can-float .mat-form-field-autofill-control:-webkit-autofill+.mat-form-field-label-wrapper .mat-form-field-label { + transform: translateY(-1.28125em) scale(.75) perspective(100px) translateZ(.00101px); + -ms-transform: translateY(-1.28124em) scale(.75); + width: 133.33334% +} + +.mat-form-field-appearance-legacy.mat-form-field-can-float .mat-input-server[label]:not(:label-shown)+.mat-form-field-label-wrapper .mat-form-field-label { + transform: translateY(-1.28125em) scale(.75) perspective(100px) translateZ(.00102px); + -ms-transform: translateY(-1.28123em) scale(.75); + width: 133.33335% +} + +.mat-form-field-appearance-legacy .mat-form-field-label { + top: 1.28125em +} + +.mat-form-field-appearance-legacy .mat-form-field-underline { + bottom: 1.25em +} + +.mat-form-field-appearance-legacy .mat-form-field-subscript-wrapper { + margin-top: .54167em; + top: calc(100% - 1.66667em) +} + +@media print { + + .mat-form-field-appearance-legacy.mat-form-field-can-float .mat-input-server:focus+.mat-form-field-label-wrapper .mat-form-field-label, + .mat-form-field-appearance-legacy.mat-form-field-can-float.mat-form-field-should-float .mat-form-field-label { + transform: translateY(-1.28122em) scale(.75) + } + + .mat-form-field-appearance-legacy.mat-form-field-can-float .mat-form-field-autofill-control:-webkit-autofill+.mat-form-field-label-wrapper .mat-form-field-label { + transform: translateY(-1.28121em) scale(.75) + } + + .mat-form-field-appearance-legacy.mat-form-field-can-float .mat-input-server[label]:not(:label-shown)+.mat-form-field-label-wrapper .mat-form-field-label { + transform: translateY(-1.2812em) scale(.75) + } +} + +.mat-form-field-appearance-fill .mat-form-field-infix { + padding: .25em 0 .75em 0 +} + +.mat-form-field-appearance-fill .mat-form-field-label { + top: 1.09375em; + margin-top: -.5em +} + +.mat-form-field-appearance-fill.mat-form-field-can-float .mat-input-server:focus+.mat-form-field-label-wrapper .mat-form-field-label, +.mat-form-field-appearance-fill.mat-form-field-can-float.mat-form-field-should-float .mat-form-field-label { + transform: translateY(-.59375em) scale(.75); + width: 133.33333% +} + +.mat-form-field-appearance-fill.mat-form-field-can-float .mat-input-server[label]:not(:label-shown)+.mat-form-field-label-wrapper .mat-form-field-label { + transform: translateY(-.59374em) scale(.75); + width: 133.33334% +} + +.mat-form-field-appearance-outline .mat-form-field-infix { + padding: 1em 0 1em 0 +} + +.mat-form-field-appearance-outline .mat-form-field-label { + top: 1.84375em; + margin-top: -.25em +} + +.mat-form-field-appearance-outline.mat-form-field-can-float .mat-input-server:focus+.mat-form-field-label-wrapper .mat-form-field-label, +.mat-form-field-appearance-outline.mat-form-field-can-float.mat-form-field-should-float .mat-form-field-label { + transform: translateY(-1.59375em) scale(.75); + width: 133.33333% +} + +.mat-form-field-appearance-outline.mat-form-field-can-float .mat-input-server[label]:not(:label-shown)+.mat-form-field-label-wrapper .mat-form-field-label { + transform: translateY(-1.59374em) scale(.75); + width: 133.33334% +} + +.mat-grid-tile-footer, +.mat-grid-tile-header { + font-size: 14px +} + +.mat-grid-tile-footer .mat-line, +.mat-grid-tile-header .mat-line { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + box-sizing: border-box +} + +.mat-grid-tile-footer .mat-line:nth-child(n+2), +.mat-grid-tile-header .mat-line:nth-child(n+2) { + font-size: 12px +} + +input.mat-input-element { + margin-top: -.0625em +} + +.mat-menu-item { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 14px; + font-weight: 400 +} + +.mat-paginator, +.mat-paginator-page-size .mat-select-trigger { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 12px +} + +.mat-radio-button { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-select { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-select-trigger { + height: 1.125em +} + +.mat-slide-toggle-content { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-slider-thumb-label-text { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 12px; + font-weight: 500 +} + +.mat-stepper-horizontal, +.mat-stepper-vertical { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-step-label { + font-size: 14px; + font-weight: 400 +} + +.mat-step-sub-label-error { + font-weight: 400 +} + +.mat-step-label-error { + font-size: 14px +} + +.mat-step-label-selected { + font-size: 14px; + font-weight: 500 +} + +.mat-tab-group { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-tab-label, +.mat-tab-link { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 14px; + font-weight: 500 +} + +.mat-toolbar, +.mat-toolbar h1, +.mat-toolbar h2, +.mat-toolbar h3, +.mat-toolbar h4, +.mat-toolbar h5, +.mat-toolbar h6 { + font: 500 20px/32px Roboto, "Helvetica Neue", sans-serif; + margin: 0 +} + +.mat-tooltip { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 10px; + padding-top: 6px; + padding-bottom: 6px +} + +.mat-tooltip-handset { + font-size: 14px; + padding-top: 8px; + padding-bottom: 8px +} + +.mat-list-item { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-list-option { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-list-base .mat-list-item { + font-size: 16px +} + +.mat-list-base .mat-list-item .mat-line { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + box-sizing: border-box +} + +.mat-list-base .mat-list-item .mat-line:nth-child(n+2) { + font-size: 14px +} + +.mat-list-base .mat-list-option { + font-size: 16px +} + +.mat-list-base .mat-list-option .mat-line { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + box-sizing: border-box +} + +.mat-list-base .mat-list-option .mat-line:nth-child(n+2) { + font-size: 14px +} + +.mat-list-base .mat-subheader { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 14px; + font-weight: 500 +} + +.mat-list-base[dense] .mat-list-item { + font-size: 12px +} + +.mat-list-base[dense] .mat-list-item .mat-line { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + box-sizing: border-box +} + +.mat-list-base[dense] .mat-list-item .mat-line:nth-child(n+2) { + font-size: 12px +} + +.mat-list-base[dense] .mat-list-option { + font-size: 12px +} + +.mat-list-base[dense] .mat-list-option .mat-line { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + box-sizing: border-box +} + +.mat-list-base[dense] .mat-list-option .mat-line:nth-child(n+2) { + font-size: 12px +} + +.mat-list-base[dense] .mat-subheader { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 12px; + font-weight: 500 +} + +.mat-option { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 16px +} + +.mat-optgroup-label { + font: 500 14px/24px Roboto, "Helvetica Neue", sans-serif +} + +.mat-simple-snackbar { + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 14px +} + +.mat-simple-snackbar-action { + line-height: 1; + font-family: inherit; + font-size: inherit; + font-weight: 500 +} + +.mat-tree { + font-family: Roboto, "Helvetica Neue", sans-serif +} + +.mat-nested-tree-node, +.mat-tree-node { + font-weight: 400; + font-size: 14px +} + +.mat-ripple { + overflow: hidden; + position: relative +} + +.mat-ripple.mat-ripple-unbounded { + overflow: visible +} + +.mat-ripple-element { + position: absolute; + border-radius: 50%; + pointer-events: none; + transition: opacity, transform 0s cubic-bezier(0, 0, .2, 1); + transform: scale(0) +} + +@media (-ms-high-contrast:active) { + .mat-ripple-element { + display: none + } +} + +.cdk-visually-hidden { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + outline: 0; + -webkit-appearance: none; + -moz-appearance: none +} + +.cdk-global-overlay-wrapper, +.cdk-overlay-container { + pointer-events: none; + top: 0; + left: 0; + height: 100%; + width: 100% +} + +.cdk-overlay-container { + position: fixed; + z-index: 1000 +} + +.cdk-overlay-container:empty { + display: none +} + +.cdk-global-overlay-wrapper { + display: flex; + position: absolute; + z-index: 1000 +} + +.cdk-overlay-pane { + position: absolute; + pointer-events: auto; + box-sizing: border-box; + z-index: 1000; + display: flex; + max-width: 100%; + max-height: 100% +} + +.cdk-overlay-backdrop { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 1000; + pointer-events: auto; + -webkit-tap-highlight-color: transparent; + transition: opacity .4s cubic-bezier(.25, .8, .25, 1); + opacity: 0 +} + +.cdk-overlay-backdrop.cdk-overlay-backdrop-showing { + opacity: 1 +} + +@media screen and (-ms-high-contrast:active) { + .cdk-overlay-backdrop.cdk-overlay-backdrop-showing { + opacity: .6 + } +} + +.cdk-overlay-dark-backdrop { + background: rgba(0, 0, 0, .32) +} + +.cdk-overlay-transparent-backdrop, +.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing { + opacity: 0 +} + +.cdk-overlay-connected-position-bounding-box { + position: absolute; + z-index: 1000; + display: flex; + flex-direction: column; + min-width: 1px; + min-height: 1px +} + +.cdk-global-scrollblock { + position: fixed; + width: 100%; + overflow-y: scroll +} + +@keyframes cdk-text-field-autofill-start { + /*!*/ +} + +@keyframes cdk-text-field-autofill-end { + /*!*/ +} + +.cdk-text-field-autofill-monitored:-webkit-autofill { + animation-name: cdk-text-field-autofill-start +} + +.cdk-text-field-autofill-monitored:not(:-webkit-autofill) { + animation-name: cdk-text-field-autofill-end +} + +textarea.cdk-textarea-autosize { + resize: none +} + +textarea.cdk-textarea-autosize-measuring { + height: auto !important; + overflow: hidden !important; + padding: 2px 0 !important; + box-sizing: content-box !important +} + +.mat-ripple-element { + background-color: rgba(0, 0, 0, .1) +} + +.mat-option { + color: rgba(0, 0, 0, .87) +} + +.mat-option:focus:not(.mat-option-disabled), +.mat-option:hover:not(.mat-option-disabled) { + background: rgba(0, 0, 0, .04) +} + +.mat-option.mat-selected:not(.mat-option-multiple):not(.mat-option-disabled) { + background: rgba(0, 0, 0, .04) +} + +.mat-option.mat-active { + background: rgba(0, 0, 0, .04); + color: rgba(0, 0, 0, .87) +} + +.mat-option.mat-option-disabled { + color: rgba(0, 0, 0, .38) +} + +.mat-primary .mat-option.mat-selected:not(.mat-option-disabled) { + color: #78b7e5 +} + +.mat-accent .mat-option.mat-selected:not(.mat-option-disabled) { + color: #78b7e5 +} + +.mat-warn .mat-option.mat-selected:not(.mat-option-disabled) { + color: #f44336 +} + +.mat-optgroup-label { + color: rgba(0, 0, 0, .54) +} + +.mat-optgroup-disabled .mat-optgroup-label { + color: rgba(0, 0, 0, .38) +} + +.mat-pseudo-checkbox { + color: rgba(0, 0, 0, .54) +} + +.mat-pseudo-checkbox::after { + color: #fafafa +} + +.mat-pseudo-checkbox-disabled { + color: #b0b0b0 +} + +.mat-accent .mat-pseudo-checkbox-checked, +.mat-accent .mat-pseudo-checkbox-indeterminate, +.mat-pseudo-checkbox-checked, +.mat-pseudo-checkbox-indeterminate { + background: #78b7e5 +} + +.mat-primary .mat-pseudo-checkbox-checked, +.mat-primary .mat-pseudo-checkbox-indeterminate { + background: #78b7e5 +} + +.mat-warn .mat-pseudo-checkbox-checked, +.mat-warn .mat-pseudo-checkbox-indeterminate { + background: #f44336 +} + +.mat-pseudo-checkbox-checked.mat-pseudo-checkbox-disabled, +.mat-pseudo-checkbox-indeterminate.mat-pseudo-checkbox-disabled { + background: #b0b0b0 +} + +.mat-elevation-z0 { + box-shadow: 0 0 0 0 rgba(0, 0, 0, .2), 0 0 0 0 rgba(0, 0, 0, .14), 0 0 0 0 rgba(0, 0, 0, .12) +} + +.mat-elevation-z1 { + box-shadow: 0 2px 1px -1px rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .14), 0 1px 3px 0 rgba(0, 0, 0, .12) +} + +.mat-elevation-z2 { + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12) +} + +.mat-elevation-z3 { + box-shadow: 0 3px 3px -2px rgba(0, 0, 0, .2), 0 3px 4px 0 rgba(0, 0, 0, .14), 0 1px 8px 0 rgba(0, 0, 0, .12) +} + +.mat-elevation-z4 { + box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12) +} + +.mat-elevation-z5 { + box-shadow: 0 3px 5px -1px rgba(0, 0, 0, .2), 0 5px 8px 0 rgba(0, 0, 0, .14), 0 1px 14px 0 rgba(0, 0, 0, .12) +} + +.mat-elevation-z6 { + box-shadow: 0 3px 5px -1px rgba(0, 0, 0, .2), 0 6px 10px 0 rgba(0, 0, 0, .14), 0 1px 18px 0 rgba(0, 0, 0, .12) +} + +.mat-elevation-z7 { + box-shadow: 0 4px 5px -2px rgba(0, 0, 0, .2), 0 7px 10px 1px rgba(0, 0, 0, .14), 0 2px 16px 1px rgba(0, 0, 0, .12) +} + +.mat-elevation-z8 { + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12) +} + +.mat-elevation-z9 { + box-shadow: 0 5px 6px -3px rgba(0, 0, 0, .2), 0 9px 12px 1px rgba(0, 0, 0, .14), 0 3px 16px 2px rgba(0, 0, 0, .12) +} + +.mat-elevation-z10 { + box-shadow: 0 6px 6px -3px rgba(0, 0, 0, .2), 0 10px 14px 1px rgba(0, 0, 0, .14), 0 4px 18px 3px rgba(0, 0, 0, .12) +} + +.mat-elevation-z11 { + box-shadow: 0 6px 7px -4px rgba(0, 0, 0, .2), 0 11px 15px 1px rgba(0, 0, 0, .14), 0 4px 20px 3px rgba(0, 0, 0, .12) +} + +.mat-elevation-z12 { + box-shadow: 0 7px 8px -4px rgba(0, 0, 0, .2), 0 12px 17px 2px rgba(0, 0, 0, .14), 0 5px 22px 4px rgba(0, 0, 0, .12) +} + +.mat-elevation-z13 { + box-shadow: 0 7px 8px -4px rgba(0, 0, 0, .2), 0 13px 19px 2px rgba(0, 0, 0, .14), 0 5px 24px 4px rgba(0, 0, 0, .12) +} + +.mat-elevation-z14 { + box-shadow: 0 7px 9px -4px rgba(0, 0, 0, .2), 0 14px 21px 2px rgba(0, 0, 0, .14), 0 5px 26px 4px rgba(0, 0, 0, .12) +} + +.mat-elevation-z15 { + box-shadow: 0 8px 9px -5px rgba(0, 0, 0, .2), 0 15px 22px 2px rgba(0, 0, 0, .14), 0 6px 28px 5px rgba(0, 0, 0, .12) +} + +.mat-elevation-z16 { + box-shadow: 0 8px 10px -5px rgba(0, 0, 0, .2), 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12) +} + +.mat-elevation-z17 { + box-shadow: 0 8px 11px -5px rgba(0, 0, 0, .2), 0 17px 26px 2px rgba(0, 0, 0, .14), 0 6px 32px 5px rgba(0, 0, 0, .12) +} + +.mat-elevation-z18 { + box-shadow: 0 9px 11px -5px rgba(0, 0, 0, .2), 0 18px 28px 2px rgba(0, 0, 0, .14), 0 7px 34px 6px rgba(0, 0, 0, .12) +} + +.mat-elevation-z19 { + box-shadow: 0 9px 12px -6px rgba(0, 0, 0, .2), 0 19px 29px 2px rgba(0, 0, 0, .14), 0 7px 36px 6px rgba(0, 0, 0, .12) +} + +.mat-elevation-z20 { + box-shadow: 0 10px 13px -6px rgba(0, 0, 0, .2), 0 20px 31px 3px rgba(0, 0, 0, .14), 0 8px 38px 7px rgba(0, 0, 0, .12) +} + +.mat-elevation-z21 { + box-shadow: 0 10px 13px -6px rgba(0, 0, 0, .2), 0 21px 33px 3px rgba(0, 0, 0, .14), 0 8px 40px 7px rgba(0, 0, 0, .12) +} + +.mat-elevation-z22 { + box-shadow: 0 10px 14px -6px rgba(0, 0, 0, .2), 0 22px 35px 3px rgba(0, 0, 0, .14), 0 8px 42px 7px rgba(0, 0, 0, .12) +} + +.mat-elevation-z23 { + box-shadow: 0 11px 14px -7px rgba(0, 0, 0, .2), 0 23px 36px 3px rgba(0, 0, 0, .14), 0 9px 44px 8px rgba(0, 0, 0, .12) +} + +.mat-elevation-z24 { + box-shadow: 0 11px 15px -7px rgba(0, 0, 0, .2), 0 24px 38px 3px rgba(0, 0, 0, .14), 0 9px 46px 8px rgba(0, 0, 0, .12) +} + +.mat-app-background { + background-color: #fafafa; + color: rgba(0, 0, 0, .87) +} + +.mat-theme-loaded-marker { + display: none +} + +.mat-autocomplete-panel { + background: #fff; + color: rgba(0, 0, 0, .87) +} + +.mat-autocomplete-panel:not([class*=mat-elevation-z]) { + box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12) +} + +.mat-autocomplete-panel .mat-option.mat-selected:not(.mat-active):not(:hover) { + background: #fff +} + +.mat-autocomplete-panel .mat-option.mat-selected:not(.mat-active):not(:hover):not(.mat-option-disabled) { + color: rgba(0, 0, 0, .87) +} + +.mat-badge-content { + color: #fff; + background: #78b7e5 +} + +@media (-ms-high-contrast:active) { + .mat-badge-content { + outline: solid 1px; + border-radius: 0 + } +} + +.mat-badge-accent .mat-badge-content { + background: #78b7e5; + color: #fff +} + +.mat-badge-warn .mat-badge-content { + color: #fff; + background: #f44336 +} + +.mat-badge { + position: relative +} + +.mat-badge-hidden .mat-badge-content { + display: none +} + +.mat-badge-disabled .mat-badge-content { + background: #b9b9b9; + color: rgba(0, 0, 0, .38) +} + +.mat-badge-content { + position: absolute; + text-align: center; + display: inline-block; + border-radius: 50%; + transition: transform .2s ease-in-out; + transform: scale(.6); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + pointer-events: none +} + +.mat-badge-content._mat-animation-noopable, +.ng-animate-disabled .mat-badge-content { + transition: none +} + +.mat-badge-content.mat-badge-active { + transform: none +} + +.mat-badge-small .mat-badge-content { + width: 16px; + height: 16px; + line-height: 16px +} + +.mat-badge-small.mat-badge-above .mat-badge-content { + top: -8px +} + +.mat-badge-small.mat-badge-below .mat-badge-content { + bottom: -8px +} + +.mat-badge-small.mat-badge-before .mat-badge-content { + left: -16px +} + +[dir=rtl] .mat-badge-small.mat-badge-before .mat-badge-content { + left: auto; + right: -16px +} + +.mat-badge-small.mat-badge-after .mat-badge-content { + right: -16px +} + +[dir=rtl] .mat-badge-small.mat-badge-after .mat-badge-content { + right: auto; + left: -16px +} + +.mat-badge-small.mat-badge-overlap.mat-badge-before .mat-badge-content { + left: -8px +} + +[dir=rtl] .mat-badge-small.mat-badge-overlap.mat-badge-before .mat-badge-content { + left: auto; + right: -8px +} + +.mat-badge-small.mat-badge-overlap.mat-badge-after .mat-badge-content { + right: -8px +} + +[dir=rtl] .mat-badge-small.mat-badge-overlap.mat-badge-after .mat-badge-content { + right: auto; + left: -8px +} + +.mat-badge-medium .mat-badge-content { + width: 22px; + height: 22px; + line-height: 22px +} + +.mat-badge-medium.mat-badge-above .mat-badge-content { + top: -11px +} + +.mat-badge-medium.mat-badge-below .mat-badge-content { + bottom: -11px +} + +.mat-badge-medium.mat-badge-before .mat-badge-content { + left: -22px +} + +[dir=rtl] .mat-badge-medium.mat-badge-before .mat-badge-content { + left: auto; + right: -22px +} + +.mat-badge-medium.mat-badge-after .mat-badge-content { + right: -22px +} + +[dir=rtl] .mat-badge-medium.mat-badge-after .mat-badge-content { + right: auto; + left: -22px +} + +.mat-badge-medium.mat-badge-overlap.mat-badge-before .mat-badge-content { + left: -11px +} + +[dir=rtl] .mat-badge-medium.mat-badge-overlap.mat-badge-before .mat-badge-content { + left: auto; + right: -11px +} + +.mat-badge-medium.mat-badge-overlap.mat-badge-after .mat-badge-content { + right: -11px +} + +[dir=rtl] .mat-badge-medium.mat-badge-overlap.mat-badge-after .mat-badge-content { + right: auto; + left: -11px +} + +.mat-badge-large .mat-badge-content { + width: 28px; + height: 28px; + line-height: 28px +} + +.mat-badge-large.mat-badge-above .mat-badge-content { + top: -14px +} + +.mat-badge-large.mat-badge-below .mat-badge-content { + bottom: -14px +} + +.mat-badge-large.mat-badge-before .mat-badge-content { + left: -28px +} + +[dir=rtl] .mat-badge-large.mat-badge-before .mat-badge-content { + left: auto; + right: -28px +} + +.mat-badge-large.mat-badge-after .mat-badge-content { + right: -28px +} + +[dir=rtl] .mat-badge-large.mat-badge-after .mat-badge-content { + right: auto; + left: -28px +} + +.mat-badge-large.mat-badge-overlap.mat-badge-before .mat-badge-content { + left: -14px +} + +[dir=rtl] .mat-badge-large.mat-badge-overlap.mat-badge-before .mat-badge-content { + left: auto; + right: -14px +} + +.mat-badge-large.mat-badge-overlap.mat-badge-after .mat-badge-content { + right: -14px +} + +[dir=rtl] .mat-badge-large.mat-badge-overlap.mat-badge-after .mat-badge-content { + right: auto; + left: -14px +} + +.mat-bottom-sheet-container { + box-shadow: 0 8px 10px -5px rgba(0, 0, 0, .2), 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12); + background: #fff; + color: rgba(0, 0, 0, .87) +} + +.mat-button, +.mat-icon-button, +.mat-stroked-button { + color: inherit; + background: 0 0 +} + +.mat-button.mat-primary, +.mat-icon-button.mat-primary, +.mat-stroked-button.mat-primary { + color: #78b7e5 +} + +.mat-button.mat-accent, +.mat-icon-button.mat-accent, +.mat-stroked-button.mat-accent { + color: #78b7e5 +} + +.mat-button.mat-warn, +.mat-icon-button.mat-warn, +.mat-stroked-button.mat-warn { + color: #f44336 +} + +.mat-button.mat-accent[disabled], +.mat-button.mat-primary[disabled], +.mat-button.mat-warn[disabled], +.mat-button[disabled][disabled], +.mat-icon-button.mat-accent[disabled], +.mat-icon-button.mat-primary[disabled], +.mat-icon-button.mat-warn[disabled], +.mat-icon-button[disabled][disabled], +.mat-stroked-button.mat-accent[disabled], +.mat-stroked-button.mat-primary[disabled], +.mat-stroked-button.mat-warn[disabled], +.mat-stroked-button[disabled][disabled] { + color: rgba(0, 0, 0, .26) +} + +.mat-button.mat-primary .mat-button-focus-overlay, +.mat-icon-button.mat-primary .mat-button-focus-overlay, +.mat-stroked-button.mat-primary .mat-button-focus-overlay { + background-color: #78b7e5 +} + +.mat-button.mat-accent .mat-button-focus-overlay, +.mat-icon-button.mat-accent .mat-button-focus-overlay, +.mat-stroked-button.mat-accent .mat-button-focus-overlay { + background-color: #78b7e5 +} + +.mat-button.mat-warn .mat-button-focus-overlay, +.mat-icon-button.mat-warn .mat-button-focus-overlay, +.mat-stroked-button.mat-warn .mat-button-focus-overlay { + background-color: #f44336 +} + +.mat-button[disabled] .mat-button-focus-overlay, +.mat-icon-button[disabled] .mat-button-focus-overlay, +.mat-stroked-button[disabled] .mat-button-focus-overlay { + background-color: transparent +} + +.mat-button .mat-ripple-element, +.mat-icon-button .mat-ripple-element, +.mat-stroked-button .mat-ripple-element { + opacity: .1; + background-color: currentColor +} + +.mat-button-focus-overlay { + background: #000 +} + +.mat-stroked-button:not([disabled]) { + border-color: rgba(0, 0, 0, .12) +} + +.mat-fab, +.mat-flat-button, +.mat-mini-fab, +.mat-raised-button { + color: rgba(0, 0, 0, .87); + background-color: #fff +} + +.mat-fab.mat-primary, +.mat-flat-button.mat-primary, +.mat-mini-fab.mat-primary, +.mat-raised-button.mat-primary { + color: #fff +} + +.mat-fab.mat-accent, +.mat-flat-button.mat-accent, +.mat-mini-fab.mat-accent, +.mat-raised-button.mat-accent { + color: #fff +} + +.mat-fab.mat-warn, +.mat-flat-button.mat-warn, +.mat-mini-fab.mat-warn, +.mat-raised-button.mat-warn { + color: #fff +} + +.mat-fab.mat-accent[disabled], +.mat-fab.mat-primary[disabled], +.mat-fab.mat-warn[disabled], +.mat-fab[disabled][disabled], +.mat-flat-button.mat-accent[disabled], +.mat-flat-button.mat-primary[disabled], +.mat-flat-button.mat-warn[disabled], +.mat-flat-button[disabled][disabled], +.mat-mini-fab.mat-accent[disabled], +.mat-mini-fab.mat-primary[disabled], +.mat-mini-fab.mat-warn[disabled], +.mat-mini-fab[disabled][disabled], +.mat-raised-button.mat-accent[disabled], +.mat-raised-button.mat-primary[disabled], +.mat-raised-button.mat-warn[disabled], +.mat-raised-button[disabled][disabled] { + color: rgba(0, 0, 0, .26) +} + +.mat-fab.mat-primary, +.mat-flat-button.mat-primary, +.mat-mini-fab.mat-primary, +.mat-raised-button.mat-primary { + background-color: #78b7e5 +} + +.mat-fab.mat-accent, +.mat-flat-button.mat-accent, +.mat-mini-fab.mat-accent, +.mat-raised-button.mat-accent { + background-color: #78b7e5 +} + +.mat-fab.mat-warn, +.mat-flat-button.mat-warn, +.mat-mini-fab.mat-warn, +.mat-raised-button.mat-warn { + background-color: #f44336 +} + +.mat-fab.mat-accent[disabled], +.mat-fab.mat-primary[disabled], +.mat-fab.mat-warn[disabled], +.mat-fab[disabled][disabled], +.mat-flat-button.mat-accent[disabled], +.mat-flat-button.mat-primary[disabled], +.mat-flat-button.mat-warn[disabled], +.mat-flat-button[disabled][disabled], +.mat-mini-fab.mat-accent[disabled], +.mat-mini-fab.mat-primary[disabled], +.mat-mini-fab.mat-warn[disabled], +.mat-mini-fab[disabled][disabled], +.mat-raised-button.mat-accent[disabled], +.mat-raised-button.mat-primary[disabled], +.mat-raised-button.mat-warn[disabled], +.mat-raised-button[disabled][disabled] { + background-color: rgba(0, 0, 0, .12) +} + +.mat-fab.mat-primary .mat-ripple-element, +.mat-flat-button.mat-primary .mat-ripple-element, +.mat-mini-fab.mat-primary .mat-ripple-element, +.mat-raised-button.mat-primary .mat-ripple-element { + background-color: rgba(255, 255, 255, .1) +} + +.mat-fab.mat-accent .mat-ripple-element, +.mat-flat-button.mat-accent .mat-ripple-element, +.mat-mini-fab.mat-accent .mat-ripple-element, +.mat-raised-button.mat-accent .mat-ripple-element { + background-color: rgba(255, 255, 255, .1) +} + +.mat-fab.mat-warn .mat-ripple-element, +.mat-flat-button.mat-warn .mat-ripple-element, +.mat-mini-fab.mat-warn .mat-ripple-element, +.mat-raised-button.mat-warn .mat-ripple-element { + background-color: rgba(255, 255, 255, .1) +} + +.mat-flat-button:not([class*=mat-elevation-z]), +.mat-stroked-button:not([class*=mat-elevation-z]) { + box-shadow: 0 0 0 0 rgba(0, 0, 0, .2), 0 0 0 0 rgba(0, 0, 0, .14), 0 0 0 0 rgba(0, 0, 0, .12) +} + +.mat-raised-button:not([class*=mat-elevation-z]) { + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12) +} + +.mat-raised-button:not([disabled]):active:not([class*=mat-elevation-z]) { + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12) +} + +.mat-raised-button[disabled]:not([class*=mat-elevation-z]) { + box-shadow: 0 0 0 0 rgba(0, 0, 0, .2), 0 0 0 0 rgba(0, 0, 0, .14), 0 0 0 0 rgba(0, 0, 0, .12) +} + +.mat-fab:not([class*=mat-elevation-z]), +.mat-mini-fab:not([class*=mat-elevation-z]) { + box-shadow: 0 3px 5px -1px rgba(0, 0, 0, .2), 0 6px 10px 0 rgba(0, 0, 0, .14), 0 1px 18px 0 rgba(0, 0, 0, .12) +} + +.mat-fab:not([disabled]):active:not([class*=mat-elevation-z]), +.mat-mini-fab:not([disabled]):active:not([class*=mat-elevation-z]) { + box-shadow: 0 7px 8px -4px rgba(0, 0, 0, .2), 0 12px 17px 2px rgba(0, 0, 0, .14), 0 5px 22px 4px rgba(0, 0, 0, .12) +} + +.mat-fab[disabled]:not([class*=mat-elevation-z]), +.mat-mini-fab[disabled]:not([class*=mat-elevation-z]) { + box-shadow: 0 0 0 0 rgba(0, 0, 0, .2), 0 0 0 0 rgba(0, 0, 0, .14), 0 0 0 0 rgba(0, 0, 0, .12) +} + +.mat-button-toggle-group, +.mat-button-toggle-standalone { + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12) +} + +.mat-button-toggle-group-appearance-standard, +.mat-button-toggle-standalone.mat-button-toggle-appearance-standard { + box-shadow: none +} + +.mat-button-toggle { + color: rgba(0, 0, 0, .38) +} + +.mat-button-toggle .mat-button-toggle-focus-overlay { + background-color: rgba(0, 0, 0, .12) +} + +.mat-button-toggle-appearance-standard { + color: rgba(0, 0, 0, .87); + background: #fff +} + +.mat-button-toggle-appearance-standard .mat-button-toggle-focus-overlay { + background-color: #000 +} + +.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle { + border-left: solid 1px rgba(0, 0, 0, .12) +} + +[dir=rtl] .mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle { + border-left: none; + border-right: solid 1px rgba(0, 0, 0, .12) +} + +.mat-button-toggle-group-appearance-standard.mat-button-toggle-vertical .mat-button-toggle+.mat-button-toggle { + border-left: none; + border-right: none; + border-top: solid 1px rgba(0, 0, 0, .12) +} + +.mat-button-toggle-checked { + background-color: #e0e0e0; + color: rgba(0, 0, 0, .54) +} + +.mat-button-toggle-checked.mat-button-toggle-appearance-standard { + color: rgba(0, 0, 0, .87) +} + +.mat-button-toggle-disabled { + color: rgba(0, 0, 0, .26); + background-color: #eee +} + +.mat-button-toggle-disabled.mat-button-toggle-appearance-standard { + background: #fff +} + +.mat-button-toggle-disabled.mat-button-toggle-checked { + background-color: #bdbdbd +} + +.mat-button-toggle-group-appearance-standard, +.mat-button-toggle-standalone.mat-button-toggle-appearance-standard { + border: solid 1px rgba(0, 0, 0, .12) +} + +.mat-card { + background: #fff; + color: rgba(0, 0, 0, .87) +} + +.mat-card:not([class*=mat-elevation-z]) { + box-shadow: 0 2px 1px -1px rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .14), 0 1px 3px 0 rgba(0, 0, 0, .12) +} + +.mat-card.mat-card-flat:not([class*=mat-elevation-z]) { + box-shadow: 0 0 0 0 rgba(0, 0, 0, .2), 0 0 0 0 rgba(0, 0, 0, .14), 0 0 0 0 rgba(0, 0, 0, .12) +} + +.mat-card-subtitle { + color: rgba(0, 0, 0, .54) +} + +.mat-checkbox-frame { + border-color: rgba(0, 0, 0, .54) +} + +.mat-checkbox-checkmark { + fill: #fafafa +} + +.mat-checkbox-checkmark-path { + stroke: #fafafa !important +} + +@media (-ms-high-contrast:black-on-white) { + .mat-checkbox-checkmark-path { + stroke: #000 !important + } +} + +.mat-checkbox-mixedmark { + background-color: #fafafa +} + +.mat-checkbox-checked.mat-primary .mat-checkbox-background, +.mat-checkbox-indeterminate.mat-primary .mat-checkbox-background { + background-color: #78b7e5 +} + +.mat-checkbox-checked.mat-accent .mat-checkbox-background, +.mat-checkbox-indeterminate.mat-accent .mat-checkbox-background { + background-color: #78b7e5 +} + +.mat-checkbox-checked.mat-warn .mat-checkbox-background, +.mat-checkbox-indeterminate.mat-warn .mat-checkbox-background { + background-color: #f44336 +} + +.mat-checkbox-disabled.mat-checkbox-checked .mat-checkbox-background, +.mat-checkbox-disabled.mat-checkbox-indeterminate .mat-checkbox-background { + background-color: #b0b0b0 +} + +.mat-checkbox-disabled:not(.mat-checkbox-checked) .mat-checkbox-frame { + border-color: #b0b0b0 +} + +.mat-checkbox-disabled .mat-checkbox-label { + color: rgba(0, 0, 0, .54) +} + +@media (-ms-high-contrast:active) { + .mat-checkbox-disabled { + opacity: .5 + } +} + +@media (-ms-high-contrast:active) { + .mat-checkbox-background { + background: 0 0 + } +} + +.mat-checkbox .mat-ripple-element { + background-color: #000 +} + +.mat-checkbox-checked:not(.mat-checkbox-disabled).mat-primary .mat-ripple-element, +.mat-checkbox:active:not(.mat-checkbox-disabled).mat-primary .mat-ripple-element { + background: #78b7e5 +} + +.mat-checkbox-checked:not(.mat-checkbox-disabled).mat-accent .mat-ripple-element, +.mat-checkbox:active:not(.mat-checkbox-disabled).mat-accent .mat-ripple-element { + background: #78b7e5 +} + +.mat-checkbox-checked:not(.mat-checkbox-disabled).mat-warn .mat-ripple-element, +.mat-checkbox:active:not(.mat-checkbox-disabled).mat-warn .mat-ripple-element { + background: #f44336 +} + +.mat-chip.mat-standard-chip { + background-color: #e0e0e0; + color: rgba(0, 0, 0, .87) +} + +.mat-chip.mat-standard-chip .mat-chip-remove { + color: rgba(0, 0, 0, .87); + opacity: .4 +} + +.mat-chip.mat-standard-chip:not(.mat-chip-disabled):active { + box-shadow: 0 3px 3px -2px rgba(0, 0, 0, .2), 0 3px 4px 0 rgba(0, 0, 0, .14), 0 1px 8px 0 rgba(0, 0, 0, .12) +} + +.mat-chip.mat-standard-chip:not(.mat-chip-disabled) .mat-chip-remove:hover { + opacity: .54 +} + +.mat-chip.mat-standard-chip.mat-chip-disabled { + opacity: .4 +} + +.mat-chip.mat-standard-chip::after { + background: #000 +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary { + background-color: #78b7e5; + color: #fff +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary .mat-chip-remove { + color: #fff; + opacity: .4 +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary .mat-ripple-element { + background: rgba(255, 255, 255, .1) +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-warn { + background-color: #f44336; + color: #fff +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-warn .mat-chip-remove { + color: #fff; + opacity: .4 +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-warn .mat-ripple-element { + background: rgba(255, 255, 255, .1) +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-accent { + background-color: #78b7e5; + color: #fff +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-accent .mat-chip-remove { + color: #fff; + opacity: .4 +} + +.mat-chip.mat-standard-chip.mat-chip-selected.mat-accent .mat-ripple-element { + background: rgba(255, 255, 255, .1) +} + +.mat-table { + background: #fff +} + +.mat-table tbody, +.mat-table tfoot, +.mat-table thead, +.mat-table-sticky, +[mat-footer-row], +[mat-header-row], +[mat-row], +mat-footer-row, +mat-header-row, +mat-row { + background: inherit +} + +mat-footer-row, +mat-header-row, +mat-row, +td.mat-cell, +td.mat-footer-cell, +th.mat-header-cell { + border-bottom-color: rgba(0, 0, 0, .12) +} + +.mat-header-cell { + color: rgba(0, 0, 0, .54) +} + +.mat-cell, +.mat-footer-cell { + color: rgba(0, 0, 0, .87) +} + +.mat-calendar-arrow { + border-top-color: rgba(0, 0, 0, .54) +} + +.mat-datepicker-content .mat-calendar-next-button, +.mat-datepicker-content .mat-calendar-previous-button, +.mat-datepicker-toggle { + color: rgba(0, 0, 0, .54) +} + +.mat-calendar-table-header { + color: rgba(0, 0, 0, .38) +} + +.mat-calendar-table-header-divider::after { + background: rgba(0, 0, 0, .12) +} + +.mat-calendar-body-label { + color: rgba(0, 0, 0, .54) +} + +.mat-calendar-body-cell-content { + color: rgba(0, 0, 0, .87); + border-color: transparent +} + +.mat-calendar-body-disabled>.mat-calendar-body-cell-content:not(.mat-calendar-body-selected) { + color: rgba(0, 0, 0, .38) +} + +.cdk-keyboard-focused .mat-calendar-body-active>.mat-calendar-body-cell-content:not(.mat-calendar-body-selected), +.cdk-program-focused .mat-calendar-body-active>.mat-calendar-body-cell-content:not(.mat-calendar-body-selected), +.mat-calendar-body-cell:not(.mat-calendar-body-disabled):hover>.mat-calendar-body-cell-content:not(.mat-calendar-body-selected) { + background-color: rgba(0, 0, 0, .04) +} + +.mat-calendar-body-today:not(.mat-calendar-body-selected) { + border-color: rgba(0, 0, 0, .38) +} + +.mat-calendar-body-disabled>.mat-calendar-body-today:not(.mat-calendar-body-selected) { + border-color: rgba(0, 0, 0, .18) +} + +.mat-calendar-body-selected { + background-color: #78b7e5; + color: #fff +} + +.mat-calendar-body-disabled>.mat-calendar-body-selected { + background-color: rgba(120, 183, 229, .4) +} + +.mat-calendar-body-today.mat-calendar-body-selected { + box-shadow: inset 0 0 0 1px #fff +} + +.mat-datepicker-content { + box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12); + background-color: #fff; + color: rgba(0, 0, 0, .87) +} + +.mat-datepicker-content.mat-accent .mat-calendar-body-selected { + background-color: #78b7e5; + color: #fff +} + +.mat-datepicker-content.mat-accent .mat-calendar-body-disabled>.mat-calendar-body-selected { + background-color: rgba(255, 64, 129, .4) +} + +.mat-datepicker-content.mat-accent .mat-calendar-body-today.mat-calendar-body-selected { + box-shadow: inset 0 0 0 1px #fff +} + +.mat-datepicker-content.mat-warn .mat-calendar-body-selected { + background-color: #f44336; + color: #fff +} + +.mat-datepicker-content.mat-warn .mat-calendar-body-disabled>.mat-calendar-body-selected { + background-color: rgba(244, 67, 54, .4) +} + +.mat-datepicker-content.mat-warn .mat-calendar-body-today.mat-calendar-body-selected { + box-shadow: inset 0 0 0 1px #fff +} + +.mat-datepicker-content-touch { + box-shadow: 0 0 0 0 rgba(0, 0, 0, .2), 0 0 0 0 rgba(0, 0, 0, .14), 0 0 0 0 rgba(0, 0, 0, .12) +} + +.mat-datepicker-toggle-active { + color: #78b7e5 +} + +.mat-datepicker-toggle-active.mat-accent { + color: #78b7e5 +} + +.mat-datepicker-toggle-active.mat-warn { + color: #f44336 +} + +.mat-dialog-container { + box-shadow: 0 11px 15px -7px rgba(0, 0, 0, .2), 0 24px 38px 3px rgba(0, 0, 0, .14), 0 9px 46px 8px rgba(0, 0, 0, .12); + background: #fff; + color: rgba(0, 0, 0, .87) +} + +.mat-divider { + border-top-color: rgba(0, 0, 0, .12) +} + +.mat-divider-vertical { + border-right-color: rgba(0, 0, 0, .12) +} + +.mat-expansion-panel { + background: #fff; + color: rgba(0, 0, 0, .87) +} + +.mat-expansion-panel:not([class*=mat-elevation-z]) { + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12) +} + +.mat-action-row { + border-top-color: rgba(0, 0, 0, .12) +} + +.mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]).cdk-keyboard-focused, +.mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]).cdk-program-focused, +.mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover { + background: rgba(0, 0, 0, .04) +} + +@media (hover:none) { + .mat-expansion-panel:not(.mat-expanded):not([aria-disabled=true]) .mat-expansion-panel-header:hover { + background: #fff + } +} + +.mat-expansion-panel-header-title { + color: rgba(0, 0, 0, .87) +} + +.mat-expansion-indicator::after, +.mat-expansion-panel-header-description { + color: rgba(0, 0, 0, .54) +} + +.mat-expansion-panel-header[aria-disabled=true] { + color: rgba(0, 0, 0, .26) +} + +.mat-expansion-panel-header[aria-disabled=true] .mat-expansion-panel-header-description, +.mat-expansion-panel-header[aria-disabled=true] .mat-expansion-panel-header-title { + color: inherit +} + +.mat-form-field-label { + color: rgba(0, 0, 0, .6) +} + +.mat-hint { + color: rgba(0, 0, 0, .6) +} + +.mat-form-field.mat-focused .mat-form-field-label { + color: #78b7e5 +} + +.mat-form-field.mat-focused .mat-form-field-label.mat-accent { + color: #78b7e5 +} + +.mat-form-field.mat-focused .mat-form-field-label.mat-warn { + color: #f44336 +} + +.mat-focused .mat-form-field-required-marker { + color: #78b7e5 +} + +.mat-form-field-ripple { + background-color: rgba(0, 0, 0, .87) +} + +.mat-form-field.mat-focused .mat-form-field-ripple { + background-color: #78b7e5 +} + +.mat-form-field.mat-focused .mat-form-field-ripple.mat-accent { + background-color: #78b7e5 +} + +.mat-form-field.mat-focused .mat-form-field-ripple.mat-warn { + background-color: #f44336 +} + +.mat-form-field-type-mat-native-select.mat-focused:not(.mat-form-field-invalid) .mat-form-field-infix::after { + color: #78b7e5 +} + +.mat-form-field-type-mat-native-select.mat-focused:not(.mat-form-field-invalid).mat-accent .mat-form-field-infix::after { + color: #78b7e5 +} + +.mat-form-field-type-mat-native-select.mat-focused:not(.mat-form-field-invalid).mat-warn .mat-form-field-infix::after { + color: #f44336 +} + +.mat-form-field.mat-form-field-invalid .mat-form-field-label { + color: #f44336 +} + +.mat-form-field.mat-form-field-invalid .mat-form-field-label .mat-form-field-required-marker, +.mat-form-field.mat-form-field-invalid .mat-form-field-label.mat-accent { + color: #f44336 +} + +.mat-form-field.mat-form-field-invalid .mat-form-field-ripple, +.mat-form-field.mat-form-field-invalid .mat-form-field-ripple.mat-accent { + background-color: #f44336 +} + +.mat-error { + color: #f44336 +} + +.mat-form-field-appearance-legacy .mat-form-field-label { + color: rgba(0, 0, 0, .54) +} + +.mat-form-field-appearance-legacy .mat-hint { + color: rgba(0, 0, 0, .54) +} + +.mat-form-field-appearance-legacy .mat-form-field-underline { + background-color: rgba(0, 0, 0, .42) +} + +.mat-form-field-appearance-legacy.mat-form-field-disabled .mat-form-field-underline { + background-image: linear-gradient(to right, rgba(0, 0, 0, .42) 0, rgba(0, 0, 0, .42) 33%, transparent 0); + background-size: 4px 100%; + background-repeat: repeat-x +} + +.mat-form-field-appearance-standard .mat-form-field-underline { + background-color: rgba(0, 0, 0, .42) +} + +.mat-form-field-appearance-standard.mat-form-field-disabled .mat-form-field-underline { + background-image: linear-gradient(to right, rgba(0, 0, 0, .42) 0, rgba(0, 0, 0, .42) 33%, transparent 0); + background-size: 4px 100%; + background-repeat: repeat-x +} + +.mat-form-field-appearance-fill .mat-form-field-flex { + background-color: rgba(0, 0, 0, .04) +} + +.mat-form-field-appearance-fill.mat-form-field-disabled .mat-form-field-flex { + background-color: rgba(0, 0, 0, .02) +} + +.mat-form-field-appearance-fill .mat-form-field-underline::before { + background-color: rgba(0, 0, 0, .42) +} + +.mat-form-field-appearance-fill.mat-form-field-disabled .mat-form-field-label { + color: rgba(0, 0, 0, .38) +} + +.mat-form-field-appearance-fill.mat-form-field-disabled .mat-form-field-underline::before { + background-color: transparent +} + +.mat-form-field-appearance-outline .mat-form-field-outline { + color: rgba(0, 0, 0, .12) +} + +.mat-form-field-appearance-outline .mat-form-field-outline-thick { + color: rgba(0, 0, 0, .87) +} + +.mat-form-field-appearance-outline.mat-focused .mat-form-field-outline-thick { + color: #78b7e5 +} + +.mat-form-field-appearance-outline.mat-focused.mat-accent .mat-form-field-outline-thick { + color: #78b7e5 +} + +.mat-form-field-appearance-outline.mat-focused.mat-warn .mat-form-field-outline-thick { + color: #f44336 +} + +.mat-form-field-appearance-outline.mat-form-field-invalid.mat-form-field-invalid .mat-form-field-outline-thick { + color: #f44336 +} + +.mat-form-field-appearance-outline.mat-form-field-disabled .mat-form-field-label { + color: rgba(0, 0, 0, .38) +} + +.mat-form-field-appearance-outline.mat-form-field-disabled .mat-form-field-outline { + color: rgba(0, 0, 0, .06) +} + +.mat-icon.mat-primary { + color: #78b7e5 +} + +.mat-icon.mat-accent { + color: #78b7e5 +} + +.mat-icon.mat-warn { + color: #f44336 +} + +.mat-form-field-type-mat-native-select .mat-form-field-infix::after { + color: rgba(0, 0, 0, .54) +} + +.mat-form-field-type-mat-native-select.mat-form-field-disabled .mat-form-field-infix::after, +.mat-input-element:disabled { + color: rgba(0, 0, 0, .38) +} + +.mat-input-element { + caret-color: #78b7e5 +} + +.mat-input-element::placeholder { + color: rgba(0, 0, 0, .42) +} + +.mat-input-element::-moz-placeholder { + color: rgba(0, 0, 0, .42) +} + +.mat-input-element::-webkit-input-placeholder { + color: rgba(0, 0, 0, .42) +} + +.mat-input-element:-ms-input-placeholder { + color: rgba(0, 0, 0, .42) +} + +.mat-accent .mat-input-element { + caret-color: #78b7e5 +} + +.mat-form-field-invalid .mat-input-element, +.mat-warn .mat-input-element { + caret-color: #f44336 +} + +.mat-form-field-type-mat-native-select.mat-form-field-invalid .mat-form-field-infix::after { + color: #f44336 +} + +.mat-list-base .mat-list-item { + color: rgba(0, 0, 0, .87) +} + +.mat-list-base .mat-list-option { + color: rgba(0, 0, 0, .87) +} + +.mat-list-base .mat-subheader { + color: rgba(0, 0, 0, .54) +} + +.mat-list-item-disabled { + background-color: #eee +} + +.mat-action-list .mat-list-item:focus, +.mat-action-list .mat-list-item:hover, +.mat-list-option:focus, +.mat-list-option:hover, +.mat-nav-list .mat-list-item:focus, +.mat-nav-list .mat-list-item:hover { + background: rgba(0, 0, 0, .04) +} + +.mat-menu-panel { + background: #fff +} + +.mat-menu-panel:not([class*=mat-elevation-z]) { + box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12) +} + +.mat-menu-item { + background: 0 0; + color: rgba(0, 0, 0, .87) +} + +.mat-menu-item[disabled], +.mat-menu-item[disabled]::after { + color: rgba(0, 0, 0, .38) +} + +.mat-menu-item .mat-icon-no-color, +.mat-menu-item-submenu-trigger::after { + color: rgba(0, 0, 0, .54) +} + +.mat-menu-item-highlighted:not([disabled]), +.mat-menu-item.cdk-keyboard-focused:not([disabled]), +.mat-menu-item.cdk-program-focused:not([disabled]), +.mat-menu-item:hover:not([disabled]) { + background: rgba(0, 0, 0, .04) +} + +.mat-paginator { + background: #fff +} + +.mat-paginator, +.mat-paginator-page-size .mat-select-trigger { + color: rgba(0, 0, 0, .54) +} + +.mat-paginator-decrement, +.mat-paginator-increment { + border-top: 2px solid rgba(0, 0, 0, .54); + border-right: 2px solid rgba(0, 0, 0, .54) +} + +.mat-paginator-first, +.mat-paginator-last { + border-top: 2px solid rgba(0, 0, 0, .54) +} + +.mat-icon-button[disabled] .mat-paginator-decrement, +.mat-icon-button[disabled] .mat-paginator-first, +.mat-icon-button[disabled] .mat-paginator-increment, +.mat-icon-button[disabled] .mat-paginator-last { + border-color: rgba(0, 0, 0, .38) +} + +.mat-progress-bar-background { + fill: #c5cae9 +} + +.mat-progress-bar-buffer { + background-color: #c5cae9 +} + +.mat-progress-bar-fill::after { + background-color: #78b7e5 +} + +.mat-progress-bar.mat-accent .mat-progress-bar-background { + fill: #ff80ab +} + +.mat-progress-bar.mat-accent .mat-progress-bar-buffer { + background-color: #ff80ab +} + +.mat-progress-bar.mat-accent .mat-progress-bar-fill::after { + background-color: #78b7e5 +} + +.mat-progress-bar.mat-warn .mat-progress-bar-background { + fill: #ffcdd2 +} + +.mat-progress-bar.mat-warn .mat-progress-bar-buffer { + background-color: #ffcdd2 +} + +.mat-progress-bar.mat-warn .mat-progress-bar-fill::after { + background-color: #f44336 +} + +.mat-progress-spinner circle, +.mat-spinner circle { + stroke: #78b7e5 +} + +.mat-progress-spinner.mat-accent circle, +.mat-spinner.mat-accent circle { + stroke: #78b7e5 +} + +.mat-progress-spinner.mat-warn circle, +.mat-spinner.mat-warn circle { + stroke: #f44336 +} + +.mat-radio-outer-circle { + border-color: rgba(0, 0, 0, .54) +} + +.mat-radio-button.mat-primary.mat-radio-checked .mat-radio-outer-circle { + border-color: #78b7e5 +} + +.mat-radio-button.mat-primary .mat-radio-inner-circle, +.mat-radio-button.mat-primary .mat-radio-ripple .mat-ripple-element:not(.mat-radio-persistent-ripple), +.mat-radio-button.mat-primary.mat-radio-checked .mat-radio-persistent-ripple, +.mat-radio-button.mat-primary:active .mat-radio-persistent-ripple { + background-color: #78b7e5 +} + +.mat-radio-button.mat-accent.mat-radio-checked .mat-radio-outer-circle { + border-color: #78b7e5 +} + +.mat-radio-button.mat-accent .mat-radio-inner-circle, +.mat-radio-button.mat-accent .mat-radio-ripple .mat-ripple-element:not(.mat-radio-persistent-ripple), +.mat-radio-button.mat-accent.mat-radio-checked .mat-radio-persistent-ripple, +.mat-radio-button.mat-accent:active .mat-radio-persistent-ripple { + background-color: #78b7e5 +} + +.mat-radio-button.mat-warn.mat-radio-checked .mat-radio-outer-circle { + border-color: #f44336 +} + +.mat-radio-button.mat-warn .mat-radio-inner-circle, +.mat-radio-button.mat-warn .mat-radio-ripple .mat-ripple-element:not(.mat-radio-persistent-ripple), +.mat-radio-button.mat-warn.mat-radio-checked .mat-radio-persistent-ripple, +.mat-radio-button.mat-warn:active .mat-radio-persistent-ripple { + background-color: #f44336 +} + +.mat-radio-button.mat-radio-disabled .mat-radio-outer-circle, +.mat-radio-button.mat-radio-disabled.mat-radio-checked .mat-radio-outer-circle { + border-color: rgba(0, 0, 0, .38) +} + +.mat-radio-button.mat-radio-disabled .mat-radio-inner-circle, +.mat-radio-button.mat-radio-disabled .mat-radio-ripple .mat-ripple-element { + background-color: rgba(0, 0, 0, .38) +} + +.mat-radio-button.mat-radio-disabled .mat-radio-label-content { + color: rgba(0, 0, 0, .38) +} + +.mat-radio-button .mat-ripple-element { + background-color: #000 +} + +.mat-select-value { + color: rgba(0, 0, 0, .87) +} + +.mat-select-placeholder { + color: rgba(0, 0, 0, .42) +} + +.mat-select-disabled .mat-select-value { + color: rgba(0, 0, 0, .38) +} + +.mat-select-arrow { + color: rgba(0, 0, 0, .54) +} + +.mat-select-panel { + background: #fff +} + +.mat-select-panel:not([class*=mat-elevation-z]) { + box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12) +} + +.mat-select-panel .mat-option.mat-selected:not(.mat-option-multiple) { + background: rgba(0, 0, 0, .12) +} + +.mat-form-field.mat-focused.mat-primary .mat-select-arrow { + color: #78b7e5 +} + +.mat-form-field.mat-focused.mat-accent .mat-select-arrow { + color: #78b7e5 +} + +.mat-form-field.mat-focused.mat-warn .mat-select-arrow { + color: #f44336 +} + +.mat-form-field .mat-select.mat-select-invalid .mat-select-arrow { + color: #f44336 +} + +.mat-form-field .mat-select.mat-select-disabled .mat-select-arrow { + color: rgba(0, 0, 0, .38) +} + +.mat-drawer-container { + background-color: #fafafa; + color: rgba(0, 0, 0, .87) +} + +.mat-drawer { + background-color: #fff; + color: rgba(0, 0, 0, .87) +} + +.mat-drawer.mat-drawer-push { + background-color: #fff +} + +.mat-drawer:not(.mat-drawer-side) { + box-shadow: 0 8px 10px -5px rgba(0, 0, 0, .2), 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12) +} + +.mat-drawer-side { + border-right: solid 1px rgba(0, 0, 0, .12) +} + +.mat-drawer-side.mat-drawer-end { + border-left: solid 1px rgba(0, 0, 0, .12); + border-right: none +} + +[dir=rtl] .mat-drawer-side { + border-left: solid 1px rgba(0, 0, 0, .12); + border-right: none +} + +[dir=rtl] .mat-drawer-side.mat-drawer-end { + border-left: none; + border-right: solid 1px rgba(0, 0, 0, .12) +} + +.mat-drawer-backdrop.mat-drawer-shown { + background-color: rgba(0, 0, 0, .6) +} + +.mat-slide-toggle.mat-checked .mat-slide-toggle-thumb { + background-color: #78b7e5 +} + +.mat-slide-toggle.mat-checked .mat-slide-toggle-bar { + background-color: rgba(255, 64, 129, .54) +} + +.mat-slide-toggle.mat-checked .mat-ripple-element { + background-color: #78b7e5 +} + +.mat-slide-toggle.mat-primary.mat-checked .mat-slide-toggle-thumb { + background-color: #78b7e5 +} + +.mat-slide-toggle.mat-primary.mat-checked .mat-slide-toggle-bar { + background-color: rgba(120, 183, 229, .54) +} + +.mat-slide-toggle.mat-primary.mat-checked .mat-ripple-element { + background-color: #78b7e5 +} + +.mat-slide-toggle.mat-warn.mat-checked .mat-slide-toggle-thumb { + background-color: #f44336 +} + +.mat-slide-toggle.mat-warn.mat-checked .mat-slide-toggle-bar { + background-color: rgba(244, 67, 54, .54) +} + +.mat-slide-toggle.mat-warn.mat-checked .mat-ripple-element { + background-color: #f44336 +} + +.mat-slide-toggle:not(.mat-checked) .mat-ripple-element { + background-color: #000 +} + +.mat-slide-toggle-thumb { + box-shadow: 0 2px 1px -1px rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .14), 0 1px 3px 0 rgba(0, 0, 0, .12); + background-color: #fafafa +} + +.mat-slide-toggle-bar { + background-color: rgba(0, 0, 0, .38) +} + +.mat-slider-track-background { + background-color: rgba(0, 0, 0, .26) +} + +.mat-primary .mat-slider-thumb, +.mat-primary .mat-slider-thumb-label, +.mat-primary .mat-slider-track-fill { + background-color: #78b7e5 +} + +.mat-primary .mat-slider-thumb-label-text { + color: #fff +} + +.mat-accent .mat-slider-thumb, +.mat-accent .mat-slider-thumb-label, +.mat-accent .mat-slider-track-fill { + background-color: #78b7e5 +} + +.mat-accent .mat-slider-thumb-label-text { + color: #fff +} + +.mat-warn .mat-slider-thumb, +.mat-warn .mat-slider-thumb-label, +.mat-warn .mat-slider-track-fill { + background-color: #f44336 +} + +.mat-warn .mat-slider-thumb-label-text { + color: #fff +} + +.mat-slider-focus-ring { + background-color: rgba(255, 64, 129, .2) +} + +.cdk-focused .mat-slider-track-background, +.mat-slider:hover .mat-slider-track-background { + background-color: rgba(0, 0, 0, .38) +} + +.mat-slider-disabled .mat-slider-thumb, +.mat-slider-disabled .mat-slider-track-background, +.mat-slider-disabled .mat-slider-track-fill { + background-color: rgba(0, 0, 0, .26) +} + +.mat-slider-disabled:hover .mat-slider-track-background { + background-color: rgba(0, 0, 0, .26) +} + +.mat-slider-min-value .mat-slider-focus-ring { + background-color: rgba(0, 0, 0, .12) +} + +.mat-slider-min-value.mat-slider-thumb-label-showing .mat-slider-thumb, +.mat-slider-min-value.mat-slider-thumb-label-showing .mat-slider-thumb-label { + background-color: rgba(0, 0, 0, .87) +} + +.mat-slider-min-value.mat-slider-thumb-label-showing.cdk-focused .mat-slider-thumb, +.mat-slider-min-value.mat-slider-thumb-label-showing.cdk-focused .mat-slider-thumb-label { + background-color: rgba(0, 0, 0, .26) +} + +.mat-slider-min-value:not(.mat-slider-thumb-label-showing) .mat-slider-thumb { + border-color: rgba(0, 0, 0, .26); + background-color: transparent +} + +.mat-slider-min-value:not(.mat-slider-thumb-label-showing).cdk-focused .mat-slider-thumb, +.mat-slider-min-value:not(.mat-slider-thumb-label-showing):hover .mat-slider-thumb { + border-color: rgba(0, 0, 0, .38) +} + +.mat-slider-min-value:not(.mat-slider-thumb-label-showing).cdk-focused.mat-slider-disabled .mat-slider-thumb, +.mat-slider-min-value:not(.mat-slider-thumb-label-showing):hover.mat-slider-disabled .mat-slider-thumb { + border-color: rgba(0, 0, 0, .26) +} + +.mat-slider-has-ticks .mat-slider-wrapper::after { + border-color: rgba(0, 0, 0, .7) +} + +.mat-slider-horizontal .mat-slider-ticks { + background-image: repeating-linear-gradient(to right, rgba(0, 0, 0, .7), rgba(0, 0, 0, .7) 2px, transparent 0, transparent); + background-image: -moz-repeating-linear-gradient(.0001deg, rgba(0, 0, 0, .7), rgba(0, 0, 0, .7) 2px, transparent 0, transparent) +} + +.mat-slider-vertical .mat-slider-ticks { + background-image: repeating-linear-gradient(to bottom, rgba(0, 0, 0, .7), rgba(0, 0, 0, .7) 2px, transparent 0, transparent) +} + +.mat-step-header.cdk-keyboard-focused, +.mat-step-header.cdk-program-focused, +.mat-step-header:hover { + background-color: rgba(0, 0, 0, .04) +} + +@media (hover:none) { + .mat-step-header:hover { + background: 0 0 + } +} + +.mat-step-header .mat-step-label, +.mat-step-header .mat-step-optional { + color: rgba(0, 0, 0, .54) +} + +.mat-step-header .mat-step-icon { + background-color: rgba(0, 0, 0, .54); + color: #fff +} + +.mat-step-header .mat-step-icon-selected, +.mat-step-header .mat-step-icon-state-done, +.mat-step-header .mat-step-icon-state-edit { + background-color: #78b7e5; + color: #fff +} + +.mat-step-header .mat-step-icon-state-error { + background-color: transparent; + color: #f44336 +} + +.mat-step-header .mat-step-label.mat-step-label-active { + color: rgba(0, 0, 0, .87) +} + +.mat-step-header .mat-step-label.mat-step-label-error { + color: #f44336 +} + +.mat-stepper-horizontal, +.mat-stepper-vertical { + background-color: #fff +} + +.mat-stepper-vertical-line::before { + border-left-color: rgba(0, 0, 0, .12) +} + +.mat-horizontal-stepper-header::after, +.mat-horizontal-stepper-header::before, +.mat-stepper-horizontal-line { + border-top-color: rgba(0, 0, 0, .12) +} + +.mat-sort-header-arrow { + color: #757575 +} + +.mat-tab-header, +.mat-tab-nav-bar { + border-bottom: 1px solid rgba(0, 0, 0, .12) +} + +.mat-tab-group-inverted-header .mat-tab-header, +.mat-tab-group-inverted-header .mat-tab-nav-bar { + border-top: 1px solid rgba(0, 0, 0, .12); + border-bottom: none +} + +.mat-tab-label, +.mat-tab-link { + color: rgba(0, 0, 0, .87) +} + +.mat-tab-label.mat-tab-disabled, +.mat-tab-link.mat-tab-disabled { + color: rgba(0, 0, 0, .38) +} + +.mat-tab-header-pagination-chevron { + border-color: rgba(0, 0, 0, .87) +} + +.mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron { + border-color: rgba(0, 0, 0, .38) +} + +.mat-tab-group[class*=mat-background-] .mat-tab-header, +.mat-tab-nav-bar[class*=mat-background-] { + border-bottom: none; + border-top: none +} + +.mat-tab-group.mat-primary .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-primary .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-primary .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-primary .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-primary .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-primary .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-primary .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-primary .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled) { + background-color: rgba(197, 202, 233, .3) +} + +.mat-tab-group.mat-primary .mat-ink-bar, +.mat-tab-nav-bar.mat-primary .mat-ink-bar { + background-color: #78b7e5 +} + +.mat-tab-group.mat-primary.mat-background-primary .mat-ink-bar, +.mat-tab-nav-bar.mat-primary.mat-background-primary .mat-ink-bar { + background-color: #fff +} + +.mat-tab-group.mat-accent .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-accent .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-accent .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-accent .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-accent .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-accent .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-accent .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-accent .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled) { + background-color: rgba(255, 128, 171, .3) +} + +.mat-tab-group.mat-accent .mat-ink-bar, +.mat-tab-nav-bar.mat-accent .mat-ink-bar { + background-color: #78b7e5 +} + +.mat-tab-group.mat-accent.mat-background-accent .mat-ink-bar, +.mat-tab-nav-bar.mat-accent.mat-background-accent .mat-ink-bar { + background-color: #fff +} + +.mat-tab-group.mat-warn .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-warn .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-warn .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-warn .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-warn .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-warn .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-warn .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-warn .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled) { + background-color: rgba(255, 205, 210, .3) +} + +.mat-tab-group.mat-warn .mat-ink-bar, +.mat-tab-nav-bar.mat-warn .mat-ink-bar { + background-color: #f44336 +} + +.mat-tab-group.mat-warn.mat-background-warn .mat-ink-bar, +.mat-tab-nav-bar.mat-warn.mat-background-warn .mat-ink-bar { + background-color: #fff +} + +.mat-tab-group.mat-background-primary .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-primary .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-primary .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-primary .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-primary .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-primary .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-primary .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-primary .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled) { + background-color: rgba(197, 202, 233, .3) +} + +.mat-tab-group.mat-background-primary .mat-tab-header, +.mat-tab-group.mat-background-primary .mat-tab-links, +.mat-tab-nav-bar.mat-background-primary .mat-tab-header, +.mat-tab-nav-bar.mat-background-primary .mat-tab-links { + background-color: #78b7e5 +} + +.mat-tab-group.mat-background-primary .mat-tab-label, +.mat-tab-group.mat-background-primary .mat-tab-link, +.mat-tab-nav-bar.mat-background-primary .mat-tab-label, +.mat-tab-nav-bar.mat-background-primary .mat-tab-link { + color: #fff +} + +.mat-tab-group.mat-background-primary .mat-tab-label.mat-tab-disabled, +.mat-tab-group.mat-background-primary .mat-tab-link.mat-tab-disabled, +.mat-tab-nav-bar.mat-background-primary .mat-tab-label.mat-tab-disabled, +.mat-tab-nav-bar.mat-background-primary .mat-tab-link.mat-tab-disabled { + color: rgba(255, 255, 255, .4) +} + +.mat-tab-group.mat-background-primary .mat-tab-header-pagination-chevron, +.mat-tab-nav-bar.mat-background-primary .mat-tab-header-pagination-chevron { + border-color: #fff +} + +.mat-tab-group.mat-background-primary .mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron, +.mat-tab-nav-bar.mat-background-primary .mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron { + border-color: rgba(255, 255, 255, .4) +} + +.mat-tab-group.mat-background-primary .mat-ripple-element, +.mat-tab-nav-bar.mat-background-primary .mat-ripple-element { + background-color: rgba(255, 255, 255, .12) +} + +.mat-tab-group.mat-background-accent .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-accent .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-accent .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-accent .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-accent .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-accent .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-accent .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-accent .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled) { + background-color: rgba(255, 128, 171, .3) +} + +.mat-tab-group.mat-background-accent .mat-tab-header, +.mat-tab-group.mat-background-accent .mat-tab-links, +.mat-tab-nav-bar.mat-background-accent .mat-tab-header, +.mat-tab-nav-bar.mat-background-accent .mat-tab-links { + background-color: #78b7e5 +} + +.mat-tab-group.mat-background-accent .mat-tab-label, +.mat-tab-group.mat-background-accent .mat-tab-link, +.mat-tab-nav-bar.mat-background-accent .mat-tab-label, +.mat-tab-nav-bar.mat-background-accent .mat-tab-link { + color: #fff +} + +.mat-tab-group.mat-background-accent .mat-tab-label.mat-tab-disabled, +.mat-tab-group.mat-background-accent .mat-tab-link.mat-tab-disabled, +.mat-tab-nav-bar.mat-background-accent .mat-tab-label.mat-tab-disabled, +.mat-tab-nav-bar.mat-background-accent .mat-tab-link.mat-tab-disabled { + color: rgba(255, 255, 255, .4) +} + +.mat-tab-group.mat-background-accent .mat-tab-header-pagination-chevron, +.mat-tab-nav-bar.mat-background-accent .mat-tab-header-pagination-chevron { + border-color: #fff +} + +.mat-tab-group.mat-background-accent .mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron, +.mat-tab-nav-bar.mat-background-accent .mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron { + border-color: rgba(255, 255, 255, .4) +} + +.mat-tab-group.mat-background-accent .mat-ripple-element, +.mat-tab-nav-bar.mat-background-accent .mat-ripple-element { + background-color: rgba(255, 255, 255, .12) +} + +.mat-tab-group.mat-background-warn .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-warn .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-warn .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-group.mat-background-warn .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-warn .mat-tab-label.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-warn .mat-tab-label.cdk-program-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-warn .mat-tab-link.cdk-keyboard-focused:not(.mat-tab-disabled), +.mat-tab-nav-bar.mat-background-warn .mat-tab-link.cdk-program-focused:not(.mat-tab-disabled) { + background-color: rgba(255, 205, 210, .3) +} + +.mat-tab-group.mat-background-warn .mat-tab-header, +.mat-tab-group.mat-background-warn .mat-tab-links, +.mat-tab-nav-bar.mat-background-warn .mat-tab-header, +.mat-tab-nav-bar.mat-background-warn .mat-tab-links { + background-color: #f44336 +} + +.mat-tab-group.mat-background-warn .mat-tab-label, +.mat-tab-group.mat-background-warn .mat-tab-link, +.mat-tab-nav-bar.mat-background-warn .mat-tab-label, +.mat-tab-nav-bar.mat-background-warn .mat-tab-link { + color: #fff +} + +.mat-tab-group.mat-background-warn .mat-tab-label.mat-tab-disabled, +.mat-tab-group.mat-background-warn .mat-tab-link.mat-tab-disabled, +.mat-tab-nav-bar.mat-background-warn .mat-tab-label.mat-tab-disabled, +.mat-tab-nav-bar.mat-background-warn .mat-tab-link.mat-tab-disabled { + color: rgba(255, 255, 255, .4) +} + +.mat-tab-group.mat-background-warn .mat-tab-header-pagination-chevron, +.mat-tab-nav-bar.mat-background-warn .mat-tab-header-pagination-chevron { + border-color: #fff +} + +.mat-tab-group.mat-background-warn .mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron, +.mat-tab-nav-bar.mat-background-warn .mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron { + border-color: rgba(255, 255, 255, .4) +} + +.mat-tab-group.mat-background-warn .mat-ripple-element, +.mat-tab-nav-bar.mat-background-warn .mat-ripple-element { + background-color: rgba(255, 255, 255, .12) +} + +.mat-toolbar { + background: #f5f5f5; + color: rgba(0, 0, 0, .87) +} + +.mat-toolbar.mat-primary { + background: #78b7e5; + color: #fff +} + +.mat-toolbar.mat-accent { + background: #78b7e5; + color: #fff +} + +.mat-toolbar.mat-warn { + background: #f44336; + color: #fff +} + +.mat-toolbar .mat-focused .mat-form-field-ripple, +.mat-toolbar .mat-form-field-ripple, +.mat-toolbar .mat-form-field-underline { + background-color: currentColor +} + +.mat-toolbar .mat-focused .mat-form-field-label, +.mat-toolbar .mat-form-field-label, +.mat-toolbar .mat-form-field.mat-focused .mat-select-arrow, +.mat-toolbar .mat-select-arrow, +.mat-toolbar .mat-select-value { + color: inherit +} + +.mat-toolbar .mat-input-element { + caret-color: currentColor +} + +.mat-tooltip { + background: rgba(97, 97, 97, .9) +} + +.mat-tree { + background: #fff +} + +.mat-nested-tree-node, +.mat-tree-node { + color: rgba(0, 0, 0, .87) +} + +.mat-snack-bar-container { + color: rgba(255, 255, 255, .7); + background: #323232; + box-shadow: 0 3px 5px -1px rgba(0, 0, 0, .2), 0 6px 10px 0 rgba(0, 0, 0, .14), 0 1px 18px 0 rgba(0, 0, 0, .12) +} + +.mat-simple-snackbar-action { + color: #78b7e5 +} + +.mat-select { + display: inline-block; + width: 100%; + outline: none +} + +.mat-select-trigger { + display: inline-table; + cursor: pointer; + position: relative; + box-sizing: border-box +} + +.mat-select-disabled .mat-select-trigger { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: default +} + +.mat-select-value { + display: table-cell; + max-width: 0; + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap +} + +.mat-select-value-text { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis +} + +.mat-select-arrow-wrapper { + display: table-cell; + vertical-align: middle +} + +.mat-form-field-appearance-fill .mat-select-arrow-wrapper { + transform: translateY(-50%) +} + +.mat-form-field-appearance-outline .mat-select-arrow-wrapper { + transform: translateY(-25%) +} + +.mat-form-field-appearance-standard.mat-form-field-has-label .mat-select:not(.mat-select-empty) .mat-select-arrow-wrapper { + transform: translateY(-50%) +} + +.mat-form-field-appearance-standard .mat-select.mat-select-empty .mat-select-arrow-wrapper { + transition: transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1) +} + +._mat-animation-noopable.mat-form-field-appearance-standard .mat-select.mat-select-empty .mat-select-arrow-wrapper { + transition: none +} + +.mat-select-arrow { + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid; + margin: 0 4px +} + +.mat-select-panel-wrap { + flex-basis: 100% +} + +.mat-select-panel { + min-width: 112px; + max-width: 280px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding-top: 0; + padding-bottom: 0; + max-height: 256px; + min-width: 100%; + border-radius: 4px +} + +.cdk-high-contrast-active .mat-select-panel { + outline: solid 1px +} + +.mat-select-panel .mat-optgroup-label, +.mat-select-panel .mat-option { + font-size: inherit; + line-height: 3em; + height: 3em +} + +.mat-form-field-type-mat-select:not(.mat-form-field-disabled) .mat-form-field-flex { + cursor: pointer +} + +.mat-form-field-type-mat-select .mat-form-field-label { + width: calc(100% - 18px) +} + +.mat-select-placeholder { + transition: color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1) +} + +._mat-animation-noopable .mat-select-placeholder { + transition: none +} + +.mat-form-field-hide-placeholder .mat-select-placeholder { + color: transparent; + -webkit-text-fill-color: transparent; + transition: none; + display: block +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/3_dx-dir.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/3_dx-dir.scss new file mode 100644 index 0000000..d9162ad --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/3_dx-dir.scss @@ -0,0 +1,10 @@ +/*==================================== + DX-DIRECTORY +======================================*/ + +@import 'dx-button.scss'; +@import 'dx-checkbox.scss'; +@import 'dx-grid.scss'; +@import 'dx-toolbar.scss'; +@import 'dx-typography.scss'; +@import 'dx-additional.scss'; \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-additional.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-additional.scss new file mode 100644 index 0000000..0c53c1a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-additional.scss @@ -0,0 +1,74 @@ +@import 'hr-core-consts.scss'; +/*===================================== + DX-ADDITIONAL +======================================*/ + +.dx-tooltip-wrapper .dx-overlay-content { + border: 1px solid #ddd; + background-color: #fff; + color: #333; + -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + border-radius: $hrBorder-radius-small; +} + +.dx-tooltip-wrapper.dx-popover-wrapper .dx-popover-arrow:after { + border: 1px solid #ddd; + background: #fff; +} + +.dx-slider .dx-tooltip-wrapper .dx-overlay-content { + -webkit-box-shadow: none; + box-shadow: none; +} + +.dx-tooltip-wrapper.dx-popover-wrapper .dx-popover-arrow { + display: block; +} + + +// DX Tabs styling +//---------------- Tabs +.dx-tab { + background: $hrColor-DarkBlue; + transition: all 0.3s ease; +} + +.dx-tab.dx-tab-selected, +.dx-tab.dx-tab-selected .mat-icon { + color: $hrColor-LightBlue; +} + +.dx-tab-content, +.dx-tab-text { + vertical-align: middle; + text-transform: uppercase; + line-height: 24px; + font-weight: 500; +} + + +.dx-tabs.dx-state-focused .dx-tab.dx-state-focused { + background-color: $hrColor-DarkBlue; //rgba(3,169,244,.12) +} + +.dx-tab.dx-tab-selected:before { + height: 2px !important; +} + +.dx-tab:hover:not([disabled]) { + background-color: $hrColor-LightBlue !important; + color: $hrColor-DarkBlue !important; +} + +.dx-tab:hover:not([disabled]) .mat-icon { + color: $hrColor-DarkBlue !important; +} + +.dx-tab:not(.dx-tab-selected):not(.dx-state-hover) { + background: 0 0; +} + +.dx-tabs { + text-align: center; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-button.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-button.scss new file mode 100644 index 0000000..b82d67a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-button.scss @@ -0,0 +1,84 @@ +/*===================================== + DX-BUTTON +======================================*/ +.buttonClose { + font-size: 16px; + cursor: pointer; + text-align: center; + margin-left: auto; + float: right; +} + +.btn-layout-ok { + cursor: pointer !important; + top: 5px; + right: 5px; + margin-left: 5px; + border-width: 0; +} + +.btn-layout-cancel { + cursor: pointer !important; + top: 5px; + right: 5px; + margin-left: 5px !important; + border-width: 0; +} + +.withexport .dx-button { + // margin-left: 0px !important; + left: -1px; + margin-top: 6%; + height: 21px; + width: 21px; + min-width: 21px !important; +} + +.withexport .dx-button .dx-button-content { + padding: 0px; + top: 1px; +} +//----------------------- setting for grid's export button: end + +/*===================================== + DX-DIAL-BUTTON +======================================*/ + +// corrections for css of dev-extreme 23.2.5 - dial button: start +.dx-fa-button.dx-fa-button-main .dx-overlay-content { + min-width: 56px; + max-height: 56px; + border-radius: 28px; +} + +.dx-fa-button.dx-fa-button-main .dx-overlay-content .dx-fa-button-icon, +.dx-fa-button.dx-fa-button-main .dx-overlay-content .dx-fa-button-icon-close { + padding: 19px; +} + +// corrections for css of dev-extreme 23.2.5 - dial button: end + +.dx-fa-button.dx-fa-button-main .dx-overlay-content { + background-color: rgba(255,255,255,0.4); + color: $hrColor-DarkBlue; +} + + +.dx-fa-button.dx-fa-button-main .dx-overlay-content .dx-fa-button-label-wrapper .dx-fa-button-label { + text-transform: none; + font-weight: bolder; + color: $hrColor-DarkBlue; + font-size: 14px; +} + + +.dx-fa-button .dx-fa-button-icon .dx-icon, +.dx-fa-button .dx-fa-button-icon-close .dx-icon { + font-size: 30px; + margin-top: -6px; + margin-left: -6px; +} + +.dx-fa-button .dx-overlay-content .dx-fa-button-label-wrapper .dx-fa-button-label { + font-size: 14px; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-checkbox.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-checkbox.scss new file mode 100644 index 0000000..2b80303 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-checkbox.scss @@ -0,0 +1,12 @@ +/*===================================== + DX-CHECKBOX +======================================*/ +.cb-checked-first { + cursor: pointer !important; + margin-top: 12px; + right: 20px; + margin-left: auto !important; + border-width: 0; + font-size: smaller; + position: relative; +} \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-grid.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-grid.scss new file mode 100644 index 0000000..f6106fb --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-grid.scss @@ -0,0 +1,179 @@ +/*==================================== + DX-GRID +======================================*/ + +.hr-dx-datagrid-height-area .dx-datagrid-rowsview { + height: 1px !important; //trick to prevent dx-grid to overflow, if grid's heigh not fixed and aligned to the area above +} + +.hr-dx-datagrid-height-auto .dx-datagrid-rowsview { + height: inherit !important; //default behavior: the dx-grid heigh=auto if it is not fixed -> it aligns to the area above if its heigh td:not(.dx-focused), +.dx-datagrid-rowsview .dx-row-focused.dx-data-row > tr > td:not(.dx-focused), +.dx-datagrid-rowsview .dx-row-focused.dx-data-row .dx-command-edit .dx-link { + background-color: $hrColor-LightBlue !important; + color: #fff !important; +} + +.dx-datagrid .dx-datagrid-content .dx-datagrid-table .dx-row > td { + padding-left: 3px; // !important; + padding-right: 3px; // !important; + padding-bottom: 5px; // !important; + padding-top: 5px; // !important; +} + +.dx-datagrid-headers .dx-datagrid-content .dx-datagrid-table .dx-row.dx-header-row > td { + padding-top: 5px !important; + padding-bottom: 5px !important; +} + +.dx-datagrid .dx-datagrid-content .dx-datagrid-table .dx-row > td:first-child { + padding-left: 10px; +} + +.dx-datagrid .dx-datagrid-content .dx-datagrid-table .dx-row > td:last-child { + padding-right: 10px; +} + + +.dx-datagrid .dx-column-indicators.dx-visibility-hidden { + display: none; //don't show gap for the align=center grid headers if sort arrow is shown rights +} + +//----------------------- grid header settings +.headeralignment_left .dx-datagrid-headers .dx-datagrid-table .dx-row>td { + //align only grid header left + text-align: left !important; +} + +.headeralignment_right .dx-datagrid-headers .dx-datagrid-table .dx-row>td { + //align only grid header right + text-align: right !important; +} + +.headeralignment_center .dx-datagrid-headers .dx-datagrid-table .dx-row>td { + //align only grid header center + text-align: center !important; +} + +// .dx-datagrid-headers .dx-datagrid-table .dx-row>td { +// +// text-align: left !important; //set all dx-headers left aligned - must be used in style.css - apps depended, not in core! +// padding-top: 5px; //enger grid headers +// padding-bottom: 5px; //enger grid headers +// } + +//----------------------- grid row filter settings +.dx-datagrid .dx-editor-with-menu, +.dx-datagrid-container .dx-editor-with-menu { + height: 20px; +} + + +.dx-editor-cell .dx-texteditor .dx-texteditor-input { + height: 20px; + padding-top: 10px; +} + +.dx-datagrid .dx-editor-with-menu .dx-menu-item-content .dx-icon.dx-icon-filter-operation-default, +.dx-datagrid-container .dx-editor-with-menu .dx-menu-item-content .dx-icon.dx-icon-filter-operation-default, +.dx-datagrid .dx-item-content dx-menu-item-content { + // margin-top: -14px; + margin-top: 3px; +} + +// .dx-datagrid .dx-dropdowneditor-icon::before { +// margin-top: -12px; +// } + +.dx-datagrid .dx-texteditor-input-container .dx-placeholder { + margin-top: -5px; +} + +.dx-editor-cell.dx-editor-inline-block:not(.dx-command-select)::before { + padding-top: 0px; + padding-bottom: 0px; +} + +//------------------------ setting for grid's export button +.withexport .dx-datagrid-export-button .dx-icon-export-excel-button:before { + content: "\f05f"; +} + +.withexport .dx-datagrid-export-button .dx-icon-xlsxfile:before { + content: "\f05f"; +} + +.withexport .dx-header-row > td:last-of-type > .dx-datagrid-text-content { + width: calc(100% - 8px); +} + +.withexport .dx-header-row > td:last-of-type > .dx-sort-indicator { + width: calc(100% - 28px); +} + +.withexport .dx-datagrid-header-panel { + z-index: 2; +} +//----------------------- setting for grid's export button: end + +//---------customizing + +.dx-freespace-row { + height: 0px !important; +} + +.inline-edit-grid .dx-datagrid .dx-datagrid-content .dx-datagrid-table .dx-row>td { + padding-left: 7px; + padding-right: 7px; +} + +.inline-edit-grid .dx-datagrid .dx-datagrid-content .dx-datagrid-table .dx-row:not(.dx-header-row)>td { + padding-bottom: 0px; + padding-top: 0px; +} + + +.inline-editor { + // margin-top: -0.7em; + width: 100%; +} + +.inline-editor .mat-form-field-infix { + border-top-width: 0px; +} + + +.inline-editor-suffix { + // margin-top: -0.7em; + width: 100%; + padding-right: 10px; +} + +.inline-editor-checkbox { + padding-left: 5px; + margin-top: 0px; +} + + +td[role='gridcell']:has(.grid-vert-left-line) { + border-left: 1px solid #e0e0e0; +} + +td[role='gridcell']:has(.grid-vert-right-line) { + border-right: 1px solid #e0e0e0; +} + +td[role='gridcell']:has(.grid-botom-line) { + border-bottom: 1px solid #e0e0e0; +} + +td[role='gridcell']:has(.grid-top-line) { + border-top: 1px solid #e0e0e0; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-toolbar.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-toolbar.scss new file mode 100644 index 0000000..637b3f7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-toolbar.scss @@ -0,0 +1,17 @@ +/*===================================== + DX-TOOLBAR +======================================*/ + +.withexport .dx-toolbar { + height: 0px; +} + +.withexport .dx-toolbar .dx-toolbar-items-container { + height: 0px; + left: 10px; +} + +.withexport .dx-toolbar-after { + height: 0px; + padding-left: 0px !important; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-typography.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-typography.scss new file mode 100644 index 0000000..401ba8c --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-devextreme-styling/dx-typography.scss @@ -0,0 +1,11 @@ +/*==================================== + DX-TYPOGRAPHY +======================================*/ + +//for the same layout of material autocomplete, material calendar and material select components +// .dx-theme-material-typography input, +// .dx-theme-material-typography textarea { +// // font-family: inherit !important; //to use font from instead /css/dx.material.blue.light.compact.css of indigo-pink.scss +// //to use line-height from instead /css/dx.material.blue.light.compact.css of indigo-pink.scss +// line-height: 1 !important; +// } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/3_mat-dir.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/3_mat-dir.scss new file mode 100644 index 0000000..de84a82 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/3_mat-dir.scss @@ -0,0 +1,9 @@ +/*==================================== + MATERIAL-DIRECTORY +======================================*/ + +@import 'mat-button.scss'; +@import 'mat-checkbox.scss'; +@import 'mat-toolbar.scss'; +@import 'mat-typography.scss'; +@import 'mat-additional.scss'; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-additional.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-additional.scss new file mode 100644 index 0000000..82c4085 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-additional.scss @@ -0,0 +1,149 @@ +@import 'hr-core-consts.scss'; +/*===================================== + MAT-ADDITIONAL +======================================*/ + +// sidenav styling +mat-sidenav-container, +mat-sidenav-content, +mat-sidenav { + height: 100%; +} + +/*=========================================================================================================================*/ + +mat-sidenav { + width: 250px; +} + +// Tab Gruppen +mat-tab-group { + text-align: center; +} + +mat-tab-group p { + padding-top: 20px; +} + +/*=========================================================================================================================*/ +// spinner styling + +.mat-spinner circle { + stroke: $hrColor-DarkBlue !important; //#78b7e5; +} + +.hrd-mat-spinner { + transform: scale(0.3); + left: calc(50% - 46px); + top: -38px; + // display: inline-block !important; + position: absolute !important; +} + +.input.mat-input-element { + margin-top: inherit !important; +} + +// the next 2 settings do the mat form field enger +.mat-form-field-appearance-legacy .mat-form-field-underline { + bottom: 5px; +} + +.mat-form-field-wrapper { + padding-bottom: 5px !important; +} + +.mat-option { + height: 30px !important; + display: flex !important; +} + +/*=========================================================================================================================*/ +// dialog styling + +.mat-dialog-container { + border-radius: $hrBorder-radius-big !important; + height: auto !important; + overflow: hidden !important; +} + +//additional dead code +/* +// "-" symbol color in check box partially selected +::ng-deep .mat-checkbox-mixedmark { + background-color: rgba(0, 0, 0, .54); +} + +// check-symbol color in check box and width +::ng-deep .mat-checkbox-checkmark-path { + stroke: $hrColor-LightBlue !important; + stroke-width: 3 !important; +} +*/ + + +.mat-tab-label-active { + font-weight: bold !important; + opacity: 1 !important; +} + +.hr-alfa-disabled .mat-form-field-disabled, +.hr-alfa-disabled .mat-form-field-disabled .mat-select-value, +.hr-alfa-disabled .mat-input-element:disabled, +.hr-alfa-disabled .mat-checkbox-disabled .mat-checkbox-label, +.hr-alfa-disabled .mat-checkbox-disabled .mat-checkbox-input, +.hr-alfa-disabled .mat-radio-button.mat-radio-disabled .mat-radio-label-content { + color: rgba(0, 0, 0, $hrColor-Alpha_Disabled) !important; +} + +//--- menu + +.mat-menu-item { + line-height: 30px !important; + height: 30px !important; +} + + +//--- errors +.mat-error { + text-align: left; + width: fit-content; + background-color: rgb(255, 255, 255); +} + + +/*=========================================================================================================================*/ +// stepper + +.mat-vertical-stepper-header { + padding: 24px 10px 24px 24px; +} + +.mat-stepper-vertical-line::before { + top: -16px; + bottom: -16px; +} + + +/*=========================================================================================================================*/ +// drop down + +.mat-select-trigger { + height: 1.25em; + display: inline-table !important; +} + +.mat-input-element { + text-overflow: ellipsis; + // overflow: hidden; + // white-space: nowrap; +} + +.mat-select-arrow-wrapper { + display: table-cell !important; +} + +// .dx-dropdowneditor-button .dx-button-content { +// position: absolute; +// margin-top: 5px; +// } diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-button.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-button.scss new file mode 100644 index 0000000..8005406 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-button.scss @@ -0,0 +1,142 @@ +@import 'hr-core-consts.scss'; +/*===================================== + MAT-BUTTON +======================================*/ + +.mat-stroked-button, +.mat-raised-button { + min-width: auto !important; + padding-right: 5px !important; + padding-left: 5px !important; + transition: all 0.3s ease; +} + +//Stroke button accent styling +.mat-button.mat-accent, +.mat-icon-button.mat-accent, +.mat-stroked-button.mat-accent { + color: white; + background: $hrColor-DarkBlue; +} + +.mat-stroked-button:hover:not([disabled]), +.mat-raised-button:hover:not([disabled]) +{ + background-color: $hrColor-LightBlue !important; + color: $hrColor-DarkBlue !important; + border-color: $hrColor-DarkBlue; +} + +.mat-stroked-button:hover:not([disabled]) .mat-icon, +.mat-raised-button:hover:not([disabled]) .mat-icon +{ + color: $hrColor-DarkBlue !important; +} + +.mat-stroked-button:focus, +.mat-raised-button:focus + { + background: $hrColor-DarkBlue; + color: $hrColor-LightBlue; +} + +.mat-stroked-button:focus .mat-icon, +.mat-raised-button:focus .mat-icon, +.mat-stroked-toggle:focus .mat-icon { + color: $hrColor-LightBlue; +} + +.material-icons { + color: $hrColor-DarkBlue; + text-align: center; + } + +.mat-button .material-icons, +.mat-fab .material-icons, +.mat-mini-fab .material-icons { + color: unset; +} + +.mat-icon-button { + padding: 0 !important; + min-width: 0 !important; + width: 25px !important; + height: 25px !important; + flex-shrink: 0 !important; + line-height: 25px !important; + border-radius: 50% !important; +} + +.mat-stroked-button[disabled] .material-icons, +.mat-icon-button[disabled] .material-icons, +.mat-flat-button[disabled] .material-icons, +.mat-raised-button[disabled] .material-icons { + color: rgba(11, 58, 98, 0.4); +} + +.mat-raised-button { + margin-right: 2px !important; +} + +//---------- Mat Toggle Buttons --------- + +.mat-button-toggle:focus + { + background: $hrColor-LightBlue; + color: white; +} + +.mat-stroked-toggle:focus .mat-icon { + color: white; +} + +.hr-darkblue .mat-button-toggle +{ + background: $hrColor-DarkBlue; + color: white !important; +} + +.hr-darkblue .mat-button-toggle-checked +{ + background: $hrColor-LightBlue; + color: white !important; + // border-color: $hrColor-DarkBlue; +} + +.mat-button-toggle-checked +{ + background: $hrColor-DarkBlue; + color: $hrColor-LightBlue !important; +// border-color: $hrColor-DarkBlue; +} + +.mat-button-toggle:hover:not([disabled]) +{ + background-color: $hrColor-LightBlue !important; + color: $hrColor-DarkBlue !important; + border-color: $hrColor-DarkBlue; +} + +.mat-button-toggle:hover:not([disabled]) .material-icons { + color: $hrColor-DarkBlue !important; +} + +.mat-button-toggle[disabled] .material-icons { + color: rgba(11, 58, 98, 0.4); +} + + +.mat-button-wrapper:not(:has(.mat-icon)) { + padding-left: 5px; + padding-right: 5px; +} + +.mat-button-wrapper:has(.mat-icon) { + padding-right: 7px; +} + +.mat-button-withoutcaption .mat-button-wrapper:has(.mat-icon), +.mat-form-field .mat-button-wrapper +{ + padding-right: 0px; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-checkbox.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-checkbox.scss new file mode 100644 index 0000000..9960e27 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-checkbox.scss @@ -0,0 +1,37 @@ +/*===================================== + MAT-CHECKBOX +======================================*/ + +// check box frame color if is checked +::ng-deep .mat-checkbox-checked .mat-checkbox-frame { + border-color: $hrColor-LightBlue !important; +} + +//checkbox filling - transperant or light blue +::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background, +.mat-checkbox-indeterminate.mat-accent .mat-checkbox-background { + background-color: $hrColor-LightBlue !important; //transparent; //#78b7e5; +} + +::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background { + background-color: $hrColor-LightBlueMain !important; +} + +::ng-deep .mat-step-header .mat-step-icon-selected { + background-color: $hrColor-DarkBlue !important; +} + +::ng-deep div.mat-step-icon.mat-step-icon-state-edit { + background-color: $hrColor-LightBlueMain !important; +} + +::ng-deep .mat-radio-button.mat-accent .mat-radio-inner-circle, +.mat-radio-button.mat-accent .mat-radio-ripple .mat-ripple-element:not(.mat-radio-persistent-ripple), +.mat-radio-button.mat-accent.mat-radio-checked .mat-radio-persistent-ripple, +.mat-radio-button.mat-accent:active .mat-radio-persistent-ripple { + background-color: $hrColor-DarkBlue; +} + +::ng-deep .mat-radio-button.mat-accent.mat-radio-checked .mat-radio-outer-circle { + border-color: $hrColor-DarkBlue; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-toolbar.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-toolbar.scss new file mode 100644 index 0000000..4aa1e8a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-toolbar.scss @@ -0,0 +1,21 @@ +@import 'hr-core-consts'; + +/*===================================== + MAT-TOOLBAR +======================================*/ + +.mat-toolbar.mat-primary { + background: $hrColor-DarkBlue !important; // #76a9cb; + color: #fff !important; +} + +.mat-toolbar-row, +.mat-toolbar-single-row { + height: 45px !important; +} + +mat-toolbar { + // border-bottom-left-radius: $hrBorder-radius-small; + // border-bottom-right-radius: $hrBorder-radius-small; + border-radius: $hrBorder-radius-small; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-typography.scss b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-typography.scss new file mode 100644 index 0000000..22cc1f5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/css/3-vendor/hr-material-styling/mat-typography.scss @@ -0,0 +1,3 @@ +/*==================================== + MAT-TYPOGRAPHY +======================================*/ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/devextreme-license.ts b/ClientApp/staff-db-ui/src/app/shared/core/devextreme-license.ts new file mode 100644 index 0000000..b258d12 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/devextreme-license.ts @@ -0,0 +1 @@ +export const licenseKey = ''; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-decimal.directive.ts b/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-decimal.directive.ts new file mode 100644 index 0000000..abd4e94 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-decimal.directive.ts @@ -0,0 +1,98 @@ +import { Directive, HostListener, ElementRef, OnInit, Optional, AfterViewInit, OnDestroy, Input, LOCALE_ID, Inject } from '@angular/core'; +import { formatNumber } from '@angular/common'; +import { NgControl } from '@angular/forms'; +import { Subscription } from 'rxjs'; +import * as keycode from '@angular/cdk/keycodes'; + + +@Directive({ + standalone: true, + selector: '[henselDecimal]' +}) +export class HenselMaskDecimalDirective implements OnInit, AfterViewInit, OnDestroy { + private el: HTMLInputElement; + private previousValue: any; + private subscription: Subscription; + private focused: boolean = false; + private noOfDecimals: number = 2; + private transformAnyway: boolean = false;S + @Input() + set henselDecimal(value: number) { + // if (value || value === 0) + this.noOfDecimals = value; + } + + @Input() henselDecimalAllowEmpty: boolean = false; + + constructor( + private elementRef: ElementRef, + @Inject(LOCALE_ID) private localeId: string, + @Optional() private control: NgControl) { + this.el = this.elementRef.nativeElement; + } + + useDirective(): boolean { + return (this.noOfDecimals !== undefined && this.noOfDecimals !== null); + } + + + @HostListener('focus', ['$event.target.value']) + onFocus() { + if (!this.useDirective()) return; + this.previousValue = this.control.value; //this.el.value; + this.transform(0, this.noOfDecimals); + this.focused = true; + this.el.select(); + } + + @HostListener('keydown', ['$event']) + onKeyDown(event: any) { + if (this.useDirective()) { + switch (event.which) { + case keycode.ESCAPE: // ESC + event.stopPropagation(); + // this.el.value = this.previousValue; + this.transformAnyway = true; + this.control.control.setValue(!this.previousValue && this.henselDecimalAllowEmpty ? this.previousValue : +(this.previousValue ?? 0)); + return false; + } + } + return true; + } + + + @HostListener('blur', ['$event.target.value']) + onBlur(value: any) { + if (!this.useDirective()) return; + this.focused = false; + this.transform(this.noOfDecimals, this.noOfDecimals); + if ((isNaN(this.control.value) || !this.control.value) && !this.henselDecimalAllowEmpty) this.control.control.setValue(0); + } + + ngAfterViewInit(): void { + } + + ngOnInit() { + if (!this.useDirective()) return; + this.subscription = this.control.valueChanges.subscribe(() => setTimeout(() => { + this.transform(this.noOfDecimals, this.noOfDecimals); + }, 0) + ); + } + + ngOnDestroy(): void { + this.subscription?.unsubscribe(); + } + + + transform = (noOfDecimalsMin: number, noOfDecimalsMax: number) => { + const controlValueIsNull = (this.control.value === null) || (this.control.value === undefined); + if ((this.transformAnyway || !this.focused) && (!controlValueIsNull || this.el.value)) { + if ((controlValueIsNull || this.control.value === '') && this.henselDecimalAllowEmpty) { + this.el.value = null; + } else this.el.value = formatNumber(+this.control.value, this.localeId, `1.${noOfDecimalsMin}-${noOfDecimalsMax}`); + this.transformAnyway = false; + } + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-dnd.directive.ts b/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-dnd.directive.ts new file mode 100644 index 0000000..f1fcb52 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-dnd.directive.ts @@ -0,0 +1,88 @@ +import { Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, Output, ViewChild } from '@angular/core'; + +@Directive({ + standalone: true, + selector: '[henselDnD]' +}) + + +export class HenselDnDDirective { + + private _disabled: boolean = false; + public get disabled(): boolean { + return this._disabled; + } + @Input() + public set disabled(value: boolean) { + this._disabled = value; + } + + // tslint:disable-next-line: no-output-on-prefix + @Output() onFileDropped = new EventEmitter(); + @HostBinding('style.background-color') private backgroundColor; + @HostBinding('style.opacity') private opacity; + // @ViewChild('dndicon') icon: ElementRef; + private icon: any; + private _dragover: boolean = false; + public get dragover(): boolean { + return this._dragover; + } + public set dragover(value: boolean) { + if (this._dragover === value) return; + if (value && this.disabled) return; + this._dragover = value; + if (value) { + if (!this.icon) { + this.icon = document.getElementById('dndicon'); + if (this.icon) { + this.lastIcon = this.icon.innerText; + if (this.icon) this.icon.innerText = 'vertical_align_top'; + } + } + this.backgroundColor = '#76a9cb'; + this.opacity = '1'; + } else { + setTimeout(() => { + if (!this.dragover) { + if (this.icon) this.icon.innerText = this.lastIcon; + this.icon = null; + delete this.opacity; + delete this.backgroundColor; + } + }, 100); + } + } + + private lastIcon: string; + + + //Dragover listener + @HostListener('dragover', ['$event']) onDragOver(evt) { + if (this.disabled) evt.dataTransfer.dropEffect = 'none'; + else evt.dataTransfer.dropEffect = 'copy'; + evt.preventDefault(); + evt.stopPropagation(); + this.dragover = true; + } + + //Dragleave listener + @HostListener('dragleave', ['$event']) public onDragLeave(evt) { + evt.preventDefault(); + evt.stopPropagation(); + this.dragover = false; + } + + //Drop listener + @HostListener('drop', ['$event']) public ondrop(evt) { + evt.preventDefault(); + evt.stopPropagation(); + if (!this._disabled) { + const files = evt.dataTransfer.files; + if (files.length > 0) this.onFileDropped.emit(files); + } + + this.dragover = false; + } + + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-mask.directive.ts b/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-mask.directive.ts new file mode 100644 index 0000000..47904c5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-mask.directive.ts @@ -0,0 +1,35 @@ +import { Directive, HostListener, Input, Optional } from '@angular/core'; +import { NgControl } from '@angular/forms'; + +@Directive({ + standalone: true, + selector: '[henselMask]' +}) + +export class HenselMaskDirective { + @Input() + set henselMask(value) { + this.regExpr = new RegExp(value); + } + + private _oldvalue: string = ''; + private regExpr: any; + constructor(@Optional() private control: NgControl) { + } + @HostListener('input', ['$event']) + change($event) { + const item = $event.target; + const value = item.value; + let pos = item.selectionStart; + const matchvalue = value; + const noMatch: boolean = (value && !(this.regExpr.test(matchvalue))); + if (noMatch) { + item.selectionStart = item.selectionEnd = pos - 1; + if (item.value.length < this._oldvalue.length && pos === 0) pos = 2; + if (this.control) this.control.control.setValue(this._oldvalue, { emit: false }); + + item.value = this._oldvalue; + item.selectionStart = item.selectionEnd = pos - 1; + } else this._oldvalue = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-stepper-scroller.ts b/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-stepper-scroller.ts new file mode 100644 index 0000000..ccb6d90 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/directives/hensel-stepper-scroller.ts @@ -0,0 +1,21 @@ +import { Directive, HostListener } from '@angular/core'; +import { MatStepper } from '@angular/material/stepper'; + +/* is used to: if a selected step is out of visibility, stepper screen is scrolled automatically to show it */ + +@Directive({ + standalone: true, + selector: '[mat-vertical-stepper-scroller]', +}) +export class MatVerticalStepperScrollerDirective { + constructor(private stepper: MatStepper) {} + + @HostListener('animationDone') + selectionChanged() { + const stepId = this.stepper._getStepLabelId(this.stepper.selectedIndex); + const stepElement = document.getElementById(stepId); + if (stepElement) { + stepElement.scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth' }); + } + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/images/DHR-2015-1004_DHR_Logo_Querformat_RGB.png b/ClientApp/staff-db-ui/src/app/shared/core/images/DHR-2015-1004_DHR_Logo_Querformat_RGB.png new file mode 100644 index 0000000..89e1574 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/images/DHR-2015-1004_DHR_Logo_Querformat_RGB.png differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_bright.ico b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_bright.ico new file mode 100644 index 0000000..bc6c2d1 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_bright.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_color.ico b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_color.ico new file mode 100644 index 0000000..d65b48a Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_color.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_color3d.ico b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_color3d.ico new file mode 100644 index 0000000..917acf3 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_color3d.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_red.ico b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_red.ico new file mode 100644 index 0000000..7e7f832 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_red.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_white.ico b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_white.ico new file mode 100644 index 0000000..ff4f496 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/images/hr-logo_white.ico differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/images/logo.png b/ClientApp/staff-db-ui/src/app/shared/core/images/logo.png new file mode 100644 index 0000000..204a0e0 Binary files /dev/null and b/ClientApp/staff-db-ui/src/app/shared/core/images/logo.png differ diff --git a/ClientApp/staff-db-ui/src/app/shared/core/injection-tokens.ts b/ClientApp/staff-db-ui/src/app/shared/core/injection-tokens.ts new file mode 100644 index 0000000..3728d6a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/injection-tokens.ts @@ -0,0 +1,35 @@ +import { InjectionToken, NgModule } from '@angular/core'; + +export interface IENVIRONMENT { + production: boolean; + useLoginWithJWT?: boolean; + dontUseWindowsLogin?: boolean; + apiUrl: string; + APP_TITLE: string; + appVersion?: string; + appBuild?: string; + sentry_dsn?: string; + translationFolder: string; + headerData?: string; + culture?: string; + language?: string; + protocol?: string; +} + + +export const ENVIRONMENT_TOKEN = new InjectionToken('environment'); +export const SUPPORTED_LANGUAGES_TOKEN = new InjectionToken('Languages supported by App'); +export const SUPPORTED_CULTURES_TOKEN = new InjectionToken('Culturess supported by App'); + +export const APPICON4TEST_TOKEN = new InjectionToken('APPICON4TEST_TOKEN', { + providedIn: 'root', + factory: () => 'assets/icons/hr-logo_red.ico', +}); +export const APPICON4LIVE_TOKEN = new InjectionToken('APPICON4LIVE_TOKEN', { + providedIn: 'root', + factory: () => 'assets/icons/hr-logo_color.ico', +}); +export const APPICON4NAVBAR_TOKEN = new InjectionToken('APPICON4NAVBAR_TOKEN', { + providedIn: 'root', + factory: () => 'assets/icons/hr-logo_bright.ico', +}); diff --git a/ClientApp/staff-db-ui/src/app/shared/core/models/coreuser.ts b/ClientApp/staff-db-ui/src/app/shared/core/models/coreuser.ts new file mode 100644 index 0000000..8d9d3b4 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/models/coreuser.ts @@ -0,0 +1,75 @@ +import { BaseEntity } from '../models/generics/baseentity'; +import { EN_CoreEntities } from '../services/globals'; + +export interface UserRole { + code: string; + caption: string; +} + + +export const enum EN_UserRoles { + User = 'user', + Master = 'master', + Admin = 'admin', + DepartmentMaster = 'departmentmaster', + DepartmentUser = 'departmentuser' +} + + +export class CoreUser extends BaseEntity { + typeName: string = EN_CoreEntities.User; + + webAppUserId: number; + name: string; + shortName: string; + loginName: string; + password: string; + roleList: string; + webAppRoleList: string; + token?: string; + jwtExpiredOn: Date; + lastLogin: string | Date | null; + clientVersion: string; + timeZoneOffsetInMin: number; + language: string; + culture: string; + showDisclaimer: boolean; + + get entityId(): number { return this.webAppUserId; } + set entityId(id: number) { this.webAppUserId = id; } + + get isAdmin(): boolean { + return this.isInRolle(EN_UserRoles.Admin); + } + + get isMaster(): boolean { + return this.isInRolle(EN_UserRoles.Master) || this.isInRolle(EN_UserRoles.DepartmentMaster) || this.isAdmin; + } + + showFooter: boolean; + + public isInRolle(role: string): boolean { + role = role?.toLowerCase(); + return (this.roleList && ((',' + this.roleList.replace(' ', '') + ',').toLowerCase().indexOf(',' + role + ',') > -1)) + || (this.webAppRoleList && ((',' + this.webAppRoleList.replace(' ', '') + ',').toLowerCase().indexOf(',' + role + ',') > -1)); + } + + + assign(source: Partial): CoreUser { + super.assign(source); + if (this.jwtExpiredOn && typeof this.jwtExpiredOn !== 'object') this.jwtExpiredOn = new Date(this.jwtExpiredOn); + return this; + } + + clear() { + super.clear(); + this.jwtExpiredOn = undefined; + this.token = undefined; + } +} + + +export interface UserRoles { + admin?: boolean; + master?: boolean; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentity.ts b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentity.ts new file mode 100644 index 0000000..f7b701e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentity.ts @@ -0,0 +1,209 @@ + +import { cnst_ErrorCode4Unauthorized, EN_Error } from '../../consts'; +import { ResultSubject } from '../../models/resultsubject'; +import { RepositoryService } from '../../services/http/repository.service'; +import { Observable } from 'rxjs'; +import { now } from '../../utils'; + +export type BaseEntityCallBack = (entity?: BaseEntity) => void; +export type ErrorCallBack = (error: any) => void; + +export class BaseEntity { + public typeName: string = ''; //is used as Controller for URL queries + public get entitytitle(): string { return ''; } //is used for messages + public get useNull4Clear(): boolean { return false; } //is used for clear to set null instead of 0 or '' + public entityChanged: boolean = false; + get dateFields(): string { + return null; + } + protected technicalFields: string[] = ['dateFields', 'dontInsertFields', 'dontUpdateFields', 'typeName', 'entitytitle', 'technicalFields', 'lastLoaded', 'useNull4Clear']; + public dontUpdateFields: string[] = [...this.technicalFields, 'entityChanged']; + public dontInsertFields: string[] = [...this.technicalFields, 'entityChanged']; + public lastLoaded: number; + + resetCallBack: (obj: BaseEntity) => void; + + constructor(source?: Partial) { + // this.typeName = this.constructor.name; //is not working in productive environment !!! + if (source) this.assign(source); + else this.clear(); + } + + public deleteFields(): BaseEntity { + const retEntity: BaseEntity = Object.assign({}, this); + const whatfields: string[] = this.isNew() ? this.dontInsertFields : this.dontUpdateFields; + whatfields.forEach((field: string) => delete retEntity[field]); + return retEntity; + } + + get entityId(): number { return -1; } + set entityId(id: number) { } + + + public assign(source: Partial): BaseEntity { + this.clear(); + const res = Object.assign(this, source); + this.approveDateFields(this.dateFields); + return res; + } + + + public approveDateField(fieldname: string) { + if (this[fieldname] && !(this[fieldname] instanceof Date)) this[fieldname] = new Date(this[fieldname]); + } + + + public approveDateFields(fieldnames: string) { + if (!fieldnames) return; + const list = fieldnames.split(','); + list.forEach(fld => this.approveDateField(fld.trim())); + } + + + protected clearField(fldName: string, useNull: boolean = false) { + if (this[fldName] instanceof Array) this[fldName] = []; + else { + if (fldName.slice(-2) === 'Id') this[fldName] = null; + else { + switch (useNull || this.useNull4Clear ? null : typeof this[fldName]) { + case 'number': + this[fldName] = 0; + break; + case 'boolean': + this[fldName] = false; + break; + case 'string': + this[fldName] = ''; + break; + default: + this[fldName] = null; + break; + } + } + } + } + + + public clear(useNull: boolean = false) { + try { + for (const prop in this) { + if ((this.technicalFields.indexOf(prop) === -1) && this.propertyIsEnumerable(prop)) this.clearField(prop, useNull); + } + } catch (ex) { } + + if (this.isRealObject()) this.entityId = 0; + + this.entityChanged = false; + if (this.resetCallBack) { this.resetCallBack(this); } + } + + + public isEmpty() { + return Object.keys(this).length === 0 && (typeof this) === 'object'; + } + + //checks if this a realy Object with all methods but not only record with data fields after http call + public isRealObject() { + return 'entityId' in this; + } + + + public isValidInput() { return true; } + + public isNew() { return !this.entityId || this.entityId <= 0; } + + public insertWithIds() { return false; } + + load(repositoryService: RepositoryService, loadedcallback: BaseEntityCallBack, errorcallback?: ErrorCallBack, completecallback?: () => void): boolean { + const currentId = this.entityId; + if (!this.isNew() || currentId === -1) //-1 means load entity w/o id, f.e. Info + { + repositoryService.getDataById(this.typeName, currentId) + .subscribe((entity: BaseEntity) => { + if (this.entityId !== currentId) return false; //means, that meanwhile a load command for another Id was executed. it must win + console.log('loaded', entity); + this.lastLoaded = now(); + this.assign(entity); + if (loadedcallback) loadedcallback(this); + return true; + }, (error: any) => { + if (error.status !== cnst_ErrorCode4Unauthorized) this.clear(); + if (errorcallback) errorcallback(new ResultSubject(error, this, this.typeName + ': ')); + }, completecallback); + } else { + this.clear(); + // if (loadedcallback) loadedcallback(this); //for new only complete is triggered - otherwise an empty line is added to the grid, because of sync + if (completecallback) completecallback(); + } + return false; + } + + + public includeFieldForUpdate(fieldNames: string) { + const fieldList = fieldNames.split(','); + fieldList.forEach(fieldName => { + const index = this.dontUpdateFields.indexOf(fieldName); + if (index > -1) this.dontUpdateFields.splice(index, 1); + }); + } + + + public excludeFieldFromUpdate(fieldNames: string) { + const fieldList = fieldNames.split(','); + fieldList.forEach(fieldName => { + const index = this.dontUpdateFields.indexOf(fieldName); + if (index === -1) this.dontUpdateFields.push(fieldName); + }); + } + + + public async saveAsync(repositoryService: RepositoryService): Promise { + return new Promise((resolve, reject) => this.save(repositoryService, () => resolve(true), () => resolve(false))); + } + + + public save(repositoryService: RepositoryService, loadedcallback: BaseEntityCallBack, errorcallback?: ErrorCallBack, completecallback?: () => void, useSuffixInsteadEntityId?: string): void { + const lastId = this.entityId; + if (this.isNew()) this.entityId = this.insertWithIds() ? -this.entityId : 0; //the case when entityId<0 + const cloneEntity = this.deleteFields(); + this.entityId = lastId; //the case when entityId<0 + // if (this.isNew()) cloneEntity.entityId = 0; //the case when entityId<0 + + const loadedObj$: Observable = !this.isNew() && (useSuffixInsteadEntityId === null || useSuffixInsteadEntityId === undefined) ? + repositoryService.putDataById(this.typeName, this.entityId, cloneEntity) : + repositoryService.postDataById(this.typeName, useSuffixInsteadEntityId ?? this.entityId, cloneEntity); + + loadedObj$.subscribe( + (entity: BaseEntity) => { + console.log('loaded', entity); + this.assign(entity); + if (!this.isNew() /* means save successed*/) { + this.lastLoaded = now(); + if (loadedcallback) loadedcallback(this); + } else { + this.entityChanged = true; + if (errorcallback) errorcallback(({ errMsg: this.typeName + ': ' + EN_Error.Save, entity: this })); + } + } + , (error: any) => { if (errorcallback) errorcallback(new ResultSubject(error, this, this.typeName + ': ')); } + , completecallback); + } + + + //delete by Id + delete(repositoryService: RepositoryService, loadedcallback: BaseEntityCallBack, errorcallback?: ErrorCallBack, completecallback?: () => void): boolean { + //return this.load_update(EN_HTPPMethod.Delete, dataservice, loadedcallback, errorcallback, extrafilter); + if (!this.isNew()) { + repositoryService.deleteDataById(this.typeName, this.entityId) + .subscribe(() => { + console.log('deleted', this); + if (loadedcallback) loadedcallback(this); + return true; + } + , (error: any) => { if (errorcallback) errorcallback(new ResultSubject(error, this, this.typeName + ': ')); } + , completecallback); + } else this.clear(); + return true; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentity.wrapper.ts b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentity.wrapper.ts new file mode 100644 index 0000000..11d3e5f --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentity.wrapper.ts @@ -0,0 +1,895 @@ +import * as keycode from '@angular/cdk/keycodes'; +import { inject } from '@angular/core'; +import { NgForm } from '@angular/forms'; +import { BehaviorSubject, forkJoin, Subject, Subscription } from 'rxjs'; +import { cnst_CANCEL_ERROR, EN_EntityBeforeSaveCallBackResults, EN_EntityEditingStates } from '../../consts'; +import { IMessageBoxData } from '../../services/globals'; +import { AppLogsService } from '../../services/applogs.service'; +import { RepositoryService } from '../../services/http/repository.service'; +import { HenselTranslateService } from '../../services/localization/hensel-translate.service'; +import { getErrorMessageAsText, now } from '../../utils'; +import { ResultSubject } from '../resultsubject'; +import { BaseEntity, BaseEntityCallBack, ErrorCallBack } from './baseentity'; +import { BaseEntityDetail, BaseEntityDetailList, mdLOAD, mdSAVE } from './baseentitydetaillist'; +import { BaseEntityListWrapper } from './baseentitylist.wrapper'; +import { MatDialogRef } from '../../components/angular-material-index'; + + +export enum EN_SynchronizeListAfter { + Load = 0, + New = 1, + Save = 2 +} + + +export class BaseEntityWrapper { + public static EN_ViewMode = EN_EntityEditingStates.View; + public static EN_NewMode = EN_EntityEditingStates.New; + public static EN_EditMode = EN_EntityEditingStates.Edit; + public static EN_KeyEditMode = EN_EntityEditingStates.EditKey; + public static EN_Idle = EN_EntityEditingStates.Idle; + public entityList: BaseEntityListWrapper; + public delayEntityChange = 500; //delay to set changed flag + public delaySetEditModeCallback = 500; //delay to call callback after edit mode was changed + public delayToReloadedEntity = 2000; //reload entity only after delay since it was loaded last time + public loadedDataExpiresInMs: number = 0; //reload entity before edit if it was loaded longer as loadedDataExpiresInMs, if loadedDataExpiresInMs = 0 - no reload before edit + + public syncEntityListWhenSave: boolean = true; + public syncEntityListWhenLoad: boolean = true; + private _lastChangedTime = 0; //to avoid repeateadly changing of changed during loading/assigning + private _detailForm: NgForm; + protected _entity: T; + + + public errorCallBack: ErrorCallBack; + public loadedCallBack: BaseEntityCallBack; + public completeCallBack: () => void; + public beforeNewCallBack: BaseEntityCallBack; //callback to be called before insert + public beforeSaveCallBack: (entity: BaseEntity) => Promise; //callback to be called before save, returns 0-all ok, continue saving, 1-all ok, break further saving, 2 - error, ignore coninue + public beforeDeleteCallBack: (entity: BaseEntity) => Promise; //callback to be called before save, returns 0-all ok, continue saving, 1-all ok, break further saving, 2 - error, ignore coninue + public isEntityChangedCallBack: (entity: BaseEntity) => boolean; + public isEntityValidCallBack: (entity: BaseEntity) => boolean; + + public detailFormHTMLId: string; + public entityLoaded$: Subject = new Subject(); + + public entityIsLoading$: BehaviorSubject = new BehaviorSubject(false); + public onCheckFormValidInput: (form: NgForm) => boolean; + public get entityIsLoading(): boolean { + return this.entityIsLoading$.value; + } + public set entityIsLoading(value: boolean) { + const wasLoading = this.entityIsLoading; + if (!value && wasLoading || value && !wasLoading) this.entityIsLoading$.next(value); + this.appLogsService.dlog('--- Loading', this.entity.typeName + ': ' + this.entity.entityId + ' == ' + value); + if (!value && wasLoading) this.entityLoaded$.next(); + } + + public indexInList4New: number = -1; //last + + private _keyDownListenerStopped: boolean = false; + public get keyDownListenerStopped(): boolean { + return this._keyDownListenerStopped || + this.detailItems.items.some((item: BaseEntityDetail) => item.baseEntityList ? item.baseEntityList.focusedEntityShadowed?.keyDownListenerStopped : item.baseEntityWrapper.keyDownListenerStopped); + } + public set keyDownListenerStopped(value: boolean) { + this._keyDownListenerStopped = value; + } + + public hierarchyLevel: number = 0; + public confirmationsOn: boolean = true; + public dontShowErrors: boolean = false; + + private _editModeDefault: EN_EntityEditingStates = BaseEntityWrapper.EN_ViewMode; + public get editModeDefault(): EN_EntityEditingStates { + return this._editModeDefault; + } + public set editModeDefault(value: EN_EntityEditingStates) { + if (value !== null && value !== undefined) { + this._editModeDefault = value; + this.resetEditMode(); + } + } + + private _lastLoadedEntityId: number = 0; + private _editMode: EN_EntityEditingStates = this.editModeDefault; + public get editMode(): EN_EntityEditingStates { + return this._editMode; + } + public set editMode(newState: EN_EntityEditingStates) { + if (this.editMode === newState) return; + setTimeout(() => { + this.editModeDirectly = newState; + this.entityWasChanged = false; // to avoid changed state imedeately after going into edit mode (eable/disable buttons trigger form change event too) + if (this.inNotViewMode) this.setFocus4Form(!this.detailFormHTMLId ? 'form_' + this.entity.typeName : this.detailFormHTMLId); + }, 0); //timeout to avoid "change after checked" warning + } + + public set editModeDirectly(newState: EN_EntityEditingStates) { + this._editMode = newState; + this.appLogsService.dlog('--- Editmode', this.entity.typeName + ': ' + this.entityId + ' == ' + newState); + } + + get entitytitle(): string { + const title = this.entity?.entitytitle; + return this.translate.translateString(title); + } + + public canNew: boolean = true; + public canEdit: boolean = true; + public canCancel: boolean = true; + public canDelete: boolean = true; + public dontLoadEntity: boolean = false; + public dontCheckSaveButton: boolean = false; + public dontUpdateEntityDirectly: boolean = false; + public dontInsertEntityDirectly: boolean = false; + + public detailItems: BaseEntityDetailList = new BaseEntityDetailList(); + + private _wasChanged: boolean = false; + private delayedEditsubscription: Subscription; + protected translate: HenselTranslateService; + private loginSubscriptionSave: Subscription; + private loginSubscriptionLoad: Subscription; + + protected appLogsService: AppLogsService; + protected repositoryService: RepositoryService; + + constructor( + protected TEntity: new (source?: BaseEntity) => T, + defaultEditMode?: EN_EntityEditingStates, + appLogsService?: AppLogsService, + repositoryService?: RepositoryService, + ) // + { + this.appLogsService = appLogsService ?? inject(AppLogsService); + this.repositoryService = repositoryService ?? inject(RepositoryService); + this.translate = this.appLogsService.translate; + + if (defaultEditMode !== null && defaultEditMode !== undefined) { + this._editModeDefault = defaultEditMode; + this._editMode = defaultEditMode; + } + + setTimeout(() => { this.entityWasChanged = false; }, 0); //to avoid the changed was set during the initial binding + this._entity = new TEntity(); + } + + public get isNew(): boolean { + return !this.entity || ( + this.entity.entityId === 0 /* because of if this.dontInsertEntityDirectly it can be <0*/ + || this.entity.insertWithIds() && this.entity.entityId < 0 /* or if for insert Id is set explicitely */ + ); + } + + public get inViewMode(): boolean { return this.editModeDefault !== BaseEntityWrapper.EN_ViewMode && !this.inNewMode || this.editMode === BaseEntityWrapper.EN_ViewMode; } + public get inNotViewMode(): boolean { return this.editMode === BaseEntityWrapper.EN_EditMode || this.editMode === BaseEntityWrapper.EN_KeyEditMode || this.editMode === BaseEntityWrapper.EN_NewMode; } + public get inNewKeyEditMode(): boolean { return this.editMode === BaseEntityWrapper.EN_KeyEditMode || this.editMode === BaseEntityWrapper.EN_NewMode; } + public get inNewEditMode(): boolean { return this.editMode === BaseEntityWrapper.EN_EditMode || this.editMode === BaseEntityWrapper.EN_NewMode; } + public get inEditMode(): boolean { return this.editMode === BaseEntityWrapper.EN_EditMode; } + public get inNewMode(): boolean { return this.editMode === BaseEntityWrapper.EN_NewMode; } + public get inKeyEditMode(): boolean { return this.editMode === BaseEntityWrapper.EN_KeyEditMode; } + public onFormChange: (val: any) => boolean; + + public resetEditMode() { + if (this.hierarchyLevel === 0 && this.isNew && this.editModeDefault !== EN_EntityEditingStates.View) return; //this logic is used only for entity wrapper 1st level + this.editMode = this.editModeDefault; + } + + public set entityWasLoaded(finished: boolean) { + this.entityIsLoading = !finished; + if (finished) this.entityWasChanged = false; + } + + // we set false imedeatelely, but true only after entityChangeDelay=def 500 ms were gone, since the last call to set + public set entityWasChanged(changed: boolean) { + if (this.entity) { + this.appLogsService.dlog('--- ' + this.entity.typeName + ' CHANGED: ', changed, ' after ', now() - this._lastChangedTime); + if (!changed || (now() - this._lastChangedTime > this.delayEntityChange)) { + setTimeout(() => this.entity.entityChanged = changed); //to avoid change after check error, because is used in interface onSaveEnabled + this._wasChanged = changed; //to return properly value from this.changed() + } + this._lastChangedTime = now(); + } + } + + public get entityWasChanged() { + return this.entity?.entityChanged || this.detailItems.changed() + || (!!this.isEntityChangedCallBack && this.isEntityChangedCallBack(this.entity)); + } + + public get isValidInput() { + return this.entity?.isValidInput() && this.detailItems.isValidInput() + && (!this.isEntityValidCallBack || this.isEntityValidCallBack(this.entity)); + } + + + public get detailForm(): NgForm { + return this._detailForm; + } + + public set detailForm(value: NgForm) { + this._detailForm = value; + //connect input fields of the detail form with entity change method automatically + if (!this._detailForm) return; + this.detailForm.valueChanges.subscribe((val: any) => this.doFormChange(val)); + this.updateRequired(); + } + + + doFormChange = (val: any) => { + if (!this.onFormChange || !this.onFormChange(val)) { + this.changed(val); + } + } + + + public updateRequired() { + if (!this.detailForm) return; + // to show markup (read) for required fields imediately after a form was initialised, + // but not only after the field was focused + setTimeout(() => { if (this.detailForm?.control) this.detailForm.control.markAllAsTouched(); }); + } + + get entity() { return this._entity; } + + + //just connects UI wrapper with a given enity object + set entity(ent: T | null) { + this.entityWasLoaded = false; + this._entity = ent; + this.entityWasLoaded = true; + } + + //load an entity object on its Id and connects UI wrapper with it + set entityId(id: number) { + // tslint:disable-next-line: curly + if ((!this.entity) || (!this.entity.isRealObject())) { + this._entity = new this.TEntity(); + } + + this.load(id); + } + + get entityId() { return this.entity ? this.entity.entityId : null; } + + + private unsubscribe(subscr: Subscription) { + subscr?.unsubscribe(); + subscr = null; + } + + + public load(entityId: number, _loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void) { + this.entity.entityId = entityId; + + if (!this.loginSubscriptionLoad && this.hierarchyLevel === 0) { + this.loginSubscriptionLoad = this.repositoryService.authService.loginAction$.subscribe((resultObject) => { + if (resultObject.result) { // try one time more + this.load(entityId, _loadedCallBack, _errorCallBack, _completeCallBack); + } else this.unsubscribe(this.loginSubscriptionLoad); + + }); + } else { + if (this.loginSubscriptionLoad) this.unsubscribe(this.loginSubscriptionLoad); // try only one time more + } + + const loadedDetails$: Subject[] = [new Subject()]; + // if (!_loadedCallBack) _loadedCallBack = this.loadedCallBack; + // if (!_errorCallBack) _errorCallBack = this.errorCallBack; + // if (!_completeCallBack) _completeCallBack = this.completeCallBack; + + this.detailItems.prepareObservables(loadedDetails$, mdLOAD); + + forkJoin(loadedDetails$).subscribe(() => { + + this.entityWasLoaded = true; + this.resetEditMode(); + if (this.hierarchyLevel === 0) { + this.appLogsService.dlog('------- master loaded <' + this.entity.typeName + ' ' + this.entity.entityId + '>'); + this.unsubscribe(this.loginSubscriptionLoad); + } + if (_loadedCallBack) _loadedCallBack(this.entity); + if (this.loadedCallBack) this.loadedCallBack(this.entity); + if (this.entityId) { // do check because for empty list focusedEntityShadowed.entityId is set to 0, to clear details + this.entityList?.updateListItem(this.entity); //to update entity if it was chaged in loadedCallBack + } + }, (error: ResultSubject) => { + this.cancelDelayedEditsubscription(); + this.entityIsLoading = false; + if (this.hierarchyLevel === 0) this.appLogsService.error('---!!! master error <' + this.entity.typeName + ' ' + this.entity.entityId + '>:', { error }); + const errorMsg = getErrorMessageAsText(error); + if (errorMsg !== cnst_CANCEL_ERROR) { + if (!this.dontShowErrors) this.errorMessageBox(this.translate.instant('core.error.loading', { value: this.entitytitle }), errorMsg); + if (_errorCallBack) _errorCallBack(error); + if (this.errorCallBack) this.errorCallBack(error); + this.unsubscribe(this.loginSubscriptionLoad); //relogin is not executed - don't need subscription + } + if (_completeCallBack) _completeCallBack(); + if (this.completeCallBack) this.completeCallBack(); + }, () => { + this.entityWasLoaded = true; //important for new mode, because callback loaded in this case is not called + + if (this.hierarchyLevel === 0) this.appLogsService.dlog('------- master loaded completed <' + this.entity.typeName + ' ' + this.entity.entityId + '>'); + if (_completeCallBack) _completeCallBack(); + if (this.completeCallBack) this.completeCallBack(); + }); + + //load entity itself + this.entityWasLoaded = false; + if (this.dontLoadEntity && this.entityList) { + if (this.entityList.items.length > 0 && this.entityId) {//do check because for empty list focusedEntityShadowed.entityId is set to 0, to clear details + this.entity.assign(this.entityList.getItemById(this.entity.entityId)); + + loadedDetails$[0].next(); + //load detail lists + this.detailItems.load(this, loadedDetails$, 1); + loadedDetails$[0].complete(); + } else { + this.clear(); + loadedDetails$[0].complete(); + } + } else { + this.entity.load(this.repositoryService, (entity) => { + this.synchroniseEntityList(EN_SynchronizeListAfter.Load); + loadedDetails$[0].next(); + + //load detail lists, must be in call back + //this.detailItems.load(this, loadedDetails$, 1); + }, (error: any) => { + if (this.hierarchyLevel > 0) { + loadedDetails$[0].next(); + loadedDetails$[0].complete(); //w/o complete is passed no next + //error in details does not mean error in main + } else loadedDetails$[0].error(error); + // this.entityWasLoaded = false; + }, () => { + //load detail lists, must be in call back + this.detailItems.load(this, loadedDetails$, 1); + loadedDetails$[0].complete(); + } + ); + } + } + + + public changed(event?: any): boolean { + this.entityWasChanged = true; + return this._wasChanged; //can be the case that set it to true has no affect, because of delay after it was set to false + } + + isFormValidInput() { + return ((this.onCheckFormValidInput && this.onCheckFormValidInput(this.detailForm)) || (!this.detailForm || (this.detailForm && !this.detailForm.invalid + /* valid was changed against !invalid, because valid = status==VALID, but status for disabled is DISABLED, i.e. disabled -> !valid*/ + ))) && this.isValidInput; + } + + public enabledSaveButton() { + return this.isFormValidInput() && this.inNotViewMode && (this.entityWasChanged || this.dontCheckSaveButton); + } + public enabledDeleteButton() { return this.canDelete && (!this.isNew || this.dontUpdateEntityDirectly) && !this.entityIsLoading && this.inViewMode; } + public enabledNewButton() { return this.canNew && !this.entityIsLoading && this.inViewMode /*&& !this.isNew && !this.entityWasChanged */; } + public enabledEditButton() { return this.canEdit && (!this.isNew || this.dontInsertEntityDirectly) && !this.entityIsLoading && this.inViewMode; } + public enabledCancelButton() { + return this.canCancel + && ( + this.editModeDefault === BaseEntityWrapper.EN_ViewMode && this.inNotViewMode || + this.editModeDefault !== BaseEntityWrapper.EN_ViewMode && ( + this.inEditMode && this.entityWasChanged || + this.inNewMode && (!this.entityList || this.entityList.focusedItem || //if there is a binded list with the selected item, then load it with cancel + this.entityWasChanged) //or clear if there was changed something + ) + ) + ///*(this.isNew || this.entityWasChanged || this.editModeDefault === BaseEntityWrapper.EN_ViewMode) && */ this.inNotViewMode + && !this.entityIsLoading; + } + public enabledCopyButton() { return this.canNew && (!this.isNew || this.dontInsertEntityDirectly) && !this.entityIsLoading && this.inViewMode; } + + + public async saveExcludingFields(excludeFields: string, _loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void, useSuffixInsteadEntityId?: string) { + this.entity.excludeFieldFromUpdate(excludeFields); + this.save(_loadedCallBack, _errorCallBack + , () => { + this.entity.includeFieldForUpdate(excludeFields); + if (_completeCallBack) _completeCallBack(); + } + , useSuffixInsteadEntityId + ); + } + + + public async saveAsync(): Promise { + return new Promise((resolve, reject) => this.save(null, () => resolve(false), () => resolve(true))); + } + + + public async saveAnywayAsync(): Promise { + return new Promise((resolve, reject) => this.saveAnyway(null, () => resolve(false), () => resolve(true))); + } + + + public saveAnyway(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void, useSuffixInsteadEntityId?: string) { + if (!this.entity) return; + this.save(_loadedCallBack, _errorCallBack, _completeCallBack, useSuffixInsteadEntityId, true); + } + + + public async save(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void, useSuffixInsteadEntityId?: string, dontCheckSaveButton: boolean = false) { + + if (this.entity && (dontCheckSaveButton || this.enabledSaveButton())) { + const savedDetails$: Subject[] = [new Subject()]; + const _isNew = this.isNew; + + let resBeforeSaveCallBack: EN_EntityBeforeSaveCallBackResults = EN_EntityBeforeSaveCallBackResults.Ok_Continue; + // tslint:disable-next-line: no-bitwise + const doBreak: boolean = this.beforeSaveCallBack && ((resBeforeSaveCallBack = await this.beforeSaveCallBack(this.entity)) & EN_EntityBeforeSaveCallBackResults.Ok_Break) !== 0; + if (!doBreak) { //saves main base entity only after all details entities/entity lists are successfuly saved + this.detailItems.prepareObservables4SaveAutonome(savedDetails$, mdSAVE, () => this.saveEntity(savedDetails$[0], useSuffixInsteadEntityId)); + } + + + forkJoin(savedDetails$).subscribe( + () => { + this.unsubscribe(this.loginSubscriptionSave); + this.resetEditMode(); + if (!this.synchroniseEntityList(_isNew ? EN_SynchronizeListAfter.New : EN_SynchronizeListAfter.Save)) this._cancel(); //don't change order here!!! + if (_loadedCallBack) _loadedCallBack(this.entity); + this.appLogsService.dlog('------- master saved <' + this.entity.typeName + ' ' + this.entity.entityId + '>'); + this.entityList?.updateListItem(this.entity); //to update entity if it was chaged in loadedCallBack + this.entityWasChanged = false; + }, (error: ResultSubject) => { + this.entityWasChanged = true; + this.appLogsService.error('---!!! master error <' + this.entity.typeName + '>:', { error }); + const errorMsg = getErrorMessageAsText(error); + if (errorMsg !== cnst_CANCEL_ERROR) { + if (!this.dontShowErrors) this.errorMessageBox(this.translate.instant('core.error.saving', { value: this.entitytitle }), errorMsg); + if (_errorCallBack) _errorCallBack(error); + this.unsubscribe(this.loginSubscriptionSave); //relogin is not executed - don't need subscription + } + if (_completeCallBack) _completeCallBack(); + }, () => { + this.appLogsService.dlog('------- master saved completed <' + this.entity.typeName + ' ' + this.entity.entityId + '>'); + if (_completeCallBack) _completeCallBack(); + } + ); + + if (doBreak) { + // tslint:disable-next-line: no-bitwise + const resOk = (resBeforeSaveCallBack & EN_EntityBeforeSaveCallBackResults.Error_Continue) === 0; + if (resOk) { + savedDetails$[0].next(); + savedDetails$[0].complete(); + } else savedDetails$[0].error({ errMsg: cnst_CANCEL_ERROR } as ResultSubject); //raise error callback, but without message box + return; + } + + if (!this.loginSubscriptionSave && this.hierarchyLevel === 0) { + this.loginSubscriptionSave = this.repositoryService.authService.loginAction$.subscribe((resultObject) => { + if (resultObject.result) { // try one time more + this.save(_loadedCallBack, _errorCallBack, _completeCallBack, useSuffixInsteadEntityId); + } else this.unsubscribe(this.loginSubscriptionSave); + }); + } else { + if (this.loginSubscriptionSave) this.unsubscribe(this.loginSubscriptionSave); // try only one time more + } + + //if we have details and a new main entity, we should insert it at first, get id, then save all details, and then update main entity + const mainObservable$ = savedDetails$[0]; + if (!this.detailItems.isEmpty4Save && this.isNew) { + const mainInserted$ = new Subject(); + this.saveEntity(mainInserted$, useSuffixInsteadEntityId); + mainInserted$.subscribe({ + next: () => { + //save detail Items + this.detailItems.batchSave(this); + }, error: (error: any) => { + mainObservable$.error(error); + } + }); + } else { + //save detail Items + this.detailItems.batchSave(this); + + //save entity itself - no details objects + if (this.detailItems.isEmpty4Save) this.saveEntity(mainObservable$, useSuffixInsteadEntityId); + } + + } else { //to process sub details, when main detail entity is saved, it must call _completeCallBack() anyway + if ((this.hierarchyLevel > 0) && _loadedCallBack) _loadedCallBack(this.entity); + this.appLogsService.dlog('!! completed saving main' + this.entity.typeName); + if (_completeCallBack) _completeCallBack(); + this.resetEditMode(); + } + } + + + private saveEntity(savedDetails$: Subject, useSuffixInsteadEntityId: string) { + if (!useSuffixInsteadEntityId && this.entityList && (this.isNew && this.dontInsertEntityDirectly || !this.isNew && this.dontUpdateEntityDirectly)) { + // -- we don't save details data directly, but save the connected list and data should be saved with this.entityList.save, entityId will be the minimal negative + if (this.entity.entityId === 0) { + this.entity.entityId = this.entityList.items.reduce((min: number, entity: BaseEntity) => min < entity.entityId ? min : entity.entityId, 0) - 1; + } + this.entityWasChanged = true; + this.appLogsService.dlog('!! next saving main: ' + this.entity.typeName); + savedDetails$.next(); + this.appLogsService.dlog('!! completed saving main: ' + this.entity.typeName); + savedDetails$.complete(); + } else { + this.entity.save(this.repositoryService, + (entity) => { + // this.synchroniseEntityList(); //!!! check + // this.entityWasChanged = false; + // if (loadedcallback) loadedcallback(entity); + this.appLogsService.dlog('!! next saving main: ' + this.entity.typeName); + savedDetails$.next(); + }, + (error: any) => savedDetails$.error(error), + () => { + this.appLogsService.dlog('!! completed saving main: ' + this.entity.typeName); + savedDetails$.complete(); + }, + useSuffixInsteadEntityId + ); + } + } + + + public synchroniseEntityList(calledAfterSave: EN_SynchronizeListAfter, entityList?: BaseEntityListWrapper): boolean { + if (!entityList) entityList = this.entityList; + if (!entityList + || (calledAfterSave === EN_SynchronizeListAfter.New || calledAfterSave === EN_SynchronizeListAfter.Save) && !this.syncEntityListWhenSave + || calledAfterSave === EN_SynchronizeListAfter.Load && !this.syncEntityListWhenLoad) { + return false; + } + if (calledAfterSave !== EN_SynchronizeListAfter.Load && entityList.reloadAfterItemUpdate) { + entityList.load(); + entityList.focusedItemId = this.entity.entityId; + } else entityList.updateListItem(this.entity, this.indexInList4New, calledAfterSave === EN_SynchronizeListAfter.New); + return true; + } + + + public clear(useNull: boolean = false) { + this.entity.clear(useNull); + this.detailItems.clear(useNull); + } + + + public cancelWithSave(_saveCallBack: () => void, _loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack) { + this.cancel(_loadedCallBack, _errorCallBack, null, null, _saveCallBack); + } + + + public cancel(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void, useSuffixInsteadEntityId?: string, _saveCallBack?: () => void) { + if (!this.confirmationsOn || !this.enabledSaveButton() || !this.entityWasChanged) { //only if something was changed and form is valid + setTimeout(() => this._cancel(_loadedCallBack, _errorCallBack)); + } else { + this.confirmMessageBoxYesNoCancel( + // 'Bearbeitungsabbruch von ' + this.entitytitle, + this.translate.instant('core.msgbox.header.cancel', { value: this.entitytitle }), + // `${this.entitytitle} wurde geändert. Sollen Änderungen gespeichert werden?`, + this.translate.instant('core.msgbox.body.cancel', { value: this.entitytitle }), + + () => { + if (_saveCallBack) _saveCallBack(); + else this.save(_loadedCallBack, _errorCallBack, _completeCallBack, useSuffixInsteadEntityId); + }, + () => { + if (_loadedCallBack) _loadedCallBack(this.entity); //to call close for popupdialogs before canceling starts + this._cancel(null, _errorCallBack); + } + ); + } + } + + + public _cancel(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack): boolean { + // if (!this.enabledCancelButton()) return false; //cancel must work anyway, even if viemode + if (this.entityWasChanged || this.isNew) { + + + //this.detailItems.cancel(); + if (this.isNew) { + /*if (this.entityList && this.entityList.focusedItemId) { + this.entityId = this.entityList.focusedItemId; + } else*/ + if (this._lastLoadedEntityId) this.entityId = this._lastLoadedEntityId; + else { + this.detailItems.cancel(); + this.entity.clear(); + if (this.hierarchyLevel === 0 && this.editModeDefault !== EN_EntityEditingStates.View) this.new(); //if always in edit mode and there is no items in the list the mode stays in new mode + } + } else if (this.entity) { + this.reloadAnyway((entity: BaseEntity) => { + this.resetEditMode(); + if (_loadedCallBack) _loadedCallBack(this.entity); + }, _errorCallBack); + return true; + } + } + this.resetEditMode(); + if (_loadedCallBack) _loadedCallBack(this.entity); + return true; + } + + + public async deleteAsync(): Promise { + return new Promise((resolve, reject) => this.save(() => resolve(true), () => resolve(false) /* complete is called anyway */)); + } + + + public async delete(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack) { + if (!this.confirmationsOn) return this._delete(_loadedCallBack, _errorCallBack); + this.confirmMessageBoxYesNo( + // 'Löschen von ' + this.entitytitle, + this.translate.instant('core.msgbox.header.delete', { value: this.entitytitle }), + // `Soll ${this.entitytitle} gelöscht werden?`, + this.translate.instant('core.msgbox.body.delete', { value: this.entitytitle }), + () => this._delete(_loadedCallBack, _errorCallBack), 1); + } + + private async _delete(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack) { + if (this.entity && this.enabledDeleteButton()) { + let resbeforeDeleteCallBack: EN_EntityBeforeSaveCallBackResults = EN_EntityBeforeSaveCallBackResults.Ok_Continue; + // tslint:disable-next-line: no-bitwise + if (this.beforeDeleteCallBack && ((resbeforeDeleteCallBack = await this.beforeDeleteCallBack(this.entity)) & EN_EntityBeforeSaveCallBackResults.Ok_Break) !== 0) { + // tslint:disable-next-line: no-bitwise + if ((resbeforeDeleteCallBack & EN_EntityBeforeSaveCallBackResults.Error_Continue) === 0) { + if (_loadedCallBack) _loadedCallBack(this.entity); + } else { + if (_errorCallBack) _errorCallBack({ errMsg: cnst_CANCEL_ERROR } as ResultSubject); + } + return; + } + + let loginSubscription: Subscription; + if (this.hierarchyLevel === 0) { + loginSubscription = this.repositoryService.authService.loginAction$.subscribe((resultObject) => { + if (resultObject.result) { // try one time more + loginSubscription?.unsubscribe(); + this._delete(_loadedCallBack, _errorCallBack); + } + }); + } + + + if (this.dontUpdateEntityDirectly) { + this.resetEditMode(); + if (this.entityList) this.entityList.deleteListItem(this.entity, true); + } else { + return this.entity.delete(this.repositoryService, + (entity) => { + this.resetEditMode(); + if (this.entityList) this.entityList.deleteListItem(this.entity, false); + if (_loadedCallBack) _loadedCallBack(entity); + } + , (error: ResultSubject) => { + this.appLogsService.error('---!!! delete error <' + this.entity.typeName + '>:', { error }); + const errorMsg = getErrorMessageAsText(error); + if (!this.dontShowErrors && errorMsg !== cnst_CANCEL_ERROR) { + this.errorMessageBox(this.translate.instant('core.error.deleting', { value: this.entitytitle }), errorMsg); + } + if (errorMsg !== cnst_CANCEL_ERROR && _errorCallBack) _errorCallBack(error); + }); + } + } else { + if (_loadedCallBack) _loadedCallBack(this.entity); + } + } + + + public editKey(setEditModedirectly: boolean = false, callBack?: BaseEntityCallBack): T { + return this._edit(BaseEntityWrapper.EN_KeyEditMode, setEditModedirectly, callBack); + } + + + + public edit(setEditModedirectly: boolean = false, callBack?: BaseEntityCallBack): T { + return this._edit(BaseEntityWrapper.EN_EditMode, setEditModedirectly, callBack); + } + + + public _edit(editMode: EN_EntityEditingStates, setEditModedirectly: boolean = false, callBack?: BaseEntityCallBack): T { + if (this.enabledEditButton()) { + this.appLogsService.dlog('--- Edit, since last loading expired ms', now() - (this.entity.lastLoaded || 0)); + if (this.loadedDataExpiresInMs && ((now() - (this.entity.lastLoaded || 0)) > this.loadedDataExpiresInMs)) { + this.reload(() => this._setEditMode(setEditModedirectly, editMode, callBack)); + } else this._setEditMode(setEditModedirectly, editMode, callBack); + return this.entity; + } else return null; + } + + + private _setEditMode(setEditModedirectly: boolean, editMode: EN_EntityEditingStates, callBack: BaseEntityCallBack) { + if (setEditModedirectly) { + this.editModeDirectly = editMode; + if (callBack) callBack(this.entity); + } else { + this.editMode = editMode; + setTimeout(() => { + if (callBack) callBack(this.entity); + }, this.delaySetEditModeCallback); + } + } + + + public delayedEdit(entityId2Edit: number, editFn?: () => any) { + if (entityId2Edit === this.entityId) { + if (editFn) editFn(); + else this.edit(); + } else { + if (!this.delayedEditsubscription) { + this.delayedEditsubscription = this.entityLoaded$.subscribe(() => { + this.cancelDelayedEditsubscription(); + if (editFn) editFn(); + else this.edit(); + }); + } + } + } + + + private cancelDelayedEditsubscription() { + this.delayedEditsubscription?.unsubscribe(); + this.delayedEditsubscription = null; + } + + + private setfocus4ElementsOf(qualifiedName: keyof HTMLElementTagNameMap, frm: HTMLElement): boolean { + const elements = frm?.getElementsByTagName(qualifiedName); + let focusElement = null; + if (elements) { + for (let inx = 0; inx < elements.length; inx++) { + const el = elements[inx]; + if (!(el).disabled && !el.hidden && el.autofocus /*attributes.getNamedItem('autofocus')*/) { + if (!focusElement) focusElement = el; + if ((el).required && !(el).value) { + focusElement = el; + break; + } + } + } + setTimeout(() => { + focusElement?.focus(); + }, 300); + } + return !!focusElement; + } + + + public setFocus4Form(formId: string) { + setTimeout(() => { + const frm = document.getElementById(formId); + if (!this.setfocus4ElementsOf('input', frm)) this.setfocus4ElementsOf('button', frm); + }); + } + + + private _NewCopy(copy: boolean): T { + if (this.editMode === this.editModeDefault || this.editMode === BaseEntityWrapper.EN_NewMode) //we use new() to call everytime before new + { + this._lastLoadedEntityId = this.entityId; + + this.editMode = BaseEntityWrapper.EN_NewMode; + if (!copy) this.entityId = 0; + if (this.beforeNewCallBack) this.beforeNewCallBack(this.entity); + if (copy) this.entity.entityId = 0; + + if (copy) setTimeout(() => this.entity.entityChanged = true, 0); + + this.detailItems.new(); + this.updateRequired(); + return this.entity; + } else return null; + } + + + public new(): T { return this._NewCopy(false); } + public copy(): T { return this._NewCopy(true); } + + public loadDetails(onlyDetailItem: BaseEntityListWrapper | BaseEntityWrapper) { + if (this.detailItems) this.detailItems.load(this, null, 0, onlyDetailItem); + } + + + public reloadAnyway(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void) { + this.entity.lastLoaded = 0; //to reload independend from was loaded the last time + this.reload(_loadedCallBack, _errorCallBack, _completeCallBack); + } + + + public reload(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void) { + const ignoreInterval = this.delayToReloadedEntity; + if ((now() - (this.entity.lastLoaded || 0)) > ignoreInterval) { + this.appLogsService.dlog(`--- Reload for ${this.entity.entitytitle} is executed: since last loading expired ${now() - (this.entity.lastLoaded || 0)} > ${ignoreInterval}`); + this.load(this.entityId, _loadedCallBack, _errorCallBack, _completeCallBack); //load new + } else { + this.appLogsService.dlog(`--- Reload is ignored: since last loading expired ${now() - (this.entity.lastLoaded || 0)} <= ${ignoreInterval}`); + this.entityWasLoaded = true; + if (_loadedCallBack) _loadedCallBack(this.entity); + if (_completeCallBack) _completeCallBack(); + } + } + + + public hardReload(_loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void) { + const prevDontLoadEntity = this.dontLoadEntity; + this.dontLoadEntity = false; + this.load(this.entityId, (entity?: BaseEntity) => { + this.dontLoadEntity = prevDontLoadEntity; + if (_loadedCallBack) _loadedCallBack(entity); + }, _errorCallBack, _completeCallBack); //load new + } + + + public shortcutsHandler(event: KeyboardEvent, + saveCallBack: () => void = null, _cancelCallBack: () => void = null, _newCallBack: () => void = null, _editCallBack: () => void = null) { + if (!this.keyDownListenerStopped) { + if (event.ctrlKey && !event.shiftKey && !event.altKey) { + // tslint:disable-next-line: deprecation + switch (event.which) { + case keycode.E: // Ctrl + e + event.stopPropagation(); + if (_editCallBack) _editCallBack(); + else this.edit(); + return false; //processed + case keycode.S: // Ctrl + s + event.stopPropagation(); + if (saveCallBack) saveCallBack(); + else this.save(); + return false; //processed + case keycode.N: // Ctrl + n + event.stopPropagation(); + if (_newCallBack) _newCallBack(); + else this.new(); + return false; //processed + } + } else { + if (!event.ctrlKey && !event.shiftKey && !event.altKey) { + // tslint:disable-next-line: deprecation + switch (event.which) { + case keycode.ESCAPE: // ESC + event.stopPropagation(); + if (_cancelCallBack) _cancelCallBack(); + else this.cancel(); + return false; //processed event.preventDefault()-the same, event.stopPropagation(); -> globally + } + } + } + } + return true; //default processing + } + + + showMessageBox(messageBoxData: IMessageBoxData): MatDialogRef { + this.keyDownListenerStopped = true; + return this.appLogsService.showMessageBox(messageBoxData, () => this.keyDownListenerStopped = false); + } + + informationMessageBox(caption: string, message: string, callBack?: () => void): MatDialogRef { + this.keyDownListenerStopped = true; + return this.appLogsService.informationMessageBox(caption, message, () => { this.keyDownListenerStopped = false; if (callBack) callBack(); }); + } + + errorMessageBox(caption: string, message: string, okCallBack?: () => void): MatDialogRef { + this.keyDownListenerStopped = true; + return this.appLogsService.errorMessageBox(caption, message, () => { this.keyDownListenerStopped = false; if (okCallBack) okCallBack(); }); + } + + warningMessageBox(caption: string, message: string, okCallBack?: () => void): MatDialogRef { + this.keyDownListenerStopped = true; + return this.appLogsService.warningMessageBox(caption, message, () => { this.keyDownListenerStopped = false; if (okCallBack) okCallBack(); }); + } + + confirmMessageBoxYesNo(caption: string, message: string, yesCallBack: () => void, defaultButtonInx: number = 0): MatDialogRef { + this.keyDownListenerStopped = true; + return this.appLogsService.confirmMessageBoxYesNo(caption, message, yesCallBack, () => this.keyDownListenerStopped = false, defaultButtonInx); + } + + confirmMessageBoxYesNoCancel(caption: string, message: string, yesCallBack: () => void, noCallBack: () => void, defaultButtonInx: number = 0): MatDialogRef { + this.keyDownListenerStopped = true; + return this.appLogsService.confirmMessageBoxYesNoCancel(caption, message, yesCallBack, noCallBack, () => this.keyDownListenerStopped = false, defaultButtonInx); + } + + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentitydetaillist.ts b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentitydetaillist.ts new file mode 100644 index 0000000..01eb5e7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentitydetaillist.ts @@ -0,0 +1,265 @@ +import { BaseEntity, ErrorCallBack } from '../generics/baseentity'; +import { BaseEntityListWrapper } from './baseentitylist.wrapper'; +import { BaseEntityWrapper } from './baseentity.wrapper'; +import { forkJoin, Subject } from 'rxjs'; +import { EN_EntityEditingStates } from '../../consts'; + +export const mdLOAD: number = 1; +export const mdSAVE: number = 2; + +export interface BaseEntityDetail { + baseEntityList?: BaseEntityListWrapper; + baseEntityWrapper?: BaseEntityWrapper; + callBack?: (entity: BaseEntity[] | BaseEntity) => void; + errorCallBack?: ErrorCallBack; + completeCallBack?: () => void; + filterKeyField: string; + masterField4Filter: string; + mode: number; +} + + +export class BaseEntityDetailList { + public items: BaseEntityDetail[] = []; + + public observList$: Subject[] = []; + + public get isEmpty(): boolean { + return this.items.length === 0; + } + + + public get isEmpty4Save(): boolean { + return this.observList$.length === 0; + + } + + + private _register(_mode: number, _baseEntityList: BaseEntityListWrapper, _baseEntityWrapper: BaseEntityWrapper, _filterKeyField: string | string[], + _callBack?: (entity: BaseEntity[] | BaseEntity) => void, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void): BaseEntityDetail { + + let filterKeyField: string = null; + let masterField4Filter: string = null; + if (Array.isArray(_filterKeyField)) { + filterKeyField = _filterKeyField[0]; + if (_filterKeyField.length > 1) masterField4Filter = _filterKeyField[1]; + } else filterKeyField = _filterKeyField; + const item: BaseEntityDetail = { + baseEntityList: _baseEntityList, + baseEntityWrapper: _baseEntityWrapper, + filterKeyField: filterKeyField, + masterField4Filter: masterField4Filter, + callBack: _callBack, + errorCallBack: _errorCallBack, + completeCallBack: _completeCallBack, + mode: _mode + }; + this.items.push(item); + if (_baseEntityWrapper) { + _baseEntityWrapper.hierarchyLevel++; + _baseEntityWrapper.editModeDefault = EN_EntityEditingStates.Edit; //to saving with main automatically + } + if (_baseEntityList) _baseEntityList.hierarchyLevel++; + return item; + } + + + public register(_baseEntityList: BaseEntityListWrapper, _baseEntityWrapper: BaseEntityWrapper, _filterKeyField: string | string[], + _callBack?: (entity: BaseEntity[] | BaseEntity) => void, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void): BaseEntityDetail { + return this._register(mdLOAD + mdSAVE, _baseEntityList, _baseEntityWrapper, _filterKeyField, _callBack, _errorCallBack, _completeCallBack); + } + + + public register4Load(_baseEntityList: BaseEntityListWrapper, _baseEntityWrapper: BaseEntityWrapper, _filterKeyField: string | string[], + _callBack?: (entity: BaseEntity[] | BaseEntity) => void, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void): BaseEntityDetail { + return this._register(mdLOAD, _baseEntityList, _baseEntityWrapper, _filterKeyField, _callBack, _errorCallBack, _completeCallBack); + } + + + public register4Save(_baseEntityList: BaseEntityListWrapper, _baseEntityWrapper: BaseEntityWrapper, _filterKeyField: string | string[], + _callBack?: (entity: BaseEntity[] | BaseEntity) => void, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void): BaseEntityDetail { + return this._register(mdSAVE, _baseEntityList, _baseEntityWrapper, _filterKeyField, _callBack, _errorCallBack, _completeCallBack); + } + + + public prepareObservables(observList$: Subject[], mode: number) { + this.items.forEach((item: BaseEntityDetail) => { + // tslint:disable-next-line: no-bitwise + if (item.mode & mode) observList$.push(new Subject()); + }); + } + + + public prepareObservables4SaveAutonome(_observList$: Subject[], mode: number, callBack: () => void) { + this.observList$ = []; + this.prepareObservables(this.observList$, mode); + if (this.observList$.length === 0) return; + const observListAutonome$: Subject = new Subject(); + _observList$.push(observListAutonome$); + forkJoin(this.observList$).subscribe( + () => { + // console.log('******Details next'); + if (callBack) callBack(); + observListAutonome$.next(); + }, (error: any) => observListAutonome$.error(error) + , () => { + // console.log('******Details complete'); + observListAutonome$.complete(); + } + ); + } + + + public new() { + this.items.forEach((list: BaseEntityDetail) => list.baseEntityList ? list.baseEntityList.clear() : list.baseEntityWrapper.new()); + } + + + public clear(useNull: boolean = false) { + this.items.forEach((list: BaseEntityDetail) => { + if (list.baseEntityList) list.baseEntityList.clear(); + else if (list.baseEntityWrapper.entity) list.baseEntityWrapper.entity.clear(useNull); + }); + } + + + public cancel() { + this.items.forEach((list: BaseEntityDetail) => { + if (list.baseEntityList) list.baseEntityList.clear(); + else { + list.baseEntityWrapper.resetEditMode(); + if (list.baseEntityWrapper.entity) list.baseEntityWrapper.entity.clear(); + // list.baseEntityWrapper.cancel(); + } + }); + } + + + public changed(): boolean { + return this.items.some((list: BaseEntityDetail) => list.baseEntityList ? list.baseEntityList.changed : list.baseEntityWrapper.entityWasChanged); + } + + + public isValidInput(): boolean { + return this.items.every((list: BaseEntityDetail) => list.baseEntityList ? list.baseEntityList.isValidInput : list.baseEntityWrapper.isValidInput); + } + + + public load(masterEntityWrapper: BaseEntityWrapper, observList$?: Subject[], baseIndex: number = 0, onlyDetailItem: BaseEntityListWrapper | BaseEntityWrapper = null) { + // tslint:disable-next-line: no-bitwise + this.items.filter(x => (x.mode & mdLOAD)).forEach((item: BaseEntityDetail, index: number) => { + const indexObservable = index + baseIndex; + // observList$.push(new Subject()); + if (masterEntityWrapper.entityId) { + if (item.baseEntityList && (!onlyDetailItem || onlyDetailItem === item.baseEntityList)) { + if (item.filterKeyField && item.baseEntityList.filter) item.baseEntityList.filter[item.filterKeyField] = masterEntityWrapper.entity[item.masterField4Filter ?? 'entityId']; + item.baseEntityList.load( + (entityList: BaseEntity[]) => { + console.log('!! next load detail No.' + indexObservable + ': ' + (item.baseEntityList ? item.baseEntityList.translate.instant(item.baseEntityList._listName) : item.baseEntityWrapper.entity.typeName)); + if (item.callBack) item.callBack(entityList); + if (observList$) observList$[indexObservable].next(); + }, (error: any) => { + if (item.errorCallBack) item.errorCallBack(error); + if (observList$) observList$[indexObservable].error(error); + }, () => { + console.log('!! complete load detail No.' + indexObservable + ': ' + (item.baseEntityList ? item.baseEntityList.translate.instant(item.baseEntityList._listName) : item.baseEntityWrapper.entity.typeName)); + if (item.completeCallBack) item.completeCallBack(); + if (observList$) observList$[indexObservable].complete(); + } + ); + } else if (item.baseEntityWrapper && (!onlyDetailItem || onlyDetailItem === item.baseEntityWrapper)) { + item.baseEntityWrapper.load(masterEntityWrapper.entity[item.filterKeyField ?? 'entityId'], + (entity: BaseEntity) => { + console.log('!! next load detail No.' + indexObservable + ': ' + (item.baseEntityList ? item.baseEntityList.translate.instant(item.baseEntityList._listName) : item.baseEntityWrapper.entity.typeName)); + if (item.callBack) item.callBack(entity); + if (observList$) observList$[indexObservable].next(); + }, (error: any) => { + if (item.errorCallBack) item.errorCallBack(error); + if (observList$) observList$[indexObservable].error(error); + }, () => { + console.log('!! complete load detail No.' + indexObservable + ': ' + (item.baseEntityList ? item.baseEntityList.translate.instant(item.baseEntityList._listName) : item.baseEntityWrapper.entity.typeName)); + if (item.completeCallBack) item.completeCallBack(); + if (observList$) observList$[indexObservable].complete(); + } + ); + } + } else { + if (item.baseEntityList) item.baseEntityList.clear(); + else item.baseEntityWrapper.new(); + if (observList$) observList$[indexObservable].next(); + if (observList$) observList$[indexObservable].complete(); + } + }); + } + + + private itemSave(masterEntityWrapper: BaseEntityWrapper, item: BaseEntityDetail, callback: () => void, errorcallback: (error: any) => void, completecallback: () => void) { + if (item.baseEntityList) { + item.baseEntityList.items.forEach(it => { + if (it.isNew()) it[item.filterKeyField] = masterEntityWrapper.entity[item.masterField4Filter ?? 'entityId']; + }); + item.baseEntityList.save( + () => { + if (item.callBack) item.callBack(item.baseEntityList.items); + if (callback) callback(); + }, + (error: any) => { + if (item.errorCallBack) item.errorCallBack(item.baseEntityList.items); + if (errorcallback) errorcallback(error); + }, + () => { + if (item.completeCallBack) item.completeCallBack(); + if (completecallback) completecallback(); + } + ); + } else { + if (item.baseEntityWrapper.isNew) item.baseEntityWrapper.entity[item.filterKeyField] = masterEntityWrapper.entity[item.masterField4Filter ?? 'entityId']; + item.baseEntityWrapper.save( + () => { + if (item.callBack) item.callBack(item.baseEntityWrapper.entity); + if (callback) callback(); + }, + (error: any) => { + if (item.errorCallBack) item.errorCallBack(item.baseEntityWrapper.entity); + if (errorcallback) errorcallback(error); + }, + () => { + if (item.completeCallBack) item.completeCallBack(); + if (completecallback) completecallback(); + } + ); + } + } + + + public batchSave(masterEntityWrapper: BaseEntityWrapper) { + this.save(masterEntityWrapper, this.observList$, 0); + } + + + public save(masterEntityWrapper: BaseEntityWrapper, observList$: Subject[], baseIndex: number) { + // tslint:disable-next-line: no-bitwise + this.items.filter(x => x.mode & mdSAVE).forEach((item: BaseEntityDetail, index: number) => { + const indexObservable = index + baseIndex; + if (masterEntityWrapper.entityId) { //details list can be saved only if id>0 + this.itemSave(masterEntityWrapper, item, + () => { + console.log('!! next save detail No.' + indexObservable + ': ' + (item.baseEntityList ? item.baseEntityList.translate.instant(item.baseEntityList._listName) : item.baseEntityWrapper.entity.typeName)); + observList$[indexObservable].next(); + }, + (error: any) => observList$[indexObservable].error(error), + () => { + console.log('!! complete save detail No.' + indexObservable + ': ' + (item.baseEntityList ? item.baseEntityList.translate.instant(item.baseEntityList._listName) : item.baseEntityWrapper.entity.typeName)); + observList$[indexObservable].complete(); + } + ); + } else { + if (item.baseEntityList) item.baseEntityList.clear(); + else item.baseEntityWrapper.new(); + observList$[indexObservable].next(); + observList$[indexObservable].complete(); + } + }); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentityfilter.ts b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentityfilter.ts new file mode 100644 index 0000000..354bc26 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentityfilter.ts @@ -0,0 +1,129 @@ +import * as Utils from '../../utils'; +import { EN_DropDownConst4Filter } from '../../consts'; +//Date format for dates in Web API + +export class BaseFilter { + filterPrefix: string = ''; + alwaysUsefilterPrefix: boolean = false; + useObjectFilter: boolean = true; + + + public onPrepare: (retFilter: BaseFilter) => void; + protected dontConsiderFields = ',filterPrefix,alwaysUsefilterPrefix,dontConsiderFields,useObjectFilter,onPrepare,dontResetFields,'; + + public dontResetFields = ''; + + public constructor(filterPrefix: string = '', init?: Partial) { + this.filterReset(); + if (init) { Object.assign(this, init); } + this.filterPrefix = filterPrefix; + } + + + public isFieldEmpty(fldName: string): boolean { + let isEmpty: boolean; + const obj: any = this[fldName]; + isEmpty = !obj && !(typeof obj === 'boolean' && obj === false); + if (!isEmpty) { + if (obj instanceof Array) isEmpty = obj.length === 0; + else { + switch (typeof obj) { + case 'number': + isEmpty = (obj === EN_DropDownConst4Filter.AllValueInt); + break; + case 'string': + isEmpty = (obj === EN_DropDownConst4Filter.AllValueString); + break; + } + } + } + return isEmpty; + } + + + public initField(fldName: string) { + if (!this.isFieldEmpty(fldName)) { + if (this[fldName] instanceof Array) this[fldName] = []; + else { + switch (typeof this[fldName]) { + // case 'number': + // Object.assign(this, { [fldName]: 0 }); + // break; + case 'string': + Object.assign(this, { [fldName]: '' }); + break; + default: + this[fldName] = null; + break; + } + } + } + } + + + protected isServiceField(fldName: string): boolean { + return (',' + this.dontConsiderFields + ',').indexOf(',' + fldName + ',') > -1; + } + + + protected isFixedField(fldName: string): boolean { + return (',' + this.dontResetFields + ',').indexOf(',' + fldName + ',') > -1; + } + + + public getFilterURL(): any { + const retFilter: BaseFilter = Object.assign({}, this); + if (this.doPrepare) this.doPrepare(retFilter); + let retVal = ''; + // tslint:disable-next-line: forin + for (const prop in retFilter) { + if (!retFilter.isServiceField(prop) && retFilter.propertyIsEnumerable(prop) && !retFilter.isFieldEmpty(prop)) { + let curval: string = ''; + const obj = retFilter[prop]; + + if (obj instanceof Array) { + if (obj.length > 0) curval = obj.join(); + } else curval = Utils.toStringConsiderDateFormat(obj); + if (curval) retVal += `&${prop}=${curval}`; + } + } + if (retVal.length) retVal = retVal.substring(1); + if (retVal.length) retVal = retFilter.filterPrefix + '?' + retVal; + else if (retFilter.alwaysUsefilterPrefix) retVal = retFilter.filterPrefix; + + return retVal; + } + + + getFilter(): any { + const retFilter: BaseFilter = Object.assign({}, this); + if (this.doPrepare) this.doPrepare(retFilter); + delete retFilter.alwaysUsefilterPrefix; + delete retFilter.filterPrefix; + delete retFilter.useObjectFilter; + delete retFilter.dontConsiderFields; + delete retFilter.dontResetFields; + return retFilter; + } + + protected doPrepare(retFilter: BaseFilter) { + for (const prop in this) { + if (!this.isServiceField(prop) && this.propertyIsEnumerable(prop) && !this.isFieldEmpty(prop)) { + const obj = retFilter[prop as string]; + switch (typeof obj) { + case 'string': + retFilter[prop as string] = obj.trim(); + break; + } + } + } + if (this.onPrepare) this.onPrepare(retFilter); + } + + + public filterReset() { + for (const prop in this) { + if (!this.isServiceField(prop) && !this.isFixedField(prop) && this.propertyIsEnumerable(prop)) this.initField(prop); + } + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentitylist.wrapper.ts b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentitylist.wrapper.ts new file mode 100644 index 0000000..c8d9a2e --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/models/generics/baseentitylist.wrapper.ts @@ -0,0 +1,683 @@ +import { BaseEntity, ErrorCallBack, BaseEntityCallBack } from './baseentity'; +import { BaseEntityWrapper } from './baseentity.wrapper'; +import { Subscription, interval, Observable, Subject, forkJoin, of } from 'rxjs'; +import { BaseFilter } from './baseentityfilter'; +import { RepositoryService } from '../../services/http/repository.service'; +import { UINotifierService } from '../../services/notification/uinotifier.service'; +import { cnst_CANCEL_ERROR, EN_EntityBeforeSaveCallBackResults, EN_EntityEditingStates } from '../../consts'; +import { getErrorMessageAsText, isEqual, now } from '../../utils'; +import { AppLogsService } from '../../services/applogs.service'; +import { ResultSubject } from '../resultsubject'; +import * as keycode from '@angular/cdk/keycodes'; +import { HenselTranslateService } from '../../services/localization/hensel-translate.service'; +import { inject } from '@angular/core'; + +export class BaseEntityListWrapper { + public static delayDoItemSelect: number = 500; //item is selected if the last ..ms doSelect was not called + public static delayDoItemFocus: number = 500; //item is focused if the last ..ms doFocus was not called + public static dalayFocusLastItem: number = 500; //delay after last item of the list is selected in the grid component + public static dalayFocusFirstItem: number = 1250; //delay after last item of the list is selected in the grid component, use it to wait the finish of grid sorting + public focusedEntityShadowed: BaseEntityWrapper; + public reloadAfterItemUpdate: boolean = false; + public alwaysFocused: boolean = true; // approves that if the list is not empty it has always focused row (after delete rows or reloading), after loading the focused is not changed + public afterLoadFocusFirstItem: boolean = false; // approves that after reloading the first row always has focus + public batchInsert: boolean = true; + public focusedItemGridIndex: number = -1; + public useFocusedGridIndex: boolean = true; + public focusedCallBack: BaseEntityCallBack; + public focusedRoutingCallBack: BaseEntityCallBack; + public savedCallBack: VoidFunction; + public confirmationsOn: boolean = false; + public dontShowErrors: boolean = true; + public beforeSaveCallBack: (entity: BaseEntity[]) => Promise; //callback to be called before save, returns 0-all ok, continue saving, 1-all ok, break further saving, 2 - error, ignore coninue + public afterInsertCallBack: (entity: BaseEntity, callback?: BaseEntityCallBack) => void; + public isConnectedWithSortedGrid: boolean = true; + public connectedGrid: any; + public deletedItems: T[] = []; + public shouldBeNotEmpty: boolean = false; + public entityListLoaded$: Subject = new Subject(); + public translate: HenselTranslateService; + + private _isLoading: boolean = false; + public updateItemIfWasNotFoundInList: boolean = false; + + public get isLoading(): boolean { + return this._isLoading; + } + public set isLoading(value: boolean) { + const wasLoading = this._isLoading; + this._isLoading = value; + if (wasLoading && !value) this.entityListLoaded$.next(); + } + + + private _hierarchyLevel: number = 0; + public get hierarchyLevel(): number { + return this._hierarchyLevel; + } + public set hierarchyLevel(value: number) { + this._hierarchyLevel = value; + if (this.focusedEntityShadowed) this.focusedEntityShadowed.hierarchyLevel = value; + } + + protected _focusedTimer: Subscription = null; + protected _selectedTimer: Subscription = null; + protected _selectedItemIds: number[] = []; + protected _focusedItemId: number = 0; + protected _items: T[] = []; + + private _reloadAnyway: boolean = false; + private readonly lastElement = -1; + private loginSubscriptionSave: Subscription; + private loginSubscriptionLoad: Subscription; + + protected appLogsService: AppLogsService; + protected repositoryService: RepositoryService; + protected uiNotificationsService: UINotifierService; + + constructor( + protected TEntity: new (src?: Partial) => T, + public _listName: string, + public routing: string, //controller route + public filter?: BaseFilter, + appLogsService?: AppLogsService, + repositoryService?: RepositoryService, + uiNotificationsService?: UINotifierService, + ) { + this.appLogsService = appLogsService ?? inject(AppLogsService); + this.repositoryService = repositoryService ?? inject(RepositoryService); + this.uiNotificationsService = uiNotificationsService ?? inject(UINotifierService); + this.translate = this.appLogsService.translate; + } + + public get items(): T[] { return this._items; } + + + public set items(newItems: T[]) { + this._items = newItems; + this.deletedItems = []; + // this.clearSelected(); //is done indirectly in approveFocusedSelectedItems + this.approveFocusedSelectedItems(); + } + + get selectedItemIds(): number[] { + return this._selectedItemIds; + } + + + set selectedItemIds(list: number[]) { + // if (!(this._selectedItemsLast.length === list.length && list.every(_ => this._selectedItemsLast.find(vl => vl === _) !== undefined))) { + // this._selectedItemsLast = Object.assign([], list); + + this._selectedItemIds = list; + //Hack to avoid multicall of selected event + + if (this._selectedTimer) this._selectedTimer.unsubscribe(); + this._selectedTimer = interval(BaseEntityListWrapper.delayDoItemSelect).subscribe(() => { + this._selectedTimer?.unsubscribe(); + this.doSelect(list); + }); + } + + get focusedItemId(): number { return this._focusedItemId; } + set focusedItemId(focusedId: number) { + if (Array.isArray(focusedId)) focusedId = focusedId.length > 0 ? focusedId[0] : 0; + if (!focusedId || (typeof focusedId !== 'number')) focusedId = 0; //avoid to fire if focusedId is undefined or null or NaN, which we can get from the grid component + if (this._focusedItemId === focusedId && !this._reloadAnyway && focusedId /* important for details.enablededit() at the start*/) return; + this._focusedItemId = focusedId; + + if (this._focusedTimer) this._focusedTimer.unsubscribe(); + this._focusedTimer = interval(BaseEntityListWrapper.delayDoItemFocus).subscribe(() => { + this._focusedTimer?.unsubscribe(); + this.doFocus(focusedId); + }); + } + + public get focusedItem(): T { return this.focusedItemId ? this.getItemById(this.focusedItemId) : null; } + + + public get changed(): boolean { + return (this.deletedItems.length > 0) || this.items.some((it: BaseEntity) => it.entityChanged); + } + + + public get isValidInput(): boolean { + return (!this.shouldBeNotEmpty || this.items.length > 0) && this.items.every((it: BaseEntity) => it.isValidInput); + } + + + protected approveFocusedSelectedItems(newId: number = 0) { + const _focusedItem: T = this.focusedItem; + // setTimeout(() => { + this._reloadAnyway = true; //to call focused event for details anyway (even focusedItemId was the same) + if (!_focusedItem) { + if (newId !== 0) this.focusedItemId = newId; + else if (this.alwaysFocused) this.focusFirstItem(); + else this.focusedItemId = 0; + } else { + // this._reloadAnyway = true; + this.focusedItemId = this.focusedItemId; //reload focused entity anyway + } + if (this.items.length === 0) this.clearSelected(); + else this.selectedItemIds = this.selectedItemIds.filter(id => this.getItemById(id) !== null); + // }, 0/*cnstChangedWaitInterval*/); + } + + + public focusFirstItem(_loadedCallback?: (entity: T[]) => void, _interval: number = BaseEntityListWrapper.dalayFocusFirstItem) { + const lastFocusItemIdIndex = this.useFocusedGridIndex ? this.focusedItemGridIndex : this.focusedItemId; + if (this.useFocusedGridIndex) _interval = 0; //if the gridindex is using is used - does not matter the grid sorting + setTimeout(() => { //to set after grid's sorting + // to fix - during setting of focusedItemGridIndex, focusedItemId is changed and causes "check after change error" + const curFocusItemIdIndex = this.useFocusedGridIndex ? this.focusedItemGridIndex : this.focusedItemId; + // this.appLogsService.dlog('--- Last Focused Index/Id', this._listName, lastFocusItemIdIndex, curFocusItemIdIndex); + if (this.items && this.items.length > 0) { + if (lastFocusItemIdIndex === curFocusItemIdIndex) { //grid focus was not explicetely changed + if (this.useFocusedGridIndex) this.focusedItemGridIndex = 0; // to be aware of grid sorting + else this.focusedItemId = this.items[0].entityId; + } + } else this.focusedItemId = 0; + if (_loadedCallback) _loadedCallback(this.items); + }, _interval); + } + + + public focusLastItem(_loadedCallback?: (entity: T[]) => void, _interval: number = BaseEntityListWrapper.dalayFocusLastItem) { + const lastFocusItemIdIndex = this.useFocusedGridIndex ? this.focusedItemGridIndex : this.focusedItemId; + if (this.useFocusedGridIndex) _interval = 0; //if the gridindex is using is used - does not matter the grid sorting + setTimeout(() => { //to set after grid's sorting + const curFocusItemIdIndex = this.useFocusedGridIndex ? this.focusedItemGridIndex : this.focusedItemId; + // this.appLogsService.dlog('--- Last Focused Index/Id', this._listName, lastFocusItemIdIndex, curFocusItemIdIndex); + if (this.items && this.items.length > 0) { + if (lastFocusItemIdIndex === curFocusItemIdIndex) { //grid focus was not explicetely changed + if (this.useFocusedGridIndex) this.focusedItemGridIndex = this.items.length - 1; // to be aware of grid sorting + else this.focusedItemId = this.items[this.items.length - 1].entityId; + } + } else this.focusedItemId = 0; + if (_loadedCallback) _loadedCallback(this.items); + }, _interval); + } + + + public gridUpDownProcessing(e: any) { + switch (e.event.keyCode) { + case keycode.HOME: + this.focusFirstItem(null, 100); + e.event.stopPropagation(); + break; + case keycode.END: + this.focusLastItem(null, 100); + e.event.stopPropagation(); + break; + } + } + + public getItemById(id: number): T { return this.items ? this.items.find(it => it.entityId === id) : null; } + + + public getItemIndex(entity: T | number): number { + if ((typeof entity) === 'number') { + return this.items.findIndex((it) => (it.entityId === entity)); + } else if (entity instanceof BaseEntity) { + return this.items.findIndex((it) => it === entity || ( + entity?.entityId && ( + it?.entityId === entity?.entityId + || entity.insertWithIds() && -it?.entityId === entity?.entityId //in the case of insertWithIds entityId = -entityId after saving + ) + )); + } else return this.items.findIndex((it: any) => it === entity); + } + + + public get focusedItemIndex(): number { + return this.getItemIndex(this.focusedItem); + } + + + public isDeleted(entity: T, respawn: boolean = false): boolean { + const indexInDeleted: number = this.deletedItems.indexOf(entity); + if (respawn && indexInDeleted > -1) this.deletedItems.splice(indexInDeleted, 1); + return indexInDeleted > -1; + } + + + setTriggerItem(entity: T, itemOn: boolean) { + if (!itemOn) { + if (!entity.isNew()) this.deletedItems.push(entity); //mark for deleting if already saved, bot leave in the main list + entity.entityChanged = false; //set to be not saved from main list + } else { + entity.entityChanged = true; //mark to be saved + this.isDeleted(entity, true); //remove from list of items to delete if was there + } + } + + + public clearSelected() { this.selectedItemIds = []; } + + + public clearFocused() { this.focusedItemId = 0; } + + + public clear() { + this.items = []; + // this._items = []; + // this.clearSelected(); + // this.clearFocused(); + // if (this.focusedEntityShadowed) this.focusedEntityShadowed.clear(); + } + + + public createFocusedShadowEntity(defaultEditMode?: EN_EntityEditingStates): BaseEntityWrapper { + this.focusedEntityShadowed = new BaseEntityWrapper(this.TEntity, defaultEditMode); + this.focusedEntityShadowed.entityList = this; + this.focusedEntityShadowed.hierarchyLevel = this.hierarchyLevel; + return this.focusedEntityShadowed; + } + + + public load(_loadedCallback?: (entity: T[]) => void, _errorCallback?: ErrorCallBack, _completeCallback?: () => void): boolean // + { + if (this.filter && this.filter.useObjectFilter) { + return this.loadWithObjFilter(_loadedCallback, _errorCallback, _completeCallback); + } else this.loadWithURLFilter(_loadedCallback, _errorCallback, _completeCallback); + + } + + + public loadWithObjFilter(_loadedCallback?: (entity: T[]) => void, _errorCallback?: ErrorCallBack, _completeCallback?: () => void): boolean // + { + return this._load(this.repositoryService.getDataByObjFilter(this.routing + (this.filter.filterPrefix ? '/' + this.filter.filterPrefix : ''), this.filter.getFilter()), _loadedCallback, _errorCallback, _completeCallback); + } + + + public loadWithURLFilter(_loadedCallback?: (entity: T[]) => void, _errorCallback?: ErrorCallBack, _completeCallback?: () => void): boolean // + { + return this._load(this.repositoryService.getDataByURLFilter(this.routing, this.filter ? this.filter.getFilterURL() : ''), _loadedCallback, _errorCallback, _completeCallback); + } + + + + protected _load(loadList$: Observable, _loadedCallback?: (entity: T[]) => void, _errorCallback?: ErrorCallBack, _completeCallback?: () => void): boolean { + let msgID: number; + + if (!this.loginSubscriptionLoad && this.hierarchyLevel === 0) { + this.loginSubscriptionLoad = this.repositoryService.authService.loginAction$.subscribe((resultObject) => { + if (resultObject.result) { //try one time more + this._load(loadList$, _loadedCallback, _errorCallback, _completeCallback); + } else this.unsubscribe(this.loginSubscriptionLoad); + }); + } else { + if (this.loginSubscriptionLoad) this.unsubscribe(this.loginSubscriptionLoad); // try only one time more + } + + this.isLoading = true; + if (this.uiNotificationsService) msgID = this.uiNotificationsService.showMessage(this.translate.instant('core.msg.loading', { value: this.translate.instant(this._listName) })); + const filter4Call: BaseFilter = this.filter ? Object.assign({}, this.filter) : null; + let afterLoadFocusFirstItem = this.afterLoadFocusFirstItem; + loadList$.subscribe( + (entities: T[]) => { + try { + this.unsubscribe(this.loginSubscriptionLoad); //relogin is not executed - don't need subscription + if (!isEqual(filter4Call, this.filter)) return false; //means, that meanwhile a load command for another Id was executed. it must win + const _items: T[] = []; + if (entities) entities.map(entity => _items.push(new this.TEntity(entity))); + if (this.focusedEntityShadowed /*&& _items.length === 0*/ /*&& this.focusedRoutingCallBack*/) // to accellerate call back for empty list, otherwise it takes up to 2s, + // and to have isLoading=true for shadowEntity to disable new/edit button after list is loaded but before callback from the grid to load shadowEntity, + // otherwise can happens, the edit dialog for shadowEntity is opened and shadowEntity is loaded afterwords and get editmode=view -> error + { + this.focusedEntityShadowed.entityWasLoaded = false; //is set to fire loaded$ event for empty too, is called when wasloaded=true in pageservice.focusedRoutingCallBack + // functionality is called in approveFocusedSelectedItems called by this.items = _items; + // if (_items.length === 0) { + // this._reloadAnyway = true; //set it to 0 to call load for id=0, that sets entityWasLoaded=false, if not focusedRoutingCallBack + // this.focusedItemId = 0; //set it to 0 to call dofocused immediately. don't wait on pageservice.focusedRoutingCallBack + // } + } + this.items = _items; //here doFocused and do doSelected are triggered + if (this.uiNotificationsService) this.uiNotificationsService.showMessage(this.translate.instant('core.msg.loaded', { value: this.translate.instant(this._listName), count: this.items.length }), msgID); + if (this.afterLoadFocusFirstItem) { + this.focusFirstItem(() => { + if (_loadedCallback) _loadedCallback(this.items); + if (_completeCallback) _completeCallback(); + }); + } else if (_loadedCallback) _loadedCallback(this.items); + } catch (error) { + afterLoadFocusFirstItem = false; //to call completecallback anyway + const fehlerName: string = this.translate.instant('core.error.loading', { value: this.translate.instant(this._listName) }); + const errorMsg = getErrorMessageAsText(error); + if (errorMsg !== cnst_CANCEL_ERROR) { + if (this.uiNotificationsService) this.uiNotificationsService.showMessage(`${fehlerName}: ${errorMsg}`, msgID); + if (!this.dontShowErrors) this.appLogsService.errorMessageBox(fehlerName, errorMsg); + this.unsubscribe(this.loginSubscriptionLoad); //relogin is not executed - don't need subscription + } else this.uiNotificationsService.stopMessage(msgID); + if (_errorCallback) _errorCallback(({ errMsg: errorMsg === cnst_CANCEL_ERROR ? cnst_CANCEL_ERROR : `${fehlerName}: ${errorMsg}`, entity: this })); + } + finally { + if (_completeCallback && !afterLoadFocusFirstItem) {//_completeCallback is already called as callback for this.focusFirstItem(), don't need one time more + _completeCallback(); + } + this.isLoading = false; + } + }, + (error: any) => { + if (this.uiNotificationsService) this.uiNotificationsService.showMessage(this.translate.instant('core.error.loading', { value: this.translate.instant(this._listName) }), msgID, 6000); + if (_errorCallback) _errorCallback(error); + if (_completeCallback) _completeCallback(); + this.isLoading = false; + }, + ); + return true; + } + + + updateListItem(entity: T, insertIndex: number = this.lastElement /* at the end */, wasInserted: boolean = false): number { + if (!entity?.isEmpty() && entity.entityId !== 0) { + if (!wasInserted) { + let foundEntityIndex: number; + foundEntityIndex = this.getItemIndex(entity); + if (foundEntityIndex < 0 && this.updateItemIfWasNotFoundInList) foundEntityIndex = this.focusedItemIndex; //dont overwrite focused row in the grid, but add at the end + if (foundEntityIndex < this.items.length && foundEntityIndex > -1) { + if (this.items[foundEntityIndex] !== entity) { + this.items[foundEntityIndex].assign(entity); + // this.items[foundEntityIdx] = new this.TEntity(entity); //if is running we get spinner for the grid + } + if (this.focusedItemId !== entity.entityId) this.focusedItemId = entity.entityId; + return entity.entityId; + } + } + //inserts a new entity + const newEntity: T = new this.TEntity(entity); + if (newEntity) { + if (insertIndex < 0 || this.items.length <= insertIndex) this.items.push(newEntity); + else this.items.splice(insertIndex, 0, newEntity); + this.focusedItemId = newEntity.entityId; + return newEntity.entityId; //Id of a new Inserted entity + } + } + return -1; //no entities were updated/inserted + } + + + deleteListItem(entity: T, save2deleted: boolean = true, addAsDeletedAnyway: boolean = false): boolean { + if (!entity) return false; + const foundEntityIdx: number = this.getItemIndex(entity); + if (foundEntityIdx > -1) { + if (save2deleted && (entity instanceof BaseEntity) && !entity.isNew()) this.deletedItems.push(this.items[foundEntityIdx]); + this.items.splice(foundEntityIdx, 1); //to do delete must be called approve + //if is deleted in the sorted grid the logic cannot be used + if (!this.isConnectedWithSortedGrid) { + //timeout to avoid "Check after change error" + setTimeout(() => this.approveFocusedSelectedItems(this.items.length === 0 ? 0 : this.items[foundEntityIdx - (foundEntityIdx >= this.items.length ? 1 : 0)].entityId)); + } else if (this.items?.length === 0) this.approveFocusedSelectedItems(); + return true; + } else if (addAsDeletedAnyway && !((entity instanceof BaseEntity) && entity.isNew())) this.deletedItems.push(entity); + return false; + } + + + deleteAll(save2deleted: boolean = true) { + for (let i = this.items.length - 1; i >= 0; i--) { + const entity = this.items[i]; + if (save2deleted && !entity.isNew()) this.deletedItems.push(entity); + // this.items.splice(i, 1); //to do delete must be called approve + } + this.items.splice(0); + } + + + protected doSelect(list: number[]) { + //console.log('Selected', this.selectedItemIds); + } + + + protected doFocus(focusedId: number) { + const focusedItemId = this.focusedEntityShadowed?.entityId ?? 0; + const reloadAnyway = this._reloadAnyway; + this._reloadAnyway = false; + + if (this.focusedEntityShadowed && !this.focusedRoutingCallBack) { //use direct connection or routing + if (this.focusedEntityShadowed.entityId !== focusedId || reloadAnyway) { + this.focusedEntityShadowed.entityId = focusedId; + } + } + if (this.focusedRoutingCallBack) setTimeout(() => { this.focusedRoutingCallBack(this.focusedItem); }); + + if (this.focusedCallBack && (focusedItemId !== focusedId || reloadAnyway)) { + setTimeout(() => { this.focusedCallBack(this.focusedItem); }); + } + } + + + public async saveAsync(): Promise { + return new Promise((resolve, reject) => this.save(null, () => resolve(false), () => resolve(true))); + } + + + private unsubscribe(subscr: Subscription) { + subscr?.unsubscribe(); + subscr = null; + } + + public async save(_loadedCallback?: () => void, _errorCallback?: ErrorCallBack, _completeCallback?: () => void) { + let resBeforeSaveCallBack: EN_EntityBeforeSaveCallBackResults = EN_EntityBeforeSaveCallBackResults.Ok_Continue; + // tslint:disable-next-line: no-bitwise + const doBreak: boolean = this.beforeSaveCallBack && ((resBeforeSaveCallBack = await this.beforeSaveCallBack(this.items)) & EN_EntityBeforeSaveCallBackResults.Ok_Break) !== 0; + if (resBeforeSaveCallBack === EN_EntityBeforeSaveCallBackResults.Ok_Break) { + if (_loadedCallback) _loadedCallback(); + if (_completeCallback) _completeCallback(); + if (this.savedCallBack) this.savedCallBack(); + return; + } else if (resBeforeSaveCallBack === EN_EntityBeforeSaveCallBackResults.Error_Break) { + if (_errorCallback) _errorCallback({ errMsg: cnst_CANCEL_ERROR } as ResultSubject); + return; + } + + const updateDetails$: Subject[] = []; + const newItemList: BaseEntity[] = []; + const changedItemList: BaseEntity[] = []; + let newEntityIndex: number = 0; + + // prepare observable array for forkjoin + this.deletedItems.forEach(() => updateDetails$.push(new Subject())); + this.items.forEach((entity: T) => { + if (entity.entityChanged) { + if (entity.isNew()) { + if (this.batchInsert) { + const newEntity: BaseEntity = new this.TEntity(entity); + newEntity.entityId = 0; + newItemList.push(newEntity.deleteFields()); + } else updateDetails$.push(new Subject()); + } else changedItemList.push(entity.deleteFields()); + } + }); + if (newItemList.length > 0) updateDetails$.push(new Subject()); + if (changedItemList.length > 0) updateDetails$.push(new Subject()); + + //if nothing was deleted/added/changed + if (updateDetails$.length === 0) { + if (_loadedCallback) _loadedCallback(); + if (this.savedCallBack) this.savedCallBack(); + if (_completeCallback) _completeCallback(); + return; + } + + if (!this.loginSubscriptionSave && this.hierarchyLevel === 0 && this.repositoryService.authService.user.isAdmin) { + this.loginSubscriptionSave = this.repositoryService.authService.loginAction$.subscribe((resultObject) => { //try one time more + if (resultObject.result) { + this.appLogsService.dlog('!!! - relogin - resave list', resultObject); + this.save(_loadedCallback, _errorCallback, _completeCallback); + } else this.unsubscribe(this.loginSubscriptionSave); + }); + } else { + if (this.loginSubscriptionSave) this.unsubscribe(this.loginSubscriptionSave); // try only one time more + } + + + let msgID: number; + if (this.uiNotificationsService) msgID = this.uiNotificationsService.showMessage(this.translate.instant('core.msg.saving', { value: this.translate.instant(this._listName) })); + //wait on the result + forkJoin(updateDetails$).subscribe( + () => { + this.unsubscribe(this.loginSubscriptionSave); //relogin is not executed - don't need subscription + this.appLogsService.dlog('++ next save list <' + this.translate.instant(this._listName) + '>'); + this.items = this.items.slice(); //otherwise for new entities in the bind to grid lists id in the grid will not be updated and stay <0 + // this.approveFocusedSelectedItems(); + if (this.uiNotificationsService) this.uiNotificationsService.showMessage(this.translate.instant('core.msg.saved', { value: this.translate.instant(this._listName) }), msgID); + if (_loadedCallback) _loadedCallback(); + if (this.savedCallBack) this.savedCallBack(); + } + , (error: any) => { + this.deletedItems = this.deletedItems.filter(_ => _); //let be in array only not null elements + + this.appLogsService.error('!! error save list <' + this.translate.instant(this._listName) + '>: ', { error }); + + const fehlerName: string = this.translate.instant('core.error.saving', { value: this.translate.instant(this._listName) }); + const errorMsg = getErrorMessageAsText(error); + if (errorMsg !== cnst_CANCEL_ERROR) { + if (this.uiNotificationsService) this.uiNotificationsService.showMessage(`${fehlerName}: ${errorMsg}`, msgID); + if (!this.dontShowErrors) this.appLogsService.errorMessageBox(fehlerName, errorMsg); + this.unsubscribe(this.loginSubscriptionSave); //relogin is not executed - don't need subscription + } else this.uiNotificationsService.stopMessage(msgID); + if (_errorCallback) _errorCallback(({ errMsg: errorMsg === cnst_CANCEL_ERROR ? cnst_CANCEL_ERROR : `${fehlerName}: ${errorMsg}`, entity: this })); + } + , () => { + this.appLogsService.dlog('++ complete save list <' + this.translate.instant(this._listName) + '>'); + this.deletedItems = this.deletedItems.filter(_ => _); //let be in array only not null elements + if (_completeCallback) _completeCallback(); + } + ); + + //delete deleted entities + for (let index = 0; index < this.deletedItems.length; index++) { + const inx: number = index; //must be created every time for every observable call, otherwise we get the same value for all callbacks + if (this.deletedItems[inx]) { + this.deletedItems[inx].delete(this.repositoryService + , () => { + this.deletedItems[inx] = null; //element was sucessfully deleted - eliminate from the list of to be deleted + updateDetails$[inx].next(); + } + , (error) => updateDetails$[inx].error(error) + , () => updateDetails$[inx].complete()); + } + } + + newEntityIndex = this.deletedItems.length; + let batchRouting = this.routing.toLowerCase(); + if (batchRouting.slice(-4) === '/all') batchRouting = batchRouting.slice(0, batchRouting.length - 4); + batchRouting += '/list'; + + if (this.batchInsert) { + // insert new entities in batch + if (newItemList.length > 0) { + const inx: number = newEntityIndex; //must be created every time for every obserfable call, otherwise we get the same value for all callbacks + this.repositoryService.postData(batchRouting, newItemList) + .subscribe( + (entities: T[]) => { + // let index: number = 0; + // this.items.forEach((it: T) => { + // if (it.isNew() && it.entityChanged) it.assign(new this.TEntity(entities[index++])); + // }); + this._items.splice(0, this._items.length, ...this.items.filter( //splice - technique to save array pointer and change only array content + (it: T) => !(it.isNew() && it.entityChanged)).concat(entities.map((it: T) => new this.TEntity(it))) + ); + this.appLogsService.dlog('--- next insert list <' + this.translate.instant(this._listName) + '>', inx, this.items); + updateDetails$[inx].next(); + } + , (error) => updateDetails$[inx].error(error) + , () => { + this.appLogsService.dlog('--- complete insert list <' + this.translate.instant(this._listName) + '>', inx); + updateDetails$[inx].complete(); + } + ); + newEntityIndex++; + } + } else { + //insert new entities separately + this.items.forEach((entity: T, index: number) => { + if (entity.isNew() && entity.entityChanged) { + const inx: number = newEntityIndex; //must be created every time for every observable call, otherwise we get the same value for all callbacks + entity.save(this.repositoryService + , (loadedEntity: BaseEntity) => { + const updNext$ = updateDetails$[inx]; + const entity_ = loadedEntity; //because of collisions in callback if it is called sequentially + if (this.afterInsertCallBack) { + this.afterInsertCallBack(entity_, () => { + // loadedEntity.load(this.repositoryService, null); + updNext$.next(); + updNext$.complete(); + }); + } else updNext$.next(); + } + , (error) => updateDetails$[inx].error(error) + , () => { if (!this.afterInsertCallBack) updateDetails$[inx].complete(); } + ); + newEntityIndex++; + } + }); + } + + //save changed entities in batch + if (changedItemList.length > 0) { + const inx: number = newEntityIndex; //must be created every time for every obserfable call, otherwise we get the same value for all callbacks + this.repositoryService.putData(batchRouting, changedItemList) + .subscribe( + () => { + this.items.forEach((entity: T) => { if (entity.entityChanged) entity.entityChanged = false; }); + this.appLogsService.dlog('--- next update list <' + this.translate.instant(this._listName) + '>', inx); + updateDetails$[inx].next(); + } + , (error: any) => updateDetails$[inx].error(error) + , () => { + this.appLogsService.dlog('--- complete update list <' + this.translate.instant(this._listName) + '>', inx); + updateDetails$[inx].complete(); + } + ); + } + } + + + getId4NewItem() { + return this.items.reduce((min: number, _item: T) => (min < _item.entityId ? min : _item.entityId), 0) - 1; + } + + + newItem(src?: Partial, changed?: boolean): T { + const item: T = new this.TEntity(src); + if (changed !== null && changed !== undefined) item.entityChanged = changed; + item.entityId = this.getId4NewItem(); + this.items.push(item); + return item; + } + + public match2KeysArray(entity: BaseEntity, fieldName4EntityKey: string, keyArray: number[], fieldName4Key: string): boolean { + let wasChanged: boolean = false; + for (let index = this.items.length - 1; index >= 0; index--) { + const currItem = this.items[index]; + if (keyArray.indexOf(currItem[fieldName4Key]) === -1) { + this.deleteListItem(currItem); + wasChanged = true; + } + } + keyArray.forEach((key) => { + if (!this.items.find((item: T) => item[fieldName4Key] === key)) { + const item = new this.TEntity(); + item[fieldName4EntityKey] = entity[fieldName4EntityKey]; + item[fieldName4Key] = key; + item.entityChanged = true; + this.items.push(item); + wasChanged = true; + } + }); + return wasChanged; + } + + + public match2array(entity: BaseEntity, fieldName4EntityKey: string, fieldName4ArrayKey: string, fieldName4Key: string): boolean { + return this.match2KeysArray(entity, fieldName4EntityKey, entity[fieldName4ArrayKey], fieldName4Key); + } + + + public onFocusedRowChanging($event) { + if (this.focusedEntityShadowed && this.focusedEntityShadowed.entityIsLoading) $event.cancel = true; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/models/resultsubject.ts b/ClientApp/staff-db-ui/src/app/shared/core/models/resultsubject.ts new file mode 100644 index 0000000..d972fe0 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/models/resultsubject.ts @@ -0,0 +1,14 @@ +import { cnst_CANCEL_ERROR } from '../consts'; +import { getErrorMessageAsText } from '../utils'; + +export class ResultSubject { + result = false; + errMsg?; + entity?: any; + constructor(error: any, entity: any, prefix: string = '') { + this.errMsg = getErrorMessageAsText(error); + if ( this.errMsg !== cnst_CANCEL_ERROR && this.errMsg.indexOf(prefix) === -1) this.errMsg = prefix + this.errMsg; + this.entity = entity; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/models/serverinfo.ts b/ClientApp/staff-db-ui/src/app/shared/core/models/serverinfo.ts new file mode 100644 index 0000000..1181db9 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/models/serverinfo.ts @@ -0,0 +1,31 @@ +import { EN_CoreEntities } from '../services/globals'; +import { BaseEntity } from './generics/baseentity'; + + +export class ServerInfo extends BaseEntity { + public typeName: string = EN_CoreEntities.ServerInfo; //is used as Controller for URL queries + version: string; + server: string; + status: number; + message: string; + databaseServer: string; + databaseName: string; + databaseStatus: string; + + userName: string; + serviceLoginName: string; + isLive: boolean; + fileServer: string; + lastDataLoaded: Date; + clientVersion: string; + firstOnlineTime: Date; + lastOfflineTime: Date; + attributes: any; + officeFileServer: string; + officeFileServerURL: string; + officeFileServerVersion: string; + officeFileServerDBServer: string; + officeFileServerDBName: string; + + isNew() { return false; } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/pipes/hensel-html-sanitizer.pipe.ts b/ClientApp/staff-db-ui/src/app/shared/core/pipes/hensel-html-sanitizer.pipe.ts new file mode 100644 index 0000000..f811688 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/pipes/hensel-html-sanitizer.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; + + +@Pipe({ + name: 'htmlSanitize', + standalone: true +}) + +export class HenselHTMLSanitizer { + constructor(private sanitized: DomSanitizer) { } + transform(value) { + return this.sanitized.bypassSecurityTrustHtml(value); + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/applogs.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/applogs.service.ts new file mode 100644 index 0000000..29533eb --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/applogs.service.ts @@ -0,0 +1,164 @@ +import { Inject, Injectable } from '@angular/core'; +import * as Utils from '../utils'; +import { MatDialogService } from './mat-dialog.service'; +import { MessageBoxComponent } from '../components/message-box/message-box.component'; +import { EN_LogType } from '../consts'; +import { Globals, IMessageBoxButton, IMessageBoxData } from './globals'; +import * as Sentry from '@sentry/angular'; +import { ENVIRONMENT_TOKEN, IENVIRONMENT } from '../injection-tokens'; +import { HenselTranslateService } from './localization/hensel-translate.service'; +import { MatDialogRef } from '../components/angular-material-index'; + +const DoubledEventIntrval = 500; + +@Injectable({ + providedIn: 'root' +}) + +export class AppLogsService { + startingTimes: Map = new Map(); + constructor( + private dialog: MatDialogService, + private globals: Globals, + public translate: HenselTranslateService, + @Inject(ENVIRONMENT_TOKEN) private environment: IENVIRONMENT, + ) { } + + checkDoubledEvent(key: string) { + const nowticks = Utils.now(); + const isDoubled = (this.startingTimes.has(key) && (nowticks - this.startingTimes.get(key)) < DoubledEventIntrval); + this.startingTimes.set(key, nowticks); + return isDoubled; + } + + log(message?: any, ...optionalParams: any[]) { + this._log(EN_LogType.message, message, ...optionalParams); + } + + warn(message?: any, ...optionalParams: any[]) { + this._log(EN_LogType.warning, message, ...optionalParams); + } + + error(message?: any, ...optionalParams: any[]) { + this._log(EN_LogType.error, message, ...optionalParams); + const err = optionalParams.find(obj => typeof obj === 'object'); + if (this.environment.sentry_dsn) Sentry.captureException(err ?? message); + } + + + exception(exception: any, ...optionalParams: any[]) { + this._log(EN_LogType.error, Utils.getErrorMessageAsText(exception), ...optionalParams); + if (this.environment.sentry_dsn) Sentry.captureException(Utils.extractError(exception)); + } + + + dlog(message?: any, ...optionalParams: any[]) { + this._log(EN_LogType.debug_message, message, ...optionalParams); + } + + + private _log(logType: EN_LogType, message?: any, ...optionalParams: any[]) { + let timestr: string = ''; + let guid: string = null; + const isDebug = logType === EN_LogType.debug_message; + const guiindex = optionalParams.findIndex( + obj => { if (typeof obj === 'object' && 'guid' in obj) { guid = obj.guid; return true; } else return false; } + ); + + + if (guid) { + optionalParams.splice(guiindex, 1); + if (this.startingTimes.has(guid)) { + timestr = Utils.ms2ToTimeString(Utils.now() - this.startingTimes.get(guid), 'm:s.SSS'); + this.startingTimes.delete(guid); + logType = EN_LogType.guid_message; + } else this.startingTimes.set(guid, Utils.now()); + } + switch (logType) { + case EN_LogType.message: + console.log(message, ...optionalParams); + break; + case EN_LogType.warning: + console.warn(message, ...optionalParams); + break; + case EN_LogType.error: + console.error(message, ...optionalParams); + break; + case EN_LogType.debug_message: + if (!this.environment.production) console.log(message, ...optionalParams); + break; + case EN_LogType.guid_message: + if (!isDebug || !this.environment.production) { + console.log('Finished: ' + ((message).indexOf('%c') > -1 ? '' : '%c') + message + (timestr ? ': ' + timestr + 's' : ''), ...optionalParams); + } + break; + } + } + + showMessageBox(messageBoxData: IMessageBoxData, callBack?: () => void): MatDialogRef { + messageBoxData.overHeader = this.globals.appTitleWithVersion; + // messageBoxData.header = Utils.translateString(messageBoxData.header, this.translate); + // messageBoxData.message = Utils.translateString(messageBoxData.message, this.translate); + return this.dialog.openDialog(MessageBoxComponent, messageBoxData, true, (result: number) => { + if (callBack) callBack(); + messageBoxData.buttons.forEach((btn: IMessageBoxButton) => { + if (btn.code === result && btn.callback) btn.callback(); + }); + }, false); + } + + + errorMessageBox(caption: string, message: string, commonCallBack?: () => void): MatDialogRef { + return this.showMessageBox({ + type: EN_LogType.error, + header: caption, + message: message, + buttons: [{ title: this.translate.instant('core.btn.ok') }] + }, commonCallBack); + } + + + warningMessageBox(caption: string, message: string, commonCallBack?: () => void): MatDialogRef { + return this.showMessageBox({ + type: EN_LogType.warning, + header: caption, + message: message, + buttons: [{ title: this.translate.instant('core.btn.ok') }] + }, commonCallBack); + } + + + informationMessageBox(caption: string, message: string, commonCallBack?: () => void): MatDialogRef { + return this.showMessageBox({ + type: EN_LogType.message, + header: caption, + message: message, + buttons: [{ title: this.translate.instant('core.btn.ok') }] + }, commonCallBack); + } + + + confirmMessageBoxYesNo(caption: string, message: string, yesCallBack: () => void, commonCallBack?: () => void, defaultButtonInx: number = 0): MatDialogRef { + return this.showMessageBox({ + type: EN_LogType.confirmation, + header: caption, + message: message, + buttons: [{ title: this.translate.instant('core.btn.yes'), code: 1, default: defaultButtonInx === 0, callback: yesCallBack }, + { title: this.translate.instant('core.btn.no'), default: defaultButtonInx === 1, cancel: true, code: 0 }, + ] + }, commonCallBack); + } + + + confirmMessageBoxYesNoCancel(caption: string, message: string, yesCallBack: () => void, noCallBack: () => void, commonCallBack?: () => void, defaultButtonInx: number = 0): MatDialogRef { + return this.showMessageBox({ + type: EN_LogType.confirmation, + header: caption, + message: message, + buttons: [{ title: this.translate.instant('core.btn.yes'), code: 1, callback: yesCallBack, default: defaultButtonInx === 0 }, + { title: this.translate.instant('core.btn.no'), code: 0, callback: noCallBack, default: defaultButtonInx === 1 }, + { title: this.translate.instant('core.btn.cancel'), cancel: true, code: -1, default: defaultButtonInx === 2 }, + ] + }, commonCallBack); + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/authguard.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/authguard.ts new file mode 100644 index 0000000..a4427c5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/authguard.ts @@ -0,0 +1,63 @@ +import { Injectable, Inject } from '@angular/core'; +import { Router, ActivatedRouteSnapshot, RouterStateSnapshot, Route, UrlSegment } from '@angular/router'; +import { AuthorizeService } from './authorize.service'; +import { Globals, LOGIN_PAGE } from './globals'; +import { PageLoadingService } from './pageloading.service'; +import { AppLogsService } from './applogs.service'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthGuard { + constructor( + private router: Router, + private authService: AuthorizeService, + private globals: Globals, + private pageLoadingService: PageLoadingService, + private appLogsService: AppLogsService + ) { } + + canLoad(route: Route, segments: UrlSegment[]): boolean { + return true; + } + + + async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + let ret: boolean = true; + const urlParsed: string[] = state.url.slice(1).split('/'); + if (!(this.authService.useJWT && !this.authService.checkJWT(0) && this.authService.isLoggedIn())) { + const currentPageURL = urlParsed[0].split('?')[0]; + const currentPage = this.globals.getPage(currentPageURL); + if (this.globals.isTheLoginPage(state.url/*'/' + currentpage*/) || this.authService.isLoggedIn()) { + if (currentPage && currentPage.hidden && !currentPage.allowRedirect) return false; //security to acces hidden pages for unathorized + let param: string = null; + if (urlParsed.length > 1) param = urlParsed[urlParsed.length - 1]; + // if (currentPage?.allowRedirect && this.globals.currentPage === currentpage && !param) return false; + if (this.globals.currentPage === currentPageURL) { + if (currentPage.dontAllowEmptyURL && !param && !!this.globals.urlParam) { + param = this.globals.urlParam; + state.url += '/' + param; + ret = false; + } + } + this.globals.currentPage = currentPageURL; + this.globals.urlParam = param; + this.pageLoadingService.pageActive$.next(this.globals.urlParam); + this.appLogsService.dlog('!! Goto', state.url); + return ret; + } + } else { + this.authService.expiredJWTLogout = true; //the flag is used to show jwt expired message + if (await this.authService.tryRenewJWTAsync(false)) return true; + } + + //not logged in and not in the logon page + if (!this.globals.isTheLoginPage(state.url)) { + const queryParams = { queryParams: { returnUrl: state.url } }; + this.globals.currentPage = LOGIN_PAGE.path; + this.appLogsService.dlog('!! Goto ' + LOGIN_PAGE.path, state.url); + this.router.navigate(['/' + LOGIN_PAGE.path], queryParams); + } + return false; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/authorize.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/authorize.service.ts new file mode 100644 index 0000000..569c76b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/authorize.service.ts @@ -0,0 +1,318 @@ +import { inject, Inject, Injectable, Optional, SkipSelf } from '@angular/core'; +import { Router } from '@angular/router'; +import * as Sentry from '@sentry/angular'; +import { DeviceDetectorService } from 'ngx-device-detector'; +import { NgxSpinnerService } from 'ngx-spinner'; +import { BehaviorSubject, Observable, Subject } from 'rxjs'; +import { LoginPopupComponent } from '../components/login/login-popup/login-popup.component'; +import * as Cnst from '../consts'; +import { LOGIN_PAGE } from './globals'; +import { ENVIRONMENT_TOKEN } from '../injection-tokens'; +import { CoreUser, EN_UserRoles } from '../models/coreuser'; +import { ResultSubject } from '../models/resultsubject'; +import { AppLogsService } from '../services/applogs.service'; +import { RepositoryService } from '../services/http/repository.service'; +import * as Utils from '../utils'; +import { HenselTranslateService } from './localization/hensel-translate.service'; +import { LocaleService } from './localization/locale.service'; +import { MatDialogService } from './mat-dialog.service'; +import { UINotifierService } from './notification/uinotifier.service'; + +// tslint:disable-next-line: class-name +export class HR_JWToken { + idToken: string; + expiresInSec?: number; + expiresAt?: Date; + + constructor(idToken: string, expiresAt: Date, expiresInSec?: number) { + this.idToken = idToken; + this.expiresAt = expiresAt; + this.expiresInSec = expiresInSec; + } +} + + + +@Injectable({ providedIn: 'root' }) +export class AuthorizeService { + private environment = inject(ENVIRONMENT_TOKEN); + + public EN_LoginStatus_Unknown = Cnst.EN_LoginStatus.unknown; + public EN_LoginStatus_JWT = Cnst.EN_LoginStatus.jwt; + public EN_LoginStatus_Password = Cnst.EN_LoginStatus.loginWithNameAndPassword; + public EN_LoginStatus_Windows = Cnst.EN_LoginStatus.windowsAuthorizatoin; + + public versionObsolete$ = new Subject(); + public loginAction$ = new Subject(); + public loginLogout$ = new BehaviorSubject(null); + public loginStatus: Cnst.EN_LoginStatus = Cnst.EN_LoginStatus.unknown; + public useWindowsLogin: boolean = true; + public isMobileDevice: boolean = false; + public expiredJWTLogout: boolean = false; + public useJWT: boolean = false; + public HR_JWT: HR_JWToken; + public processDisclaimer: (coreUser: CoreUser) => Promise; + private _user: CoreUser = new CoreUser(); + private lastLoggedUserId: number; + private _versionObsolete: boolean = false; + public get versionObsolete(): boolean { + return this._versionObsolete; + } + public set versionObsolete(value: boolean) { + if (this._versionObsolete === value) return; + this._versionObsolete = value; + if (value) this.versionObsolete$.next(); + } + + private isRunningRenewJWT: boolean = false; + + + + constructor( + private dialog: MatDialogService, + private router: Router, + private repositoryService: RepositoryService, + private appLogsService: AppLogsService, + private uiNotifier: UINotifierService, + private deviceService: DeviceDetectorService, + private spinnerService: NgxSpinnerService, + private translate: HenselTranslateService, + public localeService: LocaleService, + + @Optional() @SkipSelf() parentService: AuthorizeService, + // @Inject(LOCALE_ID) private localeId: string, + ) { + + repositoryService.authService = this; //to give possibility to use authservice in base entity wrappers + this.isMobileDevice = !this.deviceService.isDesktop(); + this.useWindowsLogin = !this.isMobileDevice; + if ('useLoginWithJWT' in this.environment) this.useJWT = this.environment.useLoginWithJWT; + if ('dontUseWindowsLogin' in this.environment) this.useWindowsLogin = !this.environment.dontUseWindowsLogin; + + // if (this.useJWT) { + // if (!this.checkJWT(this.environment.production ? 60 * 24 /* relogin one day before expiration*/ : 0)) this.loginStatus = this.EN_LoginStatus_Password; + // } else if (!this.useWindowsLogin) this.loginStatus = this.EN_LoginStatus_Password; + + if (parentService) throw new Error('Authorization service is already loaded. Import it in the AppModule only'); + + this.loginAction$.subscribe((resultObject) => { + if (resultObject.result) { + // ACCOUNT_PAGE.hidden = false; + if (!(this.user.isAdmin) && this.environment.production && window) { + window.console.log = function () { }; + this.uiNotifier.isActive = false; + } + this.appLogsService.log(resultObject.errMsg, this.user); + this.uiNotifier.showMessage(this.translate.instant('core.msg.loggedon', { value: this.user.loginName })); + } else { + this.appLogsService.error(resultObject.errMsg); + this.uiNotifier.showMessage(`${resultObject.errMsg}`); + } + }); + + if (!!this.environment.sentry_dsn) { + this.loginLogout$.subscribe((user: CoreUser) => { + const scope = Sentry.getCurrentScope(); + scope.setUser({ + 'id': user?.webAppUserId.toString(), + 'shortname': user?.shortName, + 'username': user?.name, + 'login': user?.loginName, + }); + }); + } + + this.appLogsService.dlog('AuthorizeService is initialized'); + } + + + get user(): CoreUser { + return this._user; + } + + + set user(user: CoreUser) { + this._user = user; + } + + isLoggedIn(): boolean { + return this.isValidUser(); + } + + private isValidUser(): boolean { + return !this.isEmptyUser() && this.user.entityId !== 0; + } + + private isEmptyUser(): boolean { + return (!this._user) || this._user.isEmpty(); + } + + get loginname() { + return this.user?.loginName; + } + + get userName() { + return this.user?.name; + } + + logout(gotoLoginPage: boolean = true) { + this.loginStatus = this.EN_LoginStatus_Password; + this._user.clear(); + localStorage.removeItem('HR-JWToken'); + this.HR_JWT = undefined; + if (gotoLoginPage) { + if (this.isLoggedUserChanged()) this.loginLogout$.next(null); + this.lastLoggedUserId = null; + this.router.navigate(['/' + LOGIN_PAGE.path]); + } + } + + + login(loginname?: string, passw?: string) { + const loginWithPassword: boolean = !!loginname; + if (!loginWithPassword && !this.useJWT && !this.useWindowsLogin) return; + + const logController = loginWithPassword ? Cnst.cnst_LoginPassw_URL : (this.useJWT ? Cnst.cnst_LoginJWT_URL : Cnst.cnst_LoginAuth_URL); + const errorText = loginWithPassword ? this.translate.instant('core.error.logon') : this.translate.instant('core.error.logonnotpossible', { value: this.translate.instant(this.useJWT ? 'JWT-' : 'Windows-') }); + + this.user.loginName = loginname; + this.user.password = passw; + this.user.clientVersion = this.environment.appVersion; + + try { + this.user.timeZoneOffsetInMin = new Date().getTimezoneOffset(); + const loginObj$: Observable = this.repositoryService.postData(this.user.typeName + '/' + logController, this.user); + + if (loginWithPassword) { + this.HR_JWT = undefined; + this.user.culture = this.localeService.currentCulture; + this.user.language = this.localeService.currentLanguage; + } + + loginObj$.subscribe( + async (coreUser) => { + this.user.assign(coreUser); + + if (this.user.entityId) { + if (this.user.roleList && (this.user.isMaster || this.user.isInRolle(EN_UserRoles.DepartmentUser) || this.user.isInRolle(EN_UserRoles.User))) { + + if (loginWithPassword) { + this.jwtAuthentication(); + this.loginStatus = this.EN_LoginStatus_Password; + } else { + this.loginStatus = this.jwtAuthentication() ? this.EN_LoginStatus_JWT : this.EN_LoginStatus_Windows; + } + + if (!!coreUser.language) this.localeService.currentLanguage = coreUser.language; + if (!!coreUser.culture) this.localeService.currentCulture = coreUser.culture; + + if (coreUser.showDisclaimer && this.processDisclaimer) { + LoginPopupComponent.LOGIN_IS_SHOWN = true; //do not show Login poup + if (!await this.processDisclaimer(coreUser)) { + LoginPopupComponent.LOGIN_IS_SHOWN = false; + this.loginAction$.next({ result: false, errMsg: this.translate.instant('core.error.disclaimernotconfirmed') }); + // this.loginStatus = this.EN_LoginStatus_Password; //the order is important + return; + } + } + + if (this.isLoggedUserChanged()) this.loginLogout$.next(coreUser); + this.appLogsService.dlog('!! - eingelogged', new Date().toTimeString(), coreUser); + this.loginAction$.next({ result: true, entity: coreUser }); + this.lastLoggedUserId = coreUser.webAppUserId; + } else { + this.loginAction$.next({ result: false, errMsg: this.translate.instant('core.error.nouserrole'), entity: coreUser }); //roleList must be checked in backend + this.loginStatus = this.EN_LoginStatus_Password; //the order is important + } + } else { + this.loginAction$.next({ result: false, errMsg: coreUser['Message'] }); + this.loginStatus = this.EN_LoginStatus_Password; //the order is important + } + }, + error => { + this.loginAction$.next({ + result: false, errMsg: errorText + + (typeof error.error === 'string' && (error.error as string).indexOf('Exception') === -1 ? ' ' + error.error : '') + }); + this.loginStatus = this.EN_LoginStatus_Password; //the order is important + } + ); + } catch (error) { + this.loginStatus = this.EN_LoginStatus_Password; + this.appLogsService.dlog(logController + ' Unexpected Error', error); + } finally { + } + } + + + isLoggedUserChanged() { + return (this.lastLoggedUserId ?? 0) !== (this.user?.webAppUserId ?? 0); + } + + public checkJWT(correctionInMin?: number): boolean { + if (!this.HR_JWT) { + this.HR_JWT = JSON.parse(localStorage.getItem('HR-JWToken')) as HR_JWToken; + if (!this.HR_JWT?.idToken) return false; + if (this.HR_JWT) this.HR_JWT.expiresAt = new Date(this.HR_JWT?.expiresAt); + } + const expiresAt = this.HR_JWT.expiresAt; + if (correctionInMin === null || correctionInMin === undefined) return !!this.HR_JWT?.idToken; //correctionInMin === null - just load and check JWT + expiresAt.setMinutes(expiresAt.getMinutes() - correctionInMin); + return (!!this.HR_JWT?.idToken && Utils.isBefore(this.HR_JWT?.expiresAt)); + } + + + public jwtAuthentication(): boolean { + if (this.useJWT && this.user.token) { + this.user.jwtExpiredOn.setMinutes(this.user.jwtExpiredOn.getMinutes() + 1); + this.HR_JWT = new HR_JWToken(this.user.token, this.user.jwtExpiredOn); + localStorage.setItem('HR-JWToken', JSON.stringify(this.HR_JWT)); + return true; + } else return false; + } + + + loginPopup(errorMsg?: string, gotoLoginPage: boolean = false) { + if (LoginPopupComponent.LOGIN_IS_SHOWN) return; + LoginPopupComponent.LOGIN_IS_SHOWN = true; + this.logout(gotoLoginPage); + if ((errorMsg === null || errorMsg === undefined) && this.expiredJWTLogout) errorMsg = Cnst.cnst_JWT_Expired; + this.expiredJWTLogout = false; + this.dialog.openDialog(LoginPopupComponent, { errorMsg: errorMsg, authorizationService: this }, true, () => { }); + } + + + public async tryRenewJWTAsync(openLogin: boolean = true): Promise { + if (!this.useJWT) return false; + + if (LoginPopupComponent.LOGIN_IS_SHOWN || this.isRunningRenewJWT) return; + this.isRunningRenewJWT = true; + this.appLogsService.warn('Try to renew JWT'); + this.uiNotifier.showMessage(this.translate.instant('core.msg.renewJWT')); + this.spinnerService.show(); + try { + if (!this.HR_JWT || !await this.loginAsync()) { + if (openLogin) this.loginPopup(Cnst.cnst_JWT_Expired); + return false; + } + } + finally { + this.spinnerService.hide(); + this.isRunningRenewJWT = false; + } + return true; + } + + + public async loginAsync(): Promise { + return new Promise((resolve, reject) => { + const logisSubscription = + this.loginAction$.subscribe((resultObject) => { + logisSubscription.unsubscribe(); + resolve(resultObject.result); + }); + this.login(); + }); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/globals.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/globals.ts new file mode 100644 index 0000000..dda6594 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/globals.ts @@ -0,0 +1,249 @@ +import { Inject, Injectable, LOCALE_ID } from '@angular/core'; +import { Route } from '@angular/router'; +import { EN_LogType } from '../consts'; +import * as utils from '../utils'; +import { exportPivotGrid as exportPivotGridToExcel, exportDataGrid as exportDataGridToExcel } from 'devextreme/excel_exporter'; +import { exportDataGrid as exportDataGridToPDF } from 'devextreme/pdf_exporter'; +import { jsPDF, jsPDFOptions } from 'jspdf'; +import { Workbook } from 'exceljs'; +import { saveAs } from 'file-saver'; +import config from 'devextreme/core/config'; +import { licenseKey } from '../devextreme-license'; + + +export interface HRExportDataFromDxGrid { + gridComponent: any; + fileName: string; + title?: { + text?: string; + tabName?: string; + align?: 'left' | 'center' | 'right' | 'justify'; + x?: number; + y?: number; + divX?: number + }; + margin?: { top: number; right: number; bottom: number; left: number }; + pdfOptions?: jsPDFOptions; + repeatHeaders?: boolean; + customizeCallback?: (any) => void; + finalizeCallback?: () => void; +} + +export interface IMessageBoxButton { + title: string; + hint?: string; + code?: number; + default?: boolean; + cancel?: boolean; + callback?: () => void; +} + +export interface IMessageBoxData { + type: EN_LogType; + overHeader?: string; + header: string; + message: string; + buttons: IMessageBoxButton[]; +} + +export interface IAppPage extends Route { + caption: string; + icon?: string; + messageCaption?: string; + hidden?: boolean; + allowRedirect?: boolean; + disabled?: boolean; + showIconInNavbar?: boolean; + dontAllowEmptyURL?: boolean; +} + +export const LOGIN_PAGE: IAppPage = { + caption: 'core.caption.login', + path: 'login', + loadChildren: () => import('../components/login/login.module').then(m => m.LoginModule), + icon: 'logout', + allowRedirect: true, + hidden: true, + messageCaption: 'stammdaten', +}; + +export const ACCOUNT_PAGE: IAppPage = { + caption: 'core.caption.account', + path: 'account', + loadChildren: () => import('../components/account/account.module').then(m => m.AccountModule), + icon: 'account_circle', + hidden: false, + messageCaption: 'My Account', + showIconInNavbar: true +}; + +export enum EN_CoreEntities { + User = 'WebAppUser', + ServerInfo = 'Info' +} + +config({ licenseKey }); + + +@Injectable({ providedIn: 'root' }) + +export class Globals { + public hrColorDarkBlue: string = '#0b3a62'; + public hrColorLightBlue: string = '#78b7e5'; + public hrColorLightGrey: string = '#878787'; + public hrColorDarkGrey: string = '#3c3c3b'; + public hrColorGreen: string = '#76b82a'; + + public appTitle: string; + public appTitleWithVersion: string; + public currentPage: string; //path of the urrent page + public urlParam: string; //parameter in url + public mainPage: IAppPage; + public ipAddress: string; + public showIds: boolean = false; + + public appPages: IAppPage[] = [ + LOGIN_PAGE, + ]; + + constructor( + @Inject(LOCALE_ID) private locale: string + ) { } + + + isTheMainPage(page: string = null): boolean { + return this.isThePage(this.mainPage.path, page); + } + + isTheLoginPage(page: string = null): boolean { + return this.isThePage(LOGIN_PAGE.path, page); + } + + isTheCurrentPage(pageInx: number): boolean { + return this.isThePage(this.appPages[pageInx].path); + } + + isVisiblePage(page: string = null): boolean { + const pg = this.appPages.find((_pg: IAppPage) => this.isThePage(_pg.path, page)); + return (pg && !pg.hidden); + } + + isThePage(pagePath: string, page: string = null): boolean { + return page ? ((!page.startsWith('/') ? '/' : '') + page + '/').startsWith('/' + pagePath + '/') : (this.currentPage + '/').startsWith(pagePath + '/'); + } + + getPageIndex(page: string): number { + return this.appPages.findIndex((pg) => pg.path === page); + } + + + getPage(page: string): IAppPage { + const indx = this.getPageIndex(page); + return indx > -1 ? this.appPages[indx] : null; + } + + //------------------------------------------ + + public formatNumber(data: any, frac: number): string { + if (data === null || data === undefined) return ''; + if (typeof data === 'object') return utils.formatNumbers(this.locale, +data.value, frac); + else return utils.formatNumbers(this.locale, +data, frac); + } + + + formatNumber_0(data: any): string { + return this.formatNumber(data, 0); + } + + formatNumber_1(data: any): string { + return this.formatNumber(data, 1); + } + + formatNumber_2(data: any): string { + return this.formatNumber(data, 2); + } + + formatNumber_3(data: any): string { + return this.formatNumber(data, 3); + } + + formatNumber_4(data: any): string { + return this.formatNumber(data, 4); + } + + get localeDecimalSeparator(): string { + return utils.getDecimalSeparator(this.locale); + } + + get localeThousandSeparator(): string { + return utils.getThousandSeparator(this.locale); + } + + get localeDateFormat(): string { + return utils.getDateFormat(this.locale); + } + + get localeDateTimeFormat(): string { + return utils.getDateTimeFormat(this.locale); + } + + + exportToPDF(option: HRExportDataFromDxGrid) { + const doc = new jsPDF(option.pdfOptions); + doc.text(option.title.text, option.title.x ?? doc.internal.pageSize.width / option.title.divX, option.title.y ?? 15, { align: option.title.align ?? 'center' }); + exportDataGridToPDF({ + jsPDFDocument: doc, + component: option.gridComponent, + repeatHeaders: option.repeatHeaders ?? true, + margin: option.margin, + customizeCell: (options) => { if (option.customizeCallback) option.customizeCallback(options); } + }).then(() => { + doc.save(option.fileName); + if (option.finalizeCallback) option.finalizeCallback(); + }); + } + + + + public exportToExcel(option: HRExportDataFromDxGrid) { + const workbook = new Workbook(); + const worksheet = workbook.addWorksheet(option.title?.tabName ?? utils.removeSpecialChars(option.fileName)); + const self = this; + + const exportToExcel = 'dxPivotGrid' === option.gridComponent.NAME ? exportPivotGridToExcel : exportDataGridToExcel; + exportToExcel({ + component: option.gridComponent, + worksheet: worksheet, + topLeftCell: option.margin ? { row: option.margin.top, column: option.margin.left } : null, + customizeCell: (options) => { if (option.customizeCallback) option.customizeCallback(options); } + }).then(function () { + workbook.xlsx.writeBuffer() + .then((buffer: BlobPart) => { + saveAs(new Blob([buffer], { type: 'application/octet-stream' }), option.fileName + '.xlsx'); + }); + if (option.finalizeCallback) option.finalizeCallback(); + }); + } + + + public doExcelExportSimple(e: any, filename, dontExportFieldnameTemplatenameList?: string) { + this.exportToExcel({ + fileName: filename + , gridComponent: e.component + , customizeCallback: 'dxPivotGrid' === e.component.NAME && !!dontExportFieldnameTemplatenameList ? this.dontExportFieldnameTemplatename.bind(this, dontExportFieldnameTemplatenameList) : null + }); + } + + + private dontExportFieldnameTemplatename(dontExportFieldnameTemplatenameList: string, options: any) { + const { gridCell, excelCell } = options; + dontExportFieldnameTemplatenameList = ',' + dontExportFieldnameTemplatenameList.replace(' ', '').toLocaleLowerCase() + ','; + + if (!!gridCell.column?.cellTemplate && dontExportFieldnameTemplatenameList.indexOf(',#' + gridCell.column?.cellTemplate.toLocaleLowerCase() + ',') > -1 + || !!gridCell.column?.dataField && dontExportFieldnameTemplatenameList.indexOf(',' + gridCell.column?.dataField.toLocaleLowerCase() + ',') > -1 + ) { + excelCell.value = null; + excelCell._column.hidden = true; + } + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/http/http-interceptor.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/http/http-interceptor.service.ts new file mode 100644 index 0000000..16a48aa --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/http/http-interceptor.service.ts @@ -0,0 +1,157 @@ +import { Injectable, Inject } from '@angular/core'; +import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpHeaders, HttpErrorResponse, HttpResponse } from '@angular/common/http'; +import { Observable, throwError } from 'rxjs'; +import { catchError, tap, finalize } from 'rxjs/operators'; +import { AppLogsService } from '../applogs.service'; +import { AuthorizeService } from '../authorize.service'; +import * as Utils from '../../utils'; +import * as Const from '../../consts'; +import { InMemoryDataService } from '../in-memory-data.service'; +import { ENVIRONMENT_TOKEN, IENVIRONMENT } from '../../injection-tokens'; + +@Injectable({ + providedIn: 'root' +}) + +export class HttpInterceptorService implements HttpInterceptor { + constructor( + private appLogsservice: AppLogsService, + private authorizeService: AuthorizeService, + private mockDataService: InMemoryDataService, + @Inject(ENVIRONMENT_TOKEN) private environment: IENVIRONMENT, + ) { } + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + const clone = request.clone(this.prepareOptions(request.headers)); + + const guid = Utils.guid(); + const operation = `${request.method}: ${request.url}`; + this.appLogsservice.dlog('%c# HTTP Request ' + operation, { guid: guid }, 'color:' + Const.EN_AppColors.startRequestColor); + let ok: string; + + const splittedURL = request.url.split(/\//g); + let querySufix: string = ''; + const base: number = splittedURL[4] ? 4 : 3; + if (request.method === 'GET') { + querySufix = splittedURL[base] + (splittedURL.length < base + 2 ? ': list' : ''); + } else { + for (let i = base; i < splittedURL.length; i++) { + querySufix += (i === base ? '' : '/') + splittedURL[i]; + } + } + + const mockDataResponse: Observable> = this.mockDataService.parseMockData(request, guid); + if (mockDataResponse) return mockDataResponse; + + return next.handle(clone) + .pipe( + tap({ + next: (event: HttpEvent) => ok = event instanceof HttpResponse ? 'SUCCEDED' : '', + error: (error: HttpErrorResponse) => ok = 'FAILED', + complete: () => { this.appLogsservice.dlog(querySufix, { guid: guid }, 'color:' + Const.EN_AppColors.returnRequestColor); } + } + ), + + //retry(2), + catchError((error: HttpErrorResponse) => { + + // this.appLogsservice.error(Utils.getErrorMessageAsText(error), { error }); + this.appLogsservice.exception(error); + + if (error.status === Const.cnst_ErrorCode4Unauthorized) { // 401 handled in auth.interceptor + // this.authorizeService.loginPopup(Const.cnst_JWT_Expired); + this.authorizeService.tryRenewJWTAsync(); + } + return throwError(() => error); + }), + // Log when response observable either completes or errors + // finalize( + // () => { this.appLogsservice.log(querySufix, { guid: guid }, 'color:' + Const.EN_AppColors.returnRequestColor); } + // ), + ) + ; + } + + + prepareOptions(sentHeader?: HttpHeaders, withBearer: boolean = true): any { + let headerAdditionalKeys: HttpHeaders = null; + if (!!this.environment.headerData) headerAdditionalKeys = new HttpHeaders(this.environment.headerData); + + let header: HttpHeaders = null; + if (sentHeader) header = sentHeader; + else { + header = new HttpHeaders(); + header = header + .append('Content-Type', 'application/json') + .append('Accept', 'application/json'); + } + //if (headerAdditionalKeys) header = header.append(headerAdditionalKeys.getAll); + + if (withBearer && this.authorizeService.useJWT && this.authorizeService.HR_JWT) header = header.append('Authorization', 'Bearer ' + this.authorizeService.HR_JWT.idToken); + const withCredent: boolean = this.authorizeService.loginStatus === this.authorizeService.EN_LoginStatus_Windows || + this.authorizeService.loginStatus === this.authorizeService.EN_LoginStatus_Unknown && !this.authorizeService.useJWT && !headerAdditionalKeys; + return { + headers: header, + withCredentials: withCredent + }; + } + /* intercept(request: HttpRequest, next: HttpHandler): Observable> { + + const users: User[] = [ + { id: 1, username: 'test', password: 'test', firstName: 'Test', lastName: 'User' } + ]; + + const authHeader = request.headers.get('Authorization'); + const isLoggedIn = authHeader && authHeader.startsWith('Bearer fake-jwt-token'); + + // wrap in delayed observable to simulate server api call + return of(null).pipe(mergeMap(() => { + + // authenticate - public + if (request.url.endsWith('/users/authenticate') && request.method === 'POST') { + const user = users.find(x => x.username === request.body.username && x.password === request.body.password); + if (!user) return error('Username or password is incorrect'); + return ok({ + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + token: `fake-jwt-token` + }); + } + + // get all users + if (request.url.endsWith('/users') && request.method === 'GET') { + if (!isLoggedIn) return unauthorised(); + return ok(users); + } + + // pass through any requests not handled above + return next.handle(request); + })) + // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648) + .pipe(materialize()) + .pipe(delay(500)) + .pipe(dematerialize()); + + // private helper functions + + function ok(body) { + return of(new HttpResponse({ status: 200, body })); + } + + function unauthorised() { + return throwError({ status: 401, error: { message: 'Unauthorised' } }); + } + + function error(message) { + return throwError({ status: 400, error: { message } }); + } + }*/ +} +// export let fakeBackendProvider = { +// // use fake backend in place of Http service for backend-less development +// provide: HTTP_INTERCEPTORS, +// useClass: FakeBackendInterceptor, +// multi: true +// }; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/http/repository.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/http/repository.service.ts new file mode 100644 index 0000000..828f866 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/http/repository.service.ts @@ -0,0 +1,93 @@ +import { Inject, Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { AppLogsService } from '../applogs.service'; +import { cnst_IP_ADDRESS_SOURCE_URL } from '../../consts'; +import { AuthorizeService } from '../authorize.service'; +import { ENVIRONMENT_TOKEN, IENVIRONMENT } from '../../injection-tokens'; + +@Injectable({ + providedIn: 'root' +}) +export class RepositoryService { + public authService: AuthorizeService; + private apiUrl: string; + + constructor( + private httpClient: HttpClient, + private appLogService: AppLogsService, + @Inject(ENVIRONMENT_TOKEN) environment: IENVIRONMENT, + ) { + this.apiUrl = environment.apiUrl; + } + + // tslint:disable-next-line: no-shadowed-variable + deleteDataById(routing: string, id: string | number): Observable { + // tslint:disable-next-line: triple-equals + const filterstr = (id && id != '0' ? '/' + id.toString() : ''); + return this.httpClient.delete(this.apiUrl + '/' + routing + filterstr).pipe(map(response => response as T)); + } + + getDataById(routing: string, id: string | number): Observable { + // tslint:disable-next-line: triple-equals + const filterstr = (id && id != '0' && id != -1 ? '/' + id.toString() : ''); + return this.getDataByURLFilter(routing, filterstr); + } + + + putDataById(routing: string, id: string | number, obj: any): Observable { + // tslint:disable-next-line: triple-equals + // if (id && !Number.isNaN(Number(id)) && id != '0') + return this.putData(routing + '/' + id.toString(), obj); + } + + + postDataById(routing: string, id: string | number, obj: any): Observable { + // tslint:disable-next-line: triple-equals + let suffix: string = ''; + if (typeof id === 'number' || !Number.isNaN(Number(id))) { + if (Number(id) > 0) suffix = id.toString(); + } else suffix = id; + const filterstr = (suffix ? '/' + suffix : ''); + return this.postData(routing + filterstr, obj); + } + + + getDataByObjFilter(routing: string, filter: any): Observable { + this.appLogService.dlog('filter=', filter); + return this.postData(routing + (filter.filterPrefix ? '/' + filter.filterPrefix : ''), filter); + } + + + getDataByURLFilter(routing: string, filter: string): Observable { + return this.getData(routing + (filter && filter !== '' ? ((filter).slice(0, 1) !== '/' ? '/' : '') + filter : '')/*, getMethodName()*/); + } + + public putData(routing: string, obj: any, headers?: HttpHeaders): Observable { + return this.httpClient.put(this.apiUrl + '/' + routing, obj, { headers: headers }).pipe(map(response => response as T)); + } + + + public postData(routing: string, obj: any, headers?: HttpHeaders): Observable { + return this.httpClient.post(this.apiUrl + '/' + routing, obj, { headers: headers }).pipe(map(response => response as T)); + } + + public getData(routing: string, headers?: HttpHeaders): Observable { + return this.httpClient.get(this.apiUrl + '/' + routing, { headers: headers }).pipe(map(response => response as T)); + } + + public getIPAddress(): Observable { + return this.httpClient.get(cnst_IP_ADDRESS_SOURCE_URL); + } + + // public async getData(routing: string, headers?: HttpHeaders): Promise> { + // return this.httpClient.get(this.apiUrl + '/' + routing, { headers: headers }) + // .pipe( + // map(response => of(response as T)) + // , catchError(async (error: any) => { + // return of(null); + // })).toPromise(); + // } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/in-memory-data.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/in-memory-data.service.ts new file mode 100644 index 0000000..53cc190 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/in-memory-data.service.ts @@ -0,0 +1,63 @@ +import { InMemoryDbService } from 'angular-in-memory-web-api'; +import { Observable, of } from 'rxjs'; +import { HttpEvent, HttpResponse, HttpRequest } from '@angular/common/http'; +import * as Const from '../consts'; +import { AppLogsService } from './applogs.service'; +import { Injectable } from '@angular/core'; +import { delay } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root' +}) + +export class InMemoryDataService implements InMemoryDbService { + + constructor(private appLogsService: AppLogsService) { } + createDb() { + return {}; + } + + parseMockData(request: HttpRequest, guid: string): Observable> { + return undefined; + } + + + mockingInterception(request: HttpRequest, splittedURL: string[], filterStr: string, guid: string) { + let resp: Observable> = null; + switch (request.method) { + case 'PUT': + case 'POST': + resp = this.postMockData(request.body); + break; + case 'GET': + resp = this.getMockData(splittedURL[4], filterStr); + break; + case 'DELETE': + resp = this.deleteMockData(+splittedURL[5]); + break; + } + if (resp) { + this.appLogsService.dlog(splittedURL[4] + (splittedURL.length < 6 ? ': list' : ''), { guid: guid }, 'color:' + Const.EN_AppColors.returnRequestColor); + return resp.pipe(delay(500)); + } + } + + + getMockData(entityBase: string, entityFilterstring: string): Observable> { + return of(new HttpResponse( + { status: 200, body: this.getFilteredDataList(entityFilterstring) } + )); + } + + postMockData(entity: any): Observable> { + return of(new HttpResponse({ status: 200, body: Object.assign({}, entity) })); + } + + deleteMockData(id: number): Observable> { + return of(new HttpResponse({ status: 200 })); + } + + getFilteredDataList(entityFilterstring: string): any { + return null; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/localization/hensel-translate.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/localization/hensel-translate.service.ts new file mode 100644 index 0000000..b5253b0 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/localization/hensel-translate.service.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +@Injectable({ + providedIn: 'root', +}) + +export class HenselTranslateService extends TranslateService { + + public instant(key: string | Array, interpolateParams?: Object): string | any { + if (!key) return ''; + return super.instant(key, interpolateParams); + } + + public translateString(stringToTranslate: string) { + let res = stringToTranslate?.replace(/\${(.*?)}/g, (found: string, translationKey: string) => this.instant(translationKey)); + if (res === stringToTranslate) res = this.instant(res); // source string does not contain placeholder "${}" - try to translate directly + return res; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/localization/locale.provider.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/localization/locale.provider.ts new file mode 100644 index 0000000..af6f5d1 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/localization/locale.provider.ts @@ -0,0 +1,23 @@ +import { LOCALE_ID, Provider } from '@angular/core'; +import { LocaleService } from './locale.service'; + +export class LocaleId extends String { + constructor(private localeService: LocaleService) { + super(); + } + + toString(): string { + return this.localeService.currentCulture; + } + + valueOf(): string { + return this.toString(); + } +} + + +export const LocaleProvider: Provider = { + provide: LOCALE_ID, + useClass: LocaleId, + deps: [LocaleService], +}; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/localization/locale.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/localization/locale.service.ts new file mode 100644 index 0000000..8665b63 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/localization/locale.service.ts @@ -0,0 +1,119 @@ +import { Injectable, Optional, SkipSelf } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { noop } from 'rxjs'; +import * as localization from 'devextreme/localization'; +import * as deMessages from 'devextreme/localization/messages/de.json'; +import * as enMessages from 'devextreme/localization/messages/en.json'; +import * as frMessages from 'devextreme/localization/messages/fr.json'; +import { getCurrencySymbol, getDateFormat, getDateTimeFormat, getDecimalSeparator, getLocaleCurrencyCode, getThousandSeparator } from '../../utils'; +import { HenselTranslateService } from './hensel-translate.service'; + +const langMessages: { [key: string]: any } = { en: enMessages, de: deMessages, fr: frMessages }; + +type ShouldReuseRoute = (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) => boolean; + +@Injectable({ + providedIn: 'root', +}) + + +export class LocaleService { + + + public dateFormat: string; + public dateTimeFormat: string; + public thousandSeparator: string; + public decimalSeparator: string; + public currencyCode: string; + public currencySymbol: string; + + private initialized = false; + + private _currentCulture: string; + get currentCulture(): string { + return this._currentCulture; + } + set currentCulture(culture: string) { + const oldCulture = this._currentCulture; + this.setCultureWOReload(culture); + if (oldCulture !== culture) setTimeout(() => this.reloadPages()); + } + + set currentLocale(culture: string) { + this.setCultureWOReload(culture); + this.currentLanguage = culture; + } + + private _currentLanguage: string; + get currentLanguage(): string { + return this._currentLanguage; + } + set currentLanguage(lang: string) { + this._currentLanguage = lang.split('-')[0]; //it can take culture as argument too + // locale(this.currentLanguage); + this.translate.use(lang); + } + + constructor( + private router: Router, + public translate: HenselTranslateService, + @Optional() + @SkipSelf() + otherInstance: LocaleService, + ) { + if (otherInstance) throw new Error('LocaleService should have only one instance.'); + } + + + private setCultureWOReload(culture: string) { + this._currentCulture = culture; + this.dateFormat = getDateFormat(culture); + this.dateTimeFormat = getDateTimeFormat(culture); + this.thousandSeparator = getThousandSeparator(culture); + this.decimalSeparator = getDecimalSeparator(culture); + this.currencyCode = getLocaleCurrencyCode(culture); + this.currencySymbol = getCurrencySymbol(culture); + + // const lang = culture.split('-')[0]; + // const messages = {}; + // messages[lang] = langMessages[this.currentLanguage]; + // localization.loadMessages(messages); + localization.locale(culture); + } + + private setRouteReuse(reuse: ShouldReuseRoute) { + this.router.routeReuseStrategy.shouldReuseRoute = reuse; + } + + private subscribeToLangChange() { + this.translate.onLangChange.subscribe(() => { + this.reloadPages(); + }); + } + + + reloadPages = async () => { + const { shouldReuseRoute } = this.router.routeReuseStrategy; + + this.setRouteReuse(() => false); + this.router.navigated = false; + + await this.router.navigateByUrl(this.router.url).catch(noop); + this.setRouteReuse(shouldReuseRoute); + } + + + initLocaleLanguage(culture: string, lang?: string) { + if (this.initialized) return; + + this.setCultureWOReload(culture); + this.currentLanguage = lang ?? culture; + this.translate.setDefaultLang(this.currentLanguage); + setTimeout(() => this.subscribeToLangChange(), 1000); //delay avoid to fire onLangChange at the init - app start, otherwise start url will be overwritten + + this.initialized = true; + console.log('Locale is initialized !!'); + } + + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/localization/translation-loader.provider.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/localization/translation-loader.provider.ts new file mode 100644 index 0000000..d37e20d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/localization/translation-loader.provider.ts @@ -0,0 +1,22 @@ +import { Provider } from '@angular/core'; +import { TranslateLoader } from '@ngx-translate/core'; +import { HttpBackend } from '@angular/common/http'; +import { MultiTranslateHttpLoader } from 'ngx-translate-multi-http-loader'; +import { ENVIRONMENT_TOKEN, IENVIRONMENT } from '../../injection-tokens'; + + + +export function HttpLoaderFactory(_httpBackend: HttpBackend, environment: IENVIRONMENT): TranslateLoader { + return new MultiTranslateHttpLoader(_httpBackend, [ + { prefix: './assets/translate-core/', suffix: '.json' }, + { prefix: environment.translationFolder, suffix: '.json' }, + ] + ); +} + + +export const TranslateLoaderProvider: Provider = { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpBackend, ENVIRONMENT_TOKEN], +}; diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/mat-dialog.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/mat-dialog.service.ts new file mode 100644 index 0000000..a90f7f8 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/mat-dialog.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import { PopupBaseComponent } from '../components/popup-base/popup-base.component'; +import { MatDialog, MatDialogConfig, MatDialogRef } from '../components/angular-material-index'; + +@Injectable({ + providedIn: 'root' +}) +export class MatDialogService { + + constructor(private dialog: MatDialog) { } + + public openDialog(dialogComponent: any, dataObject: Object, isModal: boolean = false, onCloseDialog?: (_) => void, autofocus: boolean = true): + MatDialogRef { + const dialogConfig = new MatDialogConfig(); + if (dialogComponent instanceof PopupBaseComponent) isModal = true; // we open derived from PopupBaseComponent popup dialogs + // only as modal to shure executing of cancel function, thats reset BaseEntityWrapper + dialogConfig.disableClose = isModal; + dialogConfig.autoFocus = autofocus; + dialogConfig.data = dataObject; + const dialog = this.dialog.open(dialogComponent, dialogConfig); + dialog.afterClosed().subscribe(result => { + if (onCloseDialog) onCloseDialog(result); + }); + return dialog; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/notification/uinotification.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/notification/uinotification.ts new file mode 100644 index 0000000..50f036d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/notification/uinotification.ts @@ -0,0 +1,46 @@ +export enum EN_UINotificationType { + info = 1, + warn = 2 +} +export class UINotification { + + message: string; + type: EN_UINotificationType; + isActive: boolean; + createdTimestamp: Date; + displayedTimestamp: Date; + finishedTimestamp: Date; + duration: number; + id: number; + + constructor(message: string, type: EN_UINotificationType, duration: number, id: number) { + this.message = message; + this.isActive = true; + this.type = type; + this.createdTimestamp = new Date(); + this.duration = duration; + this.id = id; + } + + public stopMessage(): void { + this.finishedTimestamp = new Date(); + this.isActive = false; + } + + public durationExpired(timeInSeconds: number) { + if (this.displayedTimestamp && this.duration > 0) { + if (timeInSeconds >= this.displayedTimestamp.getTime() + this.duration) { + return true; + } + } + return false; + } + + public getStyleColor(): string { + if (this.type === EN_UINotificationType.info) { + return 'secondary'; + } else { + return 'primary'; + } + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/notification/uinotifier.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/notification/uinotifier.service.ts new file mode 100644 index 0000000..aa39734 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/notification/uinotifier.service.ts @@ -0,0 +1,187 @@ +import { Injectable } from '@angular/core'; +import { interval, Subject, Subscription } from 'rxjs'; +import { AppLogsService } from '../applogs.service'; +import { EN_UINotificationType, UINotification } from './uinotification'; +import { MatSnackBar, MatSnackBarConfig, MatSnackBarHorizontalPosition, MatSnackBarRef, MatSnackBarVerticalPosition, TextOnlySnackBar } from '../../components/angular-material-index'; + + +const cnst_NotifierNachrichtDauer = 1000; +const nachrichtVisible = true; + +class HenselMatSnackBarConfig extends (MatSnackBarConfig) { + constructor(obj: any) { + super(); + Object.assign(this, obj); + } +} + +@Injectable({ + providedIn: 'root' +}) +export class UINotifierService { + private readonly MAX_INACTIVE_ITEMS: number = 5; + private activeItems: UINotification[]; + private inactiveItems: UINotification[]; + private idCounter: number; + + msbPoxPosition: { horizontal: MatSnackBarHorizontalPosition, vertical: MatSnackBarVerticalPosition } = { horizontal: 'center', vertical: 'bottom' }; + + public data$: Subject; + public isActive: boolean = true; + protected pollingItervalTimer: Subscription = null; + private currentSnackBar: MatSnackBarRef; + + constructor( + private appLogsService: AppLogsService, + public snackBar: MatSnackBar, + ) { + this.data$ = new Subject(); + this.data$.subscribe((lastNotification: UINotification) => this.showNotification(lastNotification)); + + this.activeItems = []; + this.inactiveItems = []; + this.idCounter = 1; + } + + + stopPolling() { + this.hide(); + this.pollingItervalTimer?.unsubscribe(); + this.pollingItervalTimer = null; + } + + + startPolling() { + if (!this.pollingItervalTimer) this.pollingItervalTimer = interval(100).subscribe(this.checkinOnTimer); + } + + + private checkinOnTimer = () => { + if (this.activeItems.length === 0) { + this.stopPolling(); + } else { + // this.appLogsService.dlog('->timer active:' + this.activeItems.length + ', inactive' + this.inactiveItems.length); + const start = new Date().getTime(); + let item = this.activeItems[0]; + if (item.durationExpired(start)) { + this.stopMessage(item.id); + if (this.activeItems.length > 0) item = this.activeItems[0]; + } + if (item && !item.displayedTimestamp) this.data$.next(item); + // this.appLogsService.dlog('<-timer active:' + this.activeItems.length + ', inactive' + this.inactiveItems.length); + } + } + + + + // remove last MAX_INACTIVE_ITEMS + cleanUp(item: UINotification) { + const index: number = this.activeItems.indexOf(item); + if (index !== -1) this.activeItems.splice(index, 1); + this.inactiveItems.splice(0, 0, item); // neueste zuerst + + if (this.inactiveItems.length > this.MAX_INACTIVE_ITEMS) { + this.inactiveItems.splice(this.MAX_INACTIVE_ITEMS); + } + + } + + clearAll() { + this.activeItems = []; + this.inactiveItems = []; + } + + private createNew(message: string, type: EN_UINotificationType, duration: number): UINotification { + this.idCounter++; + return new UINotification(message, type, duration, this.idCounter); + } + + public getActiveItems(): UINotification[] { + return this.activeItems; + } + + public getInactiveItems(): UINotification[] { + return this.inactiveItems; + + } + public isVisible(): boolean { + return this.activeItems.length > 0; + } + + public getInactiveMessages(): string { + let msg = ''; + this.inactiveItems.forEach((item: UINotification) => { + msg += item.message + '; '; + }); + + return msg; + } + + public getActiveMessages(): string { + let msg = ''; + this.activeItems.forEach((item: UINotification) => { + msg += item.message + '; '; + }); + return msg; + } + + // return: new id + public showMessage(message: string, msgId?: number, duration: number = cnst_NotifierNachrichtDauer): number { + return this.add2Queue(message, msgId, duration, EN_UINotificationType.info); + } + + public showWarning(message: string, msgId?: number, duration: number = cnst_NotifierNachrichtDauer): number { + return this.add2Queue(message, msgId, duration, EN_UINotificationType.warn); + } + + private add2Queue(message: string, msgId: number, duration: number = cnst_NotifierNachrichtDauer, notifType: EN_UINotificationType): number { + if (!this.isActive) return; + if (msgId) { this.stopMessage(msgId); } + const item = this.createNew(message, notifType, duration); + if (this.activeItems.length > 0) { + const lastWaitingItim = this.activeItems[this.activeItems.length - 1]; + if (!lastWaitingItim.displayedTimestamp) lastWaitingItim.duration /= 4; + } + this.activeItems.push(item); + this.startPolling(); + return item.id; + } + + public stopMessage(id: number) { + const foundItem = this.activeItems.find((item: UINotification) => item.id === id); + if (foundItem) { + foundItem.stopMessage(); + this.cleanUp(foundItem); + } + } + + public updateMessage(id: number, message: string) { + this.appLogsService.dlog('updateMessage id:' + id + ' ' + message); + const foundedItem = this.activeItems.filter((item: UINotification) => item.id === id); + if (foundedItem && foundedItem[0]) { + this.appLogsService.dlog('found updateMessage id:' + id + ' ' + message); + + foundedItem[0].message = message; + } + } + + hide() { + this.appLogsService.dlog('<-Hide Message'); + this.snackBar.dismiss(); + } + + + showNotification(lastNotification: UINotification): void { + this.hide(); + lastNotification.displayedTimestamp = new Date(); + this.currentSnackBar = this.snackBar.open(lastNotification.message, undefined, new HenselMatSnackBarConfig( + { + horizontalPosition: this.msbPoxPosition.horizontal, + verticalPosition: this.msbPoxPosition.vertical, + duration: lastNotification.duration, + panelClass: 'hensel-notifier' + } + )); + this.appLogsService.dlog('Show Message id:' + lastNotification.id + ' ' + lastNotification.message); + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/page.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/page.service.ts new file mode 100644 index 0000000..a7599f9 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/page.service.ts @@ -0,0 +1,245 @@ +import { PageLoadingService } from '../services/pageloading.service'; +import { Globals, IAppPage } from './globals'; +import { AppLogsService } from './applogs.service'; +import { AuthorizeService } from './authorize.service'; +import { CoreUser } from '../models/coreuser'; +import { Router } from '@angular/router'; +import { BaseEntity, BaseEntityCallBack, ErrorCallBack } from '../models/generics/baseentity'; +import { BaseEntityListWrapper } from '../models/generics/baseentitylist.wrapper'; +import { BehaviorSubject, Subscription } from 'rxjs'; +import { HenselTranslateService } from './localization/hensel-translate.service'; +import { inject } from '@angular/core'; +import { BaseEntityWrapper } from '../models/generics/baseentity.wrapper'; +import { MatDialogService } from './mat-dialog.service'; +import { LocaleService } from './localization/locale.service'; +import { RepositoryService } from './http/repository.service'; + +export class CorePageService { + protected appPage: number; + protected get applicationPage(): any { + return this.appPage; + } + protected get appPageNoQueries(): number { + return 0; + } + protected standAlone: boolean = true; //true = page data are not depended from the global data.service, and must be loaded explicetely + + protected loadImedeately: boolean = false; //load on opening the page + protected entityList4Routing: BaseEntityListWrapper; + public loadedOverRoutingCallBack: BaseEntityCallBack = null; + public loadRoutingEntityCallBack: (entityId: number, _loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void) => void; + public loadedOverRoutingOneTimeCallBack: BaseEntityCallBack = null; + public lastURL: string; + public pageBaseDateWereLoaded$: BehaviorSubject = new BehaviorSubject(false); + private _loadFromTheSamePage: boolean = false; + public get loadFromTheSamePage(): boolean { + return this._loadFromTheSamePage; + } + protected set loadFromTheSamePage(value: boolean) { + this._loadFromTheSamePage = value; + } + private _isLoadingOverRouting: boolean = false; + public get isLoadingOverRouting(): boolean { + return this._isLoadingOverRouting; + } + protected set isLoadingOverRouting(value: boolean) { + this._isLoadingOverRouting = value; + } + protected translationService = inject(HenselTranslateService); + protected globalsService: Globals = inject(Globals); + protected pageLoadingService: PageLoadingService = inject(PageLoadingService); + protected appLogsService: AppLogsService = inject(AppLogsService); + protected authService?: AuthorizeService = inject(AuthorizeService); + protected router?: Router = inject(Router); + protected dialog: MatDialogService = inject(MatDialogService); + protected localeService: LocaleService = inject(LocaleService); + protected repoService: RepositoryService = inject(RepositoryService); + + protected backgroundLoading: boolean = false; //no need background loading at first time + + protected baseEntityWrapperWaitLoadingSubscription: Subscription; + public set baseEntityWrapperWaitLoading(pageDetails: BaseEntityWrapper) { + this.baseEntityWrapperWaitLoadingSubscription = pageDetails.entityIsLoading$.subscribe((isLoading: boolean) => { + if (isLoading) this.pageLoadingService.showSpinner(); + else this.pageLoadingService.hideSpinner(); + }); + } + + + protected isPageActive(): boolean { + return this.globalsService.currentPage === this.globalsService.appPages[this.applicationPage].path; + } + + constructor( + ) { + this.finalise = this.finalise.bind(this); + this.pageLoadingService.pageActive$.subscribe((param?: string) => { + if (this.isPageActive()) { + setTimeout(() => this.onPageActivated(param)); + } else this.loadFromTheSamePage = false; + }); + + if (this.authService) { + this.authService.loginLogout$.subscribe((user: CoreUser) => { + setTimeout(() => this.onLoggedInOut(new CoreUser(user)), 0); //wait till oncreate is finished + }); + } + } + + protected init( + ) { + this.lastURL = '/' + this.globalsService.appPages[this.applicationPage].path; + + if (//!this.globalsService.isTheMainPage() && !this.standAlone || // do not need, because if !this.standAlone, then forgroundLoading$ fires imedeately after create the service, because it is a behaviour + //after creating loads data for not standalone page except main page - for it loading is calling after stammdata are loaded on forgroundLoading$ event + this.loadImedeately && this.standAlone // or load data always the page is created and is standalone (depends from data another pages) + || this.isPageActive() && this.globalsService.urlParam) //or not created page is opened with the id as url param + { + setTimeout(() => this.onPageActivated(this.isPageActive() ? this.globalsService.urlParam : null)); //must fire after init and onLoggedInOut + } + + if (!this.standAlone) { + this.pageLoadingService.forgroundLoading$.subscribe(() => { if (this.isPageActive()) this.loadData(); }); //load data if it is the current page + //if page is loadImedeately - is loaded on activating - there is no sense to load it in bachground + if (!this.loadImedeately) this.pageLoadingService.backgroundLoading$.subscribe(() => { if (!this.isPageActive()) this.loadData(); }); //load data in background if it is not the current page + } + } + + protected onPageActivated(param: string) { + this.doRouting4Id(param); + } + + + private loadOnPageAcivated() { + this.backgroundLoading = false; //no need background loading + this.loadData(); + } + + + protected finalise() { + this.pageLoadingService.updatePageLoadedCounters(this.appPage); + } + + + protected doRouting4Id(paramId: string | number) { + if (this.entityList4Routing) { + if (!paramId /*|| Number.isNaN(Number(paramId)) || Number(paramId) === 0*/) { //without parameters + if (this.loadImedeately && !this.loadFromTheSamePage) this.loadOnPageAcivated(); + else { + if (!this.entityList4Routing.focusedItemId) { + if (this.entityList4Routing.focusedEntityShadowed) { + this.entityList4Routing.focusedEntityShadowed.clear(); + this.entityList4Routing.focusedEntityShadowed.entityIsLoading = false; // to fire loaded$ for empty lists + } + } else this.entityList4Routing.focusedRoutingCallBack(this.entityList4Routing.focusedItem); + } + this.loadFromTheSamePage = false; + } else { + if (!Number.isNaN(Number(paramId)) + && Number(paramId) !== 0 + && this.entityList4Routing.focusedEntityShadowed + && this.entityList4Routing.focusedEntityShadowed.inViewMode + ) { //load details entity from the url params + let loadFn: (entityId: number, _loadedCallBack?: BaseEntityCallBack, _errorCallBack?: ErrorCallBack, _completeCallBack?: () => void) => void; + this.isLoadingOverRouting = true; + + if (this.loadRoutingEntityCallBack) { + loadFn = this.loadRoutingEntityCallBack; + } else loadFn = this.entityList4Routing.focusedEntityShadowed.load.bind(this.entityList4Routing.focusedEntityShadowed); + + loadFn(Number(paramId), + (entity) => { + if (!entity || !entity.entityId) { + this.navigateLastURL(); + } else { + this.lastURL = this.router?.url; + if (this.loadedOverRoutingOneTimeCallBack) { + this.loadedOverRoutingOneTimeCallBack(); + this.loadedOverRoutingOneTimeCallBack = null; + } else { + if (this.loadedOverRoutingCallBack) this.loadedOverRoutingCallBack(); + } + } + this.isLoadingOverRouting = false; + }, + () => { + this.isLoadingOverRouting = false; + this.navigateLastURL(); + }, + () => { //in the case of empty master list the wrapper is simple cleared and no loade only completed dcallbak is called + this.isLoadingOverRouting = false; + } + ); + this.loadFromTheSamePage = false; + } else this.navigateLastURL(); + } + } else { + if (this.loadImedeately) this.loadOnPageAcivated(); + } + } + + + public navigateLastURL() { + this.router.navigate([this.lastURL]); + } + + + public activateRouting4EntityList(entityList: BaseEntityListWrapper, loadedOverRoutingCallBack?: BaseEntityCallBack) { + this.entityList4Routing = entityList; + this.loadedOverRoutingCallBack = loadedOverRoutingCallBack; + entityList.focusedRoutingCallBack = this.focusedRoutingCallBack.bind(this); + } + + + public focusedRoutingCallBack(focusedItem: BaseEntity | number) { + if (!this.isPageActive()) return; + const entityId: number = (typeof focusedItem === 'number') ? focusedItem : (focusedItem?.entityId || 0); + const currentEntity = this.entityList4Routing.focusedEntityShadowed; + if ((entityId > 0) && currentEntity && this.globalsService.urlParam === entityId.toString()) { + if (currentEntity.inViewMode) { + if (currentEntity.entityId === entityId) currentEntity.reload(); + else currentEntity.entityId = entityId; + } + } else { + this.loadFromTheSamePage = true; + const url = this.router.serializeUrl(this.router.createUrlTree([this.globalsService.appPages[this.applicationPage].path, entityId > 0 ? entityId : ''])); + if (this.router?.url + '/' !== url) { + //don't override routing during loading of entity + if (!this.isLoadingOverRouting) { + this.lastURL = url; + this.router.navigate([url]); + } + } else if (this.entityList4Routing?.focusedEntityShadowed) this.entityList4Routing.focusedEntityShadowed.entityIsLoading = false; // to fire loaded$ for empty lists + } + } + + + protected onLoggedInOut(user: CoreUser) { + if (!this.authService.isLoggedIn()) this.clearData(); //clears data only during logout - otherwise can id in url can be lost + } + + + public clearData() { + } + + + protected loadData(callback?: () => void) { + const isActivePage = this.isPageActive(); + if (isActivePage || !this.pageLoadingService.spinnerVisible) { + // if called from constructor or is standalone or loaded at first time - no background loading is needed + const needBackgroungLoadingOfDependendPages = isActivePage && !this.standAlone && this.backgroundLoading; //&& this.pageLoadingService.noOfHttpQueries4Page[this.applicationPage] !== -1; + this.backgroundLoading = !this.standAlone; + this.pageLoadingService.startSpinner(needBackgroungLoadingOfDependendPages, callback); + } + this.pageLoadingService.noOfHttpQueries4Page[this.applicationPage] = this.appPageNoQueries; //means, that page service is iniatilised + this.appLogsService.dlog('%c' + this.translationService.instant(this.globalsService.appPages[this.applicationPage].messageCaption) + ' data are loading', 'color:brown'); + } + + + protected loadBaseData(pageNo: number, noOfQueries: number, callback?: () => void) { + this.pageLoadingService.startSpinner(true, () => { if (callback) callback(); this.pageBaseDateWereLoaded$.next(true); }); + this.pageLoadingService.noOfHttpQueries4Page[pageNo] = noOfQueries; + this.appLogsService.dlog(this.globalsService.currentPage + ': %cstammdata data are loading', 'color:brown'); + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/pageloading.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/pageloading.service.ts new file mode 100644 index 0000000..983b6d9 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/pageloading.service.ts @@ -0,0 +1,132 @@ +import { inject, Injectable } from '@angular/core'; +import { NgxSpinnerService } from 'ngx-spinner'; +import { Globals } from './globals'; +import { AppLogsService } from './applogs.service'; +import { EN_AppColors } from '../consts'; +import { Subject, BehaviorSubject } from 'rxjs'; +import { HenselTranslateService } from './localization/hensel-translate.service'; + +@Injectable({ + providedIn: 'root' +}) + +export class PageLoadingService { + public static delayBackgroundPageLoaded = 750; // timeout in msis needed to correctly process page loadings without delays (with not completed filter) + public spinnerVisible: number = 0; + public forgroundLoading$ = new BehaviorSubject(null); + public backgroundLoading$ = new BehaviorSubject(null); + public pageActive$ = new Subject(); + private _noOfHttpQueries4Page: number[] = []; + public get noOfHttpQueries4Page(): number[] { + return this._noOfHttpQueries4Page; + } + public set noOfHttpQueries4Page(value: number[]) { + value.forEach((vl: number, index: number) => { if (this._noOfHttpQueries4Page[index] > - 1) this._noOfHttpQueries4Page[index] = vl; }); + } + + private startBackgroundLoading: boolean = false; + private waitBackgroundLoadingFinished: boolean = false; + + private arLoadedCompletedCallBacks: (() => void)[] = []; + private translationService = inject(HenselTranslateService); + private _onPageLoagingWaitBackgroundLoadingFinished: boolean = false; + public get onPageLoagingWaitBackgroundLoadingFinished(): boolean { + return this._onPageLoagingWaitBackgroundLoadingFinished; + } + public set onPageLoagingWaitBackgroundLoadingFinished(value: boolean) { + this._onPageLoagingWaitBackgroundLoadingFinished = value; + this.waitBackgroundLoadingFinished = value; + } + public startBackgroundLoadingAfterPageIsLoaded: boolean = true; + + + constructor( + private globals: Globals, + private appLogsservice: AppLogsService, + private spinnerService: NgxSpinnerService, + ) { + this.globals.appPages.forEach(_ => this.noOfHttpQueries4Page.push(-1)); //page is not loaded + } + + + public startSpinner(_startBackgroundLoading: boolean = true, callbackCompleted?: () => void) { + this.startBackgroundLoading = _startBackgroundLoading || this.startBackgroundLoading; + // if (!_startBackgroundLoading) this.waitBackgroundLoadingFinished = this.onPageLoagingWaitBackgroundLoadingFinished; + if (callbackCompleted) this.arLoadedCompletedCallBacks.push(callbackCompleted); + this.showSpinner(); + } + + + public showSpinner() { + if (this.spinnerVisible++ === 0) { + this.appLogsservice.dlog('%cshow spinner', { guid: 'spinner' }, 'color:' + EN_AppColors.hideSpinnerColor); + this.spinnerService.show(); + } + } + + + private allData4PageAreLoaded(page: number = -1): boolean { + if (page > -1 && page < this.noOfHttpQueries4Page.length) { + //wait only on this page + return this.noOfHttpQueries4Page[page] <= 0; + } + return this.noOfHttpQueries4Page.every(_ => _ <= 0); + } + + + updatePageLoadedCounters(page: number) { + if (page !== null) { + const currentPageIndex: number = (this.globals.isTheLoginPage(this.globals.appPages[page].path) ? page : this.globals.getPageIndex(this.globals.currentPage)); + + if (this.noOfHttpQueries4Page[page] > 0) this.noOfHttpQueries4Page[page]--; + // this.appLogsservice.dlog('-----', page, currentPageIndex, this.noOfHttpQueries4Page); + + if (page < this.noOfHttpQueries4Page.length && this.noOfHttpQueries4Page[page] === 0) { + //if the page data were loaded + this.appLogsservice.dlog('%c' + this.translationService.instant(this.globals.appPages[page].messageCaption) + ' data are loaded', 'color:brown'); + } + + if (currentPageIndex === page && !this.startBackgroundLoadingAfterPageIsLoaded) this.doBackgroundLoading(); + + if (this.allData4PageAreLoaded(this.waitBackgroundLoadingFinished ? -1 : currentPageIndex /* if onPageLoagingWaitBackgroundLoadingFinished all pages must be loaded before spinner hides*/)) { + // if (!this.waitBackgroundLoadingFinished) this.spinnerVisible = 1; //to hide spinner anyway + setTimeout(() => { + this.hideSpinner(); + this.doCallBacks(); + // this.spinnerVisible = 0; + this.waitBackgroundLoadingFinished = this.onPageLoagingWaitBackgroundLoadingFinished; + if (currentPageIndex === page && this.startBackgroundLoadingAfterPageIsLoaded) { + this.spinnerVisible += 1; //don't show spinner for background loading + this.waitBackgroundLoadingFinished = true; + this.doBackgroundLoading(); + this.spinnerVisible -= 1; //correcture + } + }, PageLoadingService.delayBackgroundPageLoaded); // timeout is needed to correctly process page loadings without delays (with not completed filter) + } + } + + } + + private doBackgroundLoading() { + if (this.startBackgroundLoading) { + //if the first http-call on the active page returned (only one time) + this.startBackgroundLoading = false; + this.backgroundLoading$.next(); + } + } + + + public hideSpinner() { + if ((this.spinnerVisible > 0) && (--this.spinnerVisible === 0)) { + this.appLogsservice.dlog('%chide spinner', { guid: 'spinner' }, 'color:' + EN_AppColors.hideSpinnerColor); + this.spinnerService.hide(); + } + } + + + private doCallBacks() { + const arLoadedCompletedCallBacks = this.arLoadedCompletedCallBacks; + this.arLoadedCompletedCallBacks = []; + arLoadedCompletedCallBacks.forEach((callback) => {if (callback) callback(); }); + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/print.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/print.service.ts new file mode 100644 index 0000000..6756b55 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/print.service.ts @@ -0,0 +1,25 @@ +import { Router } from '@angular/router'; + +export class PrintService { + isPrinting = false; + + constructor(private router: Router) { } + + printDocument(documentName: string, documentData: string[]) { + this.isPrinting = true; + this.router.navigate(['/', + { + outlets: { + print: ['print', documentName, documentData.join()] + } + }]); + } + + onDataReady() { + setTimeout(() => { + window.print(); + this.isPrinting = false; + this.router.navigate([{ outlets: { print: null } }]); + }); + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/services/serverinfo.service.ts b/ClientApp/staff-db-ui/src/app/shared/core/services/serverinfo.service.ts new file mode 100644 index 0000000..495f98a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/services/serverinfo.service.ts @@ -0,0 +1,176 @@ +import { inject, Injectable } from '@angular/core'; +import { SwUpdate } from '@angular/service-worker'; +import { BehaviorSubject, interval, Subscription } from 'rxjs'; +import { EN_LoginStatus } from '../consts'; +import { Globals } from './globals'; +import { APPICON4LIVE_TOKEN, APPICON4TEST_TOKEN, ENVIRONMENT_TOKEN } from '../injection-tokens'; +import { ServerInfo } from '../models/serverinfo'; +import { setIndexIcon } from '../utils'; +import { AppLogsService } from './applogs.service'; +import { AuthorizeService } from './authorize.service'; +import { RepositoryService } from './http/repository.service'; +import { HenselTranslateService } from './localization/hensel-translate.service'; +import { MatDialogRef } from '../components/angular-material-index'; + +const cnstPollingInterval1stInSec = 3; +const cnstPollingIntervalConnectedInSec = 15; +const time4TimeoutMessageInSec = 10; + +const enum EN_ServerStates { + Offline = -1, + Live = 0, + Development = 1, +} + + +@Injectable({ providedIn: 'root' }) + +export class ServerInfoService { + private environment = inject(ENVIRONMENT_TOKEN); + public serverInfo: ServerInfo = new ServerInfo(); + public serverStatus: EN_ServerStates = EN_ServerStates.Offline; + public defaultServerInfoVisible: boolean = true; + public serverInfoVisible: boolean; + protected pollingItervalTimer: Subscription = null; + public connectionReady: BehaviorSubject = new BehaviorSubject(null); + private EN_LoginStatus_Password = EN_LoginStatus.loginWithNameAndPassword; + private warningTimeOut: any; + private warningPopup: MatDialogRef; + private cnst_AppIcon4Live = inject(APPICON4LIVE_TOKEN); + private cnst_AppIcon4Test = inject(APPICON4TEST_TOKEN); + + private _pollingIntervalConnectedInSec: number = cnstPollingIntervalConnectedInSec; + + public get pollingIntervalConnectedInSec() { + return this._pollingIntervalConnectedInSec; + } + public set pollingIntervalConnectedInSec(value: number) { + this._pollingIntervalConnectedInSec = value; + this.resetPolling(value || 0); + } + + constructor( + private serverInfoDataService: RepositoryService, + public authorizationService: AuthorizeService, + public globals: Globals, + private appLogsService: AppLogsService, + public translate: HenselTranslateService, + private updateService: SwUpdate, + ) { + this.resetPolling(cnstPollingInterval1stInSec); + + this.createWarningTimeOutSubscriber = this.createWarningTimeOutSubscriber.bind(this); + this.createWarningTimeOutSubscriber(); + + this.authorizationService.loginAction$.subscribe((resultObject) => { + if (resultObject.result) { + if (this.authorizationService.user.showFooter !== undefined) { + this.serverInfoVisible = authorizationService.user.showFooter; + } else { + if (this.serverInfoVisible === undefined) this.serverInfoVisible = authorizationService.user.isAdmin; + } + } else { + this.serverInfoVisible = this.defaultServerInfoVisible || this.serverInfoVisible; + } + }); + this.appLogsService.dlog('Server Info is initialized!'); + } + + createWarningTimeOutSubscriber() { + this.warningTimeOut = setTimeout(() => { + clearTimeout(this.warningTimeOut); + this.warningPopup = this.appLogsService.warningMessageBox(this.translate.instant('core.msgbox.header.connect'), this.translate.instant('core.msgbox.body.connect'), () => this.warningTimeOut = null); + }, time4TimeoutMessageInSec * 1000); + } + + + resetPolling(intervalInSec: number) { + if (this.pollingItervalTimer) this.pollingItervalTimer.unsubscribe(); //poll always + if (intervalInSec > 0) this.pollingItervalTimer = interval(intervalInSec * 1000).subscribe(() => { this.init(); }); + } + + + private init() { + const _isLive = this.serverInfo?.isLive; + this.resetPolling(0); + this.serverInfo.firstOnlineTime = this.serverStatus === EN_ServerStates.Offline ? new Date() : null; + + this.serverInfo.save(this.serverInfoDataService, (si: ServerInfo) => { + this.resetPolling(this.pollingIntervalConnectedInSec); + if (!this.authorizationService.versionObsolete) this.updateService.checkForUpdate().then(res => this.authorizationService.versionObsolete = this.isOldVersion(this.serverInfo.clientVersion) || res); + if (si.attributes) { + si.officeFileServerURL = si.attributes['url']; + si.officeFileServerVersion = si.attributes['version']; + si.officeFileServer = si.attributes['server']; + si.officeFileServerDBServer = si.attributes['databaseserver']; + si.officeFileServerDBName = si.attributes['databasename']; + } else { + si.officeFileServerURL = null; + si.officeFileServerVersion = null; + si.officeFileServer = null; + si.officeFileServerDBServer = null; + si.officeFileServerDBName = null; + } + + if (_isLive !== si.isLive) { + if (si.isLive) { + setIndexIcon(this.cnst_AppIcon4Live); + if (this.globals.appTitleWithVersion.startsWith('Test - ')) this.globals.appTitleWithVersion = this.globals.appTitleWithVersion.replace('Test - ', ''); + } else { + setIndexIcon(this.cnst_AppIcon4Test); + if (!this.globals.appTitleWithVersion.startsWith('Test - ')) this.globals.appTitleWithVersion = 'Test - ' + this.globals.appTitleWithVersion; + } + } + + if (this.serverStatus === EN_ServerStates.Offline) { //first time connection + + if (this.warningPopup) this.warningPopup.close(); + + clearTimeout(this.warningTimeOut); + this.warningTimeOut = null; + + this.appLogsService.dlog('Server connected!'); + + this.serverStatus = this.isLive() ? EN_ServerStates.Live : EN_ServerStates.Development; + + + if (this.authorizationService.useJWT) { + // if (!this.authorizationService.checkJWT(this.environment.production ? 60 * 24 /* relogin one day before expiration*/ : 0)) this.authorizationService.loginStatus = this.EN_LoginStatus_Password; + if (!this.authorizationService.checkJWT(null)) this.authorizationService.loginStatus = this.EN_LoginStatus_Password; //only if there is no JWT + } else if (!this.authorizationService.useWindowsLogin) this.authorizationService.loginStatus = this.EN_LoginStatus_Password; + this.connectionReady.next(si); + } + } + , (err) => { + this.resetPolling(cnstPollingInterval1stInSec); + if (this.serverStatus !== EN_ServerStates.Offline) { + this.serverInfo.lastOfflineTime = new Date(); + this.serverStatus = EN_ServerStates.Offline; + } + if (!this.warningTimeOut) this.createWarningTimeOutSubscriber(); + } + , null, ''); + } + + public isOldVersion(mustVersion: string): boolean { + const isVersion = this.environment.appVersion; + const checkarrIsVersion = isVersion?.split('.'); + const checkarrMustVersion = mustVersion?.split('.'); + while (checkarrMustVersion.length > checkarrIsVersion.length) checkarrIsVersion.push('0'); + while (checkarrIsVersion.length > checkarrMustVersion.length) checkarrMustVersion.push('0'); + for (let index = 0; index < checkarrIsVersion.length; index++) { + const isVersionElement = checkarrIsVersion[index]; + const mustVersionElement = checkarrMustVersion[index]; + const isVersionElement_no = Number(isVersionElement); + const mustVersionElement_no = Number(mustVersionElement); + if (Number.isNaN(isVersionElement_no) || Number.isNaN(mustVersionElement_no)) { + if (isVersionElement !== mustVersionElement) return isVersionElement < mustVersionElement; + } else if (isVersionElement_no !== mustVersionElement_no) return isVersionElement_no < mustVersionElement_no; + } + return false; + } + + public isLive(): boolean { + return this.serverInfo?.isLive; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/utils.ts b/ClientApp/staff-db-ui/src/app/shared/core/utils.ts new file mode 100644 index 0000000..85d0b15 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/utils.ts @@ -0,0 +1,395 @@ +import * as AngularCommon from '@angular/common'; +import { HttpErrorResponse } from '@angular/common/http'; +import * as moment_ from 'moment'; +import * as Cnst from './consts'; + + +const moment = (moment_).default; + +export function guid(): string { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + // tslint:disable-next-line: no-bitwise + const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} + + +export function getMethodName(level: number = 2): string { return /at .*\.(.*)\s/.exec((new Error()).stack.split('\n')[level])[1]; } // we want the 2nd method in the call stack + + +export function ms2ToTimeString(ms: number, fmt: string) { + return moment(ms).format(fmt); +} + +export function getDecimalSeparator(culture: string): string { + return AngularCommon.getLocaleNumberSymbol(culture, AngularCommon.NumberSymbol.Decimal); +} + + +export function getThousandSeparator(culture: string): string { + return AngularCommon.getLocaleNumberSymbol(culture, AngularCommon.NumberSymbol.Group); +} + +export function getLocaleCurrencyCode(culture: string): string { + return AngularCommon.getLocaleCurrencyCode(culture); +} + +export function getCurrencySymbol(culture: string): string { + return AngularCommon.getCurrencySymbol(getLocaleCurrencyCode(culture), 'narrow', culture); +} + +export function getDateTimeFormat(culture: string): string { + return getDateFormat(culture, Cnst.EN_DateFormats.DateTime); +} + +export function getDateFormat(culture: string, dateFormatStringMode: Cnst.EN_DateFormats = Cnst.EN_DateFormats.Date): string { + let formatString: string; + switch (dateFormatStringMode) { + case Cnst.EN_DateFormats.WebAPI: + formatString = Cnst.DATE_FORMATS.display.date4WebAPI; + break; + case Cnst.EN_DateFormats.JSON: + formatString = Cnst.DATE_FORMATS.display.dateTime4JSON; + break; + case Cnst.EN_DateFormats.DateTime: + // getLocaleDateTimeFormat(culture, FormatWidth.Medium); returns {1}, {0} WTF? + formatString = stringFormat(AngularCommon.getLocaleDateTimeFormat(culture, AngularCommon.FormatWidth.Short) + , AngularCommon.getLocaleTimeFormat(culture, AngularCommon.FormatWidth.Short) + , AngularCommon.getLocaleDateFormat(culture, AngularCommon.FormatWidth.Short)).replace('yy', 'y'); + break; + default: + const localDateFormat = AngularCommon.getLocaleDateFormat(culture, AngularCommon.FormatWidth.Short); + formatString = localDateFormat.replace('yy', 'y'); //localformat "short" returns yy - that shows only the last 2 years in year, not 4 + } + return formatString; +} + + +export function toStringConsiderDateFormat(obj: any, dateFormatStringMode: Cnst.EN_DateFormats = Cnst.EN_DateFormats.WebAPI, culture: string = 'en-US' /* does not matter a culture, Cnst.EN_DateFormats.WebAPI uses explicit date format*/): string { + let ret: string = ''; + + if (obj) { + if (typeof obj === 'string') obj = new Date(obj); + if (typeof obj === 'object') { + const formatString: string = getDateFormat(culture, dateFormatStringMode); + const momentFormatString: string = formatString.toUpperCase().replace(':MM', ':mm').replace(':SS', ':ss'); + if (moment.isMoment(obj) /*'_isAMomentObject' in obj*/) ret = moment(obj).format(momentFormatString); + else if (moment.isDate(obj) /*obj instanceof Date*/) ret = AngularCommon.formatDate(obj, formatString, culture /* does not matter a culture, we are using explicit date format*/); + } else ret = obj.toString(); + } + return ret; +} + + +export function formatNumbers(locale: string, num: number, digits = 0, prefix = ''): string { + // const num = +data.value; + // let val = num.toFixed(digits).replace('.', ','); // replace decimal point + // val = val.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1.'); + return prefix + AngularCommon.formatNumber(num, locale, '1.' + digits + '-' + digits); +} + + +export function isEqual(source: object, target: object): boolean { + if (target && source) { + for (const prop in source) { + if (source.hasOwnProperty(prop) + && target.hasOwnProperty(prop) + && (target[prop] !== source[prop])) { + return false; + } + } + return true; + } else { + return !target && !source; + } +} + + +function arrayIsContainedInReturnsDiff(arr1: any[], arr2: any[], notExistInArray2: any[]): boolean { + if (!arr1) return false; + if (arr1.length === 0) return true; + if (!arr2 || arr2.length === 0) { + notExistInArray2.concat(arr1); + return false; + } else { + let result = true; + arr1.forEach((e1: any) => { + if (!arr2.some(e2 => { + if (e1 instanceof Array && e2 instanceof Array) return arraysAreEqual(e1, e2); + else return e1 === e2; + })) { + result = false; + notExistInArray2.push(e1); + } + }); + return result; + } +} + + +export function arraysAreEqualReturnsDiff(arr1: any, arr2: any, diffArr1: any, diffArr2: any): boolean { + let _arr1: any[] = arr1; + let _arr2: any[] = arr2; + if (!(arr1 instanceof Array)) _arr1 = [arr1]; + if (!(arr2 instanceof Array)) _arr2 = [arr2]; + if (!diffArr1) diffArr1 = []; + if (!diffArr2) diffArr2 = []; + return arrayIsContainedInReturnsDiff(_arr1, _arr2, diffArr1) && arrayIsContainedInReturnsDiff(_arr2, _arr1, diffArr2); +} + + +function arrayIsContainedIn(arr1: any[], arr2: any[]): boolean { + return arr1 && arr2 && (arr1.length === 0 || arr1.every((e1, i) => arr2.some(e2 => { + if (e1 instanceof Array && e2 instanceof Array && e1.length > 1 && e2.length) return arraysAreEqual(e1, e2); + else return e1 === e2; + }))); +} + + +export function arraysAreEqual(arr1: any, arr2: any): boolean { + let _arr1: any[] = arr1; + let _arr2: any[] = arr2; + if (!(arr1 instanceof Array)) _arr1 = [arr1]; + if (!(arr2 instanceof Array)) _arr2 = [arr2]; + return arrayIsContainedIn(_arr1, _arr2) && arrayIsContainedIn(_arr2, _arr1); +} + + +export function compareStrings(str1: string, str2: string): boolean { + return (str1 ?? '').localeCompare(str2 ?? '') === 0; +} + + + +export function prepareArrayFromList(obj: Object, listField: string, arrayToPprepareField: string): number[] { + if (obj[arrayToPprepareField]) return obj[arrayToPprepareField]; + obj[arrayToPprepareField] = []; + if (obj[listField]) { + const reglist: string[] = obj[listField].split(','); + reglist.forEach((vl: string, inx: number) => { if (vl && !Number.isNaN(Number(vl))) obj[arrayToPprepareField].push(+vl); }); + } + return obj[arrayToPprepareField]; +} + + +export function prepareListFromArray(obj: Object, listField: string, arrayToPprepareField: string, newArray: number[]) { + obj[arrayToPprepareField] = newArray; + obj[listField] = newArray.join(','); +} + + +export function getErrorMessageAsText(errorObj: any): string { + if (!errorObj) return 'unknown error'; + if (errorObj instanceof HttpErrorResponse && errorObj.status === Cnst.cnst_ErrorCode4Unauthorized) return Cnst.cnst_CANCEL_ERROR; + if (errorObj['errMsg']) return errorObj.errMsg; + if (errorObj['error']) { + if (typeof errorObj.error === 'string') return errorObj.error; + if (errorObj.error['errors'] && errorObj.error.errors instanceof Array && errorObj.error.errors.length > 0) return errorObj.error.errors[0].toString(); + if (errorObj.error['message']) return errorObj.message; + return errorObj.error.toString(); + } + if (errorObj['message']) return errorObj.message; + if (errorObj['statusText']) return errorObj.statusText; + return errorObj.toString(); +} + + +export function extractError(error: any) { + // Try to unwrap zone.js error. + // https://github.com/angular/angular/blob/master/packages/core/src/util/errors.ts + if (error && error.ngOriginalError) { + error = error.ngOriginalError; + } + + // We can handle messages and Error objects directly. + if (typeof error === 'string' || error instanceof Error) { + return error; + } + + // If it's http module error, extract as much information from it as we can. + if (error instanceof HttpErrorResponse) { + // The `error` property of http exception can be either an `Error` object, which we can use directly... + if (error.error instanceof Error) { + return error.error; + } + + // ... or an`ErrorEvent`, which can provide us with the message but no stack... + if (error.error instanceof ErrorEvent && error.error.message) { + return error.error.message; + } + + // ...or the request body itself, which we can use as a message instead. + if (typeof error.error === 'string') { + return `Server returned code ${error.status} with body "${error.error}"`; + } + + // if (error['error']) { + // return error.error; + // } + + // If we don't have any detailed information, fallback to the request message itself. + return error.message; + } + + // ***** CUSTOM ***** + // The above code doesn't always work since 'instanceof' relies on the object being created with the 'new' keyword + if (error.error && error.error.message) { + return error.error.message; + } + if (error.message) { + return error.message; + } + // ***** END CUSTOM ***** + + // Skip if there's no error, and let user decide what to do with it. + return null; +} + + +export function getNextDate(dt: Date, hours: number = 0, offset: number = 1): Date { + if (!dt) return null; + const date = new Date(dt); + date.setHours(hours, 0, 0, 0); + date.setDate(date.getDate() + offset); + return date; +} + + +export function today(): Date { + const date = new Date(); + date.setHours(0, 0, 0, 0); + return date; +} + + +export function setIndexIcon(iconpath: string, icon2replace: string = '#favIcon') { + const favIcon: HTMLLinkElement = document.querySelector(icon2replace); + if (favIcon) favIcon.href = iconpath; +} + + +export function setIndexTitle(title: string) { + const tileEl: HTMLLinkElement = document.querySelector('#appTitle'); + if (tileEl) tileEl.innerText = title; +} + + +export function removeSpecialChars(str: string): string { + return str + .replace(new RegExp('/ ', 'g'), '_') + .replace(new RegExp(' /', 'g'), '_') + .replace(new RegExp(' / ', 'g'), '_') + .replace(new RegExp(' ', 'g'), '_') + .replace(new RegExp('/', 'g'), '_') + .replace(new RegExp(':', 'g'), '_') + .replace(new RegExp('>', 'g'), '_') + .replace(new RegExp('<', 'g'), '_') + .replace(new RegExp('___', 'g'), '_') + .replace(new RegExp('__', 'g'), '_'); +} + + +export function dowloadFile(filename: string, data: any, type: string) { + // const blob = new Blob([response.body], { type: response.body.type }); + const blob = new Blob([JSON.stringify(data)], { type: type }); + + + // window.open(window.URL.createObjectURL(blob), filename); + const link = document.createElement('a'); + const url = URL.createObjectURL(blob); + link.setAttribute('href', url); + link.setAttribute('download', filename); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +} + + +export function cleanTextContent(text: string): string { + // strips off all non-ASCII characters + text = text.replace(new RegExp('[^\\x00-\\x7F]', 'g'), ''); + + // erases all the ASCII control characters + text = text.replace(new RegExp('[\\p{Cntrl}&&[^\r\n\t]]', 'g'), ''); + + // removes non-printable characters from Unicode + text = text.replace(new RegExp('\\p{C}', 'g'), ''); + + return text.trim(); +} + + +export function isWorkDay(dt: Date) { + return dt.getDate() === nextWorkDay(dt, -1000 * 60 * 60 * 24 ).getDate(); +} + + +export function nextWorkDay(dt: Date, shift: number = 0) { + const newdt = new Date(dt.getTime() + shift); + const day = newdt.getDay(); + newdt.setDate(newdt.getDate() + 1 + (day === 5 ? 2 : (day === 6 ? 1 : 0))); + return newdt; +} + + +export function stringFormat(str: string, ...opt_values: string[]) { + if (opt_values) { + str = str.replace(/\{([^}]+)}/g, function (match, key) { + return (opt_values != null && key in opt_values) ? opt_values[key] : match; + }); + } + return str; +} + + +export function convertTZ(date: Date | string, tzString: string) { + return new Date((typeof date === 'string' ? new Date(date) : date).toLocaleString('en-US', {timeZone: tzString})); +} + + +export function now() { + return moment.now(); +} + + +export function isBefore(dt: Date) { + return moment().isBefore(dt); +} + + +export function isLanguageSupported(lang: string, appLanguages?: string[], supportedLanguage?: Cnst.SupportedLanguage[]): boolean { + return (!appLanguages || appLanguages.indexOf(lang) > -1) + && (!supportedLanguage || supportedLanguage.findIndex((lng: Cnst.SupportedLanguage) => lng.langCode === lang) > -1); +} + + +export function isCultureSupported(culture: string, appCultures: string[], supportedCulture?: Cnst.SupportedCulture[]): boolean { + return (!appCultures || appCultures.indexOf(culture) > -1) + && (!supportedCulture || supportedCulture.findIndex((cltr: Cnst.SupportedCulture) => cltr.culture === culture) > -1); +} + + + +export function callProtocol(protocol: string, filePath: string, replaceSlash: boolean = true) { + if (replaceSlash) { + filePath = filePath.replace(new RegExp('"', 'g'), '').split('\\\\').join('\\'); + } + window.open(protocol + ':' + filePath, '_parent'); +} + + + +// export function translateString(stringToTranslate: string, translate: HenselTranslateService) { +// let res = stringToTranslate?.replace(/\${(.*?)}/g, (found: string, translationKey: string) => translate.instant(translationKey)); +// if (res === stringToTranslate) res = translate.instant(res); // source string does not contain placeholder "${}" - try to translate directly +// return res; +// } + +export function isEmpty(value: any): boolean { + return (value == null || (typeof value === 'string' && value.trim().length === 0)); +} + +export function inputNumberChanged(target: number, value: any): boolean { + return isEmpty(value) && !isEmpty(target) || !isEmpty(value) && isEmpty(target) || (target ?? 0) !== +value; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/core/validators/hensel-validator.directive.ts b/ClientApp/staff-db-ui/src/app/shared/core/validators/hensel-validator.directive.ts new file mode 100644 index 0000000..d6cd4db --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/core/validators/hensel-validator.directive.ts @@ -0,0 +1,75 @@ +import { Directive, forwardRef, Input } from '@angular/core'; +import { AbstractControl, NG_VALIDATORS, Validator } from '@angular/forms'; + +@Directive({ + standalone: true, + selector: '[hensel-validator]', + providers: [ + { provide: NG_VALIDATORS, useExisting: forwardRef(() => HenselValidator), multi: true } + ] +}) + +export class HenselValidator implements Validator { + private valueFromExcl?: number; + private valueFromIncl?: number; + private valueToIncl?: number; + private valueToExcl?: number; + private valid: boolean = true; + private control: AbstractControl; + + @Input() + set greater(value: number) { + this.valueFromExcl = value; + this.control?.updateValueAndValidity(); + } + + + @Input() + set notless(value: number) { + this.valueFromIncl = value; + this.control?.updateValueAndValidity(); + } + + + @Input() + set notgreater(value: number) { + this.valueToIncl = value; + this.control?.updateValueAndValidity(); + } + + + @Input() + set less(value: number) { + this.valueToExcl = value; + this.control?.updateValueAndValidity(); + } + + @Input() + set isValid(value: boolean) { + this.valid = value; + this.control?.updateValueAndValidity(); + } + + constructor( + // @Attribute('greater') public valueFromExcl?: number, + // @Attribute('notless') public valueFromIncl?: number, + // @Attribute('notgreater') public valueToIncl?: number, + // @Attribute('less') public valueToExcl?: number, + ) { } + + validate(c: AbstractControl): { [key: string]: any } { + // self value + this.control = c; + if (c.value === null || c.value === 'undefined' || c.value === '') return null; + const val = +c.value; + if (((this.valueFromExcl || this.valueFromExcl === 0) && val <= this.valueFromExcl) + || ((this.valueFromIncl || this.valueFromIncl === 0) && val < this.valueFromIncl) + || ((this.valueToIncl || this.valueToIncl === 0) && val > this.valueToIncl) + || ((this.valueToExcl || this.valueToExcl === 0) && val >= this.valueToExcl) + || !this.valid + ) { + return { validateEqual: false }; + } + return null; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/cost-centre.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/cost-centre.ts new file mode 100644 index 0000000..d444f42 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/cost-centre.ts @@ -0,0 +1,19 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; + +export class CostCentre extends AppBaseEntity { + typeName = EN_AppEntities.CostCentre; + costCentreId: number; + costCentreName: string; + sortOrder: number; + + + + public get entityId() { + return this.costCentreId; + } + public set entityId(value) { + this.costCentreId = value; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/department.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/department.ts new file mode 100644 index 0000000..85dc1d3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/department.ts @@ -0,0 +1,39 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; +import { AppBaseFilter } from '@app_models/generic/app.baseentityfilter'; + +export class Department extends AppBaseEntity { + typeName = EN_AppEntities.Department; + get entitytitle(): string { //is used for messages + return this.entityId ? `Abteilung "${this.departmentName}"` : 'Neue Abteilung'; + } + departmentId: number; + departmentName: string; + costCentreId: number; + departmentTypeId: number; + headofDepartmentId: number; + executiveDirectorId: number; + managingDirectorId: number; + departmentNameFolder: string; + adGroupDepartmentName: string; + clientId: number; + isVirtual: boolean; + costCentre: string; + headofDepartment: string; + executiveDirector: string; + managingDirector: string; + public get entityId() { + return this.departmentId; + } + public set entityId(value) { + this.departmentId = value; + } + + insertWithIds() { return true; } //because departmentId is not autoincrement and is set explicetely +} + + +export class DepartmentFilter extends AppBaseFilter { + departmentId: number; + departmentName: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/document-art.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/document-art.ts new file mode 100644 index 0000000..edb5f82 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/document-art.ts @@ -0,0 +1,16 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; +export class DocumentArt extends AppBaseEntity { + typeName = EN_AppEntities.DocumentArt; + documentArtId: number; + rootPath: string; + folder: string; + departmentNamesList: string; + clientId: number; + public get entityId() { + return this.documentArtId; + } + public set entityId(value) { + this.documentArtId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/employee-attribute.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/employee-attribute.ts new file mode 100644 index 0000000..2cb2563 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/employee-attribute.ts @@ -0,0 +1,16 @@ +import { EN_AppEntities } from '@app_consts'; +import { BaseData } from '@app_models/generic/app.basedata'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; + +export class EmployeeAttribute extends BaseData { + typeName = EN_AppEntities.EmployeeAttribute; + employeeAttributeId: number; + seqNo: number; + + public get entityId() { + return this.employeeAttributeId; + } + public set entityId(value) { + this.employeeAttributeId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/employee-status.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/employee-status.ts new file mode 100644 index 0000000..99453af --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/employee-status.ts @@ -0,0 +1,15 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; + +export class EmployeeStatus extends AppBaseEntity { + typeName = EN_AppEntities.EmployeeStatus; + employeeStatusId: number; + employeeStatusName: string; + public get entityId() { + return this.employeeStatusId; + } + public set entityId(value) { + this.employeeStatusId = value; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/project.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/project.ts new file mode 100644 index 0000000..8791d73 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/project.ts @@ -0,0 +1,13 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; +export class Project extends AppBaseEntity { + typeName = EN_AppEntities.Project; + projectId: number; + projectName: string; + public get entityId() { + return this.projectId; + } + public set entityId(value) { + this.projectId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/rang.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/rang.ts new file mode 100644 index 0000000..372ba9b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/rang.ts @@ -0,0 +1,17 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; +export class Rang extends AppBaseEntity { + typeName = EN_AppEntities.Rang; + rangId: number; + rangShortname: string; + rangName: string; + rangOrder: number; + + public get entityId() { + return this.rangId; + } + public set entityId(value) { + this.rangId = value; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapp-to-webapprole.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapp-to-webapprole.ts new file mode 100644 index 0000000..5a2e6f3 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapp-to-webapprole.ts @@ -0,0 +1,24 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '../generic/app.baseentity'; +import { AppBaseFilter } from '../generic/app.baseentityfilter'; + +export class WebAppToWebAppRole extends AppBaseEntity { + typeName = EN_AppEntities.WebAppToWebAppRole; + webAppToWebAppRoleId: number; + webAppId: number; + webAppRoleId: number; + webAppRoleName: string; + webAppRoleHierarchy: number; + + public get entityId() { + return this.webAppToWebAppRoleId; + } + public set entityId(value) { + this.webAppToWebAppRoleId = value; + } +} + + +export class WebAppToWebAppRoleFilter extends AppBaseFilter { + webAppId: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapp.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapp.ts new file mode 100644 index 0000000..d355214 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapp.ts @@ -0,0 +1,19 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '../generic/app.baseentity'; + +export class WebApp extends AppBaseEntity { + typeName = EN_AppEntities.WebApp; + webAppId: number; + webAppName: string; + webAppLinkLive: string; + webAppLinkDev: string; + isActive: boolean; + adWebAppName: string; + + public get entityId() { + return this.webAppId; + } + public set entityId(value) { + this.webAppId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/webappadditionalrole .ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/webappadditionalrole .ts new file mode 100644 index 0000000..6ba0a26 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/webappadditionalrole .ts @@ -0,0 +1,17 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '../generic/app.baseentity'; + +export class WebAppAdditionalRole extends AppBaseEntity { + typeName = EN_AppEntities.WebAppAdditionalRole; + webAppAdditionalRoleId: number; + webAppAdditionalRoleName: string; + adWebAppAdditionalRoleName: string; + webAppId: number; + + public get entityId() { + return this.webAppAdditionalRoleId; + } + public set entityId(value) { + this.webAppAdditionalRoleId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapprole.ts b/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapprole.ts new file mode 100644 index 0000000..1020f0a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/basedata/webapprole.ts @@ -0,0 +1,16 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from '../generic/app.baseentity'; + +export class WebAppRole extends AppBaseEntity { + typeName = EN_AppEntities.WebAppRole; + webAppRoleId: number; + webAppRoleName: string; + webAppRoleHierarchy: number; + + public get entityId() { + return this.webAppRoleId; + } + public set entityId(value) { + this.webAppRoleId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/documentart-to-department.ts b/ClientApp/staff-db-ui/src/app/shared/models/documentart-to-department.ts new file mode 100644 index 0000000..0d1f7c7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/documentart-to-department.ts @@ -0,0 +1,33 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + +export class DocumentArtToDepartment extends AppBaseEntity { + typeName = EN_AppEntities.DocumentArtToDepartment; + documentArtToDepartmentId: number; + documentArtId: number; + departmentId: number; + isActive: boolean; + useGlobix: boolean; + + documentArtName: string; + documentArtShortname: string; + documentArtFolder: string; + + public get entityId() { + return this.documentArtToDepartmentId; + } + public set entityId(value) { + this.documentArtToDepartmentId = value; + } + + public clear() { + this.isActive = true; + this.useGlobix = false; + } +} + + +export class DocumentArtToDepartmentFilter extends AppBaseFilter { + documentArtId: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/employee-to-attribute.ts b/ClientApp/staff-db-ui/src/app/shared/models/employee-to-attribute.ts new file mode 100644 index 0000000..767cdc0 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/employee-to-attribute.ts @@ -0,0 +1,17 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + +export class EmployeeToAttribute extends AppBaseEntity { + typeName = EN_AppEntities.EmployeeToAttribute; + employeeToAttributeId: number; + employeeId: number; + employeeAttributeId: number; + + public get entityId() { + return this.employeeToAttributeId; + } + public set entityId(value) { + this.employeeToAttributeId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/employee-to-department.ts b/ClientApp/staff-db-ui/src/app/shared/models/employee-to-department.ts new file mode 100644 index 0000000..82ae77b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/employee-to-department.ts @@ -0,0 +1,22 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; + +export class EmployeeToDepartment extends AppBaseEntity { + typeName = EN_AppEntities.EmployeeToDepartment; + public get entitytitle(): string { return 'Zuweisung von Abteilung "' + this.departmentName + '" für Mitarbeiter'; } //is used for messages + + employeeToDepartmentId: number; + employeeId: number; + departmentId: number; + departmentName: number; + employeeBudget: number; + employeeStatusId: number; + rangId: number; + + public get entityId() { + return this.employeeToDepartmentId; + } + public set entityId(value) { + this.employeeToDepartmentId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/employee-to-webapp.ts b/ClientApp/staff-db-ui/src/app/shared/models/employee-to-webapp.ts new file mode 100644 index 0000000..a5087e9 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/employee-to-webapp.ts @@ -0,0 +1,67 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { prepareArrayFromList, prepareListFromArray } from '@app_core/utils'; + +export class EmployeeToWebApp extends AppBaseEntity { + typeName = EN_AppEntities.EmployeeToWebapp; + public get entitytitle(): string { return 'Zuweisung von Webapp "' + this.webAppName + '" für Mitarbeiter'; } //is used for messages + employeeToWebAppId: number; + employeeId: number; + webAppId: number; + webAppRoleId: number; + departmentId: number; + webAppRoleName: string; + webAppName: string; + departmentName: string; + extendedDepartmentNameList: string; + extendedDepartmentIdList: string; + + additionalRoleNameList: string; + additionalRoleIdList: string; + + private _arExtendedDepartmentIdList: number[]; + get arExtendedDepartmentIdList(): number[] { + return prepareArrayFromList(this, 'extendedDepartmentIdList', '_arExtendedDepartmentIdList'); + } + + set arExtendedDepartmentIdList(array: number[]) { + prepareListFromArray(this, 'extendedDepartmentIdList', '_arExtendedDepartmentIdList', array); + } + + private _arAdditionalRoleIdList: number[]; + get arAdditionalRoleIdList(): number[] { + return prepareArrayFromList(this, 'additionalRoleIdList', '_arAdditionalRoleIdList'); + } + + set arAdditionalRoleIdList(array: number[]) { + prepareListFromArray(this, 'additionalRoleIdList', '_arAdditionalRoleIdList', array); + } + + + public get entityId() { + return this.employeeToWebAppId; + } + public set entityId(value) { + this.employeeToWebAppId = value; + } + + clear() { + super.clear(); + this._arExtendedDepartmentIdList = undefined; + this._arAdditionalRoleIdList = undefined; + } + + public assign(source: Partial): EmployeeToWebApp { + const oldId = this.entityId; + const oldDepIdList = this.extendedDepartmentIdList; + const oldAddRoleIdList = this.additionalRoleIdList; + this.clear(); + const obj = Object.assign(this, source); + if (oldId <= 0 && !this.isNew()) {//don't update extendedDepartmentIdList and additionalRoleIdList if the entity is reload (f.e. after insert) + this.extendedDepartmentIdList = oldDepIdList; + this.additionalRoleIdList = oldAddRoleIdList; + } + + return obj; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/employee.ts b/ClientApp/staff-db-ui/src/app/shared/models/employee.ts new file mode 100644 index 0000000..e217218 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/employee.ts @@ -0,0 +1,98 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; +import { prepareArrayFromList, prepareListFromArray } from '@app_core/utils'; + +export class Employee extends AppBaseEntity { + typeName = EN_AppEntities.Employee; + get entitytitle(): string { //is used for messages + return this.entityId ? `Mitarbeiter "${this._name}"` : 'Neuen Mitarbeiter'; + } + + employeeId: number; + employeeNo: string; + salutation: string; + firstName: string; + lastName: string; + shortName: string; + title: string; + position: string; + loginName: string; + email: string; + rangId: number; + clientId: number; + mobilePhoneNo: string; + phoneNo: string; + isActive: boolean; + + mandantCode: string; + + departmentNamesList: string; + departmentIdList: string; + webappNamesList: string; + webappIdList: string; + attributeNamesList: string; + attributeIdList: string; + + private _arAttributeIdList: number[]; + get arAttributeIdList(): number[] { + return prepareArrayFromList(this, 'attributeIdList', '_arAttributeIdList'); + } + + set arAttributeIdList(array: number[]) { + prepareListFromArray(this, 'attributeIdList', '_arAttributeIdList', array); + } + + + get _name(): string { + return this.firstName ? this.firstName + ' ' : '' + this.lastName ? this.lastName : ''; + } + + + public get fullname(): string { + return this.firstName + ' ' + this.lastName; + } + + public get entityId() { + return this.employeeId; + } + public set entityId(value) { + this.employeeId = value; + } + + constructor(source?: Employee) { + super(source); + this.dontUpdateFields = [...this.dontUpdateFields, + 'departmentNamesList', 'departmentIdList', 'webappNamesList', 'webappIdList', 'attributeNamesList', 'attributeIdList', '_arAttributeIdList']; + this.dontInsertFields = [...this.dontUpdateFields, + 'departmentNamesList', 'departmentIdList', 'webappNamesList', 'webappIdList', 'attributeNamesList', 'attributeIdList', '_arAttributeIdList']; + } + + assign(source: Partial): Employee { + super.assign(source); + return this; + } + + clear() { + super.clear(); + this._arAttributeIdList = undefined; + } +} + + +export class EmployeeFullFilter extends AppBaseFilter { + name: string; + shortName: string; + loginName: string; + email: string; + departmentIds: number[]; + attributeIds: number[]; + webappIds: number[]; + employeeId: number; + clientId: number; + isActive: boolean = true; +} + +export class EmployeeFilter extends AppBaseFilter { + employeeId: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/generic/app.basedata.ts b/ClientApp/staff-db-ui/src/app/shared/models/generic/app.basedata.ts new file mode 100644 index 0000000..90ca118 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/generic/app.basedata.ts @@ -0,0 +1,16 @@ +import { AppBaseEntity } from './app.baseentity'; + +export class BaseData extends AppBaseEntity { + id: number; + name: string; + shortname: string; + comment: string; + + public get entityId() { + return this.id; + } + public set entityId(value) { + this.id = value; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/generic/app.baseentity.ts b/ClientApp/staff-db-ui/src/app/shared/models/generic/app.baseentity.ts new file mode 100644 index 0000000..587bb40 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/generic/app.baseentity.ts @@ -0,0 +1,6 @@ +import { BaseEntity } from '@app_core/models/generics/baseentity'; + + +//here define App specifically properties and methods +export class AppBaseEntity extends BaseEntity { +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/generic/app.baseentityfilter.ts b/ClientApp/staff-db-ui/src/app/shared/models/generic/app.baseentityfilter.ts new file mode 100644 index 0000000..ef8625d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/generic/app.baseentityfilter.ts @@ -0,0 +1,4 @@ +import { BaseFilter } from '@app_core/models/generics/baseentityfilter'; + +export class AppBaseFilter extends BaseFilter { +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/subsidiary.ts b/ClientApp/staff-db-ui/src/app/shared/models/subsidiary.ts new file mode 100644 index 0000000..8b0b536 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/subsidiary.ts @@ -0,0 +1,19 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; + +export class Subsidiary extends AppBaseEntity { + typeName = EN_AppEntities.Subsidiary; + + subsidiaryId: number; + clientId: number; + name: string; + subsidiaryCode: string; + comment: string + + public get entityId() { + return this.subsidiaryId; + } + public set entityId(value) { + this.subsidiaryId = value; + } +} \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/app/shared/models/user.ts b/ClientApp/staff-db-ui/src/app/shared/models/user.ts new file mode 100644 index 0000000..59b6eef --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/user.ts @@ -0,0 +1,4 @@ +import { CoreUser } from '@app_core/models/coreuser'; + +export class User extends CoreUser { +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/webapp-to-department.ts b/ClientApp/staff-db-ui/src/app/shared/models/webapp-to-department.ts new file mode 100644 index 0000000..bfaf20b --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/webapp-to-department.ts @@ -0,0 +1,23 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + +export class WebAppToDepartment extends AppBaseEntity { + typeName = EN_AppEntities.WebAppToDepartment; + webAppToDepartmentId: number; + employeeToWebAppId: number; + departmentId: number; + departmentName: string; + + public get entityId() { + return this.webAppToDepartmentId; + } + public set entityId(value) { + this.webAppToDepartmentId = value; + } +} + + +export class EmployeeToWebAppFilter extends AppBaseFilter { + employeeToWebAppId: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/webapp-to-webappadditionalrole.ts b/ClientApp/staff-db-ui/src/app/shared/models/webapp-to-webappadditionalrole.ts new file mode 100644 index 0000000..14ace30 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/webapp-to-webappadditionalrole.ts @@ -0,0 +1,17 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + +export class WebAppToWebAppAdditionalRole extends AppBaseEntity { + typeName = EN_AppEntities.WebAppToWebAppAdditionalRole; + webAppToWebAppAdditionalRoleId: number; + employeeToWebAppId: number; + webAppAdditionalRoleId: number; + + public get entityId() { + return this.webAppToWebAppAdditionalRoleId; + } + public set entityId(value) { + this.webAppToWebAppAdditionalRoleId = value; + } +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/windream-index-to-windream-search-to-department.ts b/ClientApp/staff-db-ui/src/app/shared/models/windream-index-to-windream-search-to-department.ts new file mode 100644 index 0000000..407678d --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/windream-index-to-windream-search-to-department.ts @@ -0,0 +1,34 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + +export class WindreamIndexToWindreamSearchToDepartment extends AppBaseEntity { + typeName = EN_AppEntities.WindreamIndexToWindreamSearchToDepartment; + get entitytitle(): string { //is used for messages + return this.entityId ? `Ausgabespalte "${this._name}" für Windream Suche` : 'Neue Ausgabespalte für Windream Suche'; + } + windreamIndexToWindreamSearchToDepartmentId: number; + windreamSearchToDepartmentId: number; + windreamIndexId: number; + seq: number; + attributeSzColumnName: string; + objectTypeAttributeSzName: string; + + get _name(): string { + return this.objectTypeAttributeSzName; + } + + public get entityId() { + return this.windreamIndexToWindreamSearchToDepartmentId; + } + public set entityId(value) { + this.windreamIndexToWindreamSearchToDepartmentId = value; + } + +} + + + +export class WindreamIndexToWindreamSearchToDepartmentFilter extends AppBaseFilter { + WindreamSearchToDepartmentId: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/windream-index.ts b/ClientApp/staff-db-ui/src/app/shared/models/windream-index.ts new file mode 100644 index 0000000..cc0a7c6 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/windream-index.ts @@ -0,0 +1,39 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + + +export class WindreamIndex extends AppBaseEntity { + + typeName = EN_AppEntities.WindreamIndex; + get entitytitle(): string { //is used for messages + return this.entityId ? `WindreamIndex "${this._name}"` : 'New WindreamIndex'; + } + windreamIndexId: number; + clientId: number; + attributeDwAttrId: number; + attributeSzColumnName: string; + comment: string; + comumnLength: number; + attributeDwAttrType: number; + objectTypeAttributeSzName: string; + + get _name(): string { + return this.attributeSzColumnName; + } + get selectionName(): string { + return this.comment + ' (' + this.attributeSzColumnName + ')'; + } + public get entityId() { + return this.windreamIndexId; + } + public set entityId(value) { + this.windreamIndexId = value; + } + +} + + +export class ClientIdFilter extends AppBaseFilter { + clientId: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/windream-search-item-to-windream-search-to-department.ts b/ClientApp/staff-db-ui/src/app/shared/models/windream-search-item-to-windream-search-to-department.ts new file mode 100644 index 0000000..84a1ec0 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/windream-search-item-to-windream-search-to-department.ts @@ -0,0 +1,32 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; + +export class WindreamSearchItemToWindreamSearchToDepartment extends AppBaseEntity { + typeName = EN_AppEntities.WindreamSearchItemToWindreamSearchToDepartment; + get entitytitle(): string { //is used for messages + return this.entityId ? `Windream Suchfeld"${this._name}"` : 'Neues Windream Suchfeld'; + } + windreamSearchItemToWindreamSearchToDepartmentId: number; + windreamSearchToDepartmentId: number; + seq: number; + departmentId: number; + windreamSearchItemId: number; + windreamSearchItemName: string; + windreamSearchItemCaption: string; + windreamSearchItemPlaceHolder: string; + windreamSearchItemSearchTemplate: string; + windreamSearchItemConnectedList: string; + windreamSearchItemComment: string; + get _name(): string { + return this.windreamSearchItemName; + } + + public get entityId() { + return this.windreamSearchItemToWindreamSearchToDepartmentId; + } + + public set entityId(value) { + this.windreamSearchItemToWindreamSearchToDepartmentId = value; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/windream-search-item.ts b/ClientApp/staff-db-ui/src/app/shared/models/windream-search-item.ts new file mode 100644 index 0000000..adeeae6 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/windream-search-item.ts @@ -0,0 +1,37 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + +export class WindreamSearchItem extends AppBaseEntity { + typeName = EN_AppEntities.WindreamSearchItem; + get entitytitle(): string { //is used for messages + return this.entityId ? `Windream Suchfeld "${this._name}"` : 'Neues Windream Suchfeld'; + } + windreamSearchItemId: number; + clientId: number; + seq: number; + name: string; + comment: string; + caption: string; + placeHolder: string; + searchTemplate: string; + connectedList: string; + get _name(): string { + return this.caption; + } + + public get entityId() { + return this.windreamSearchItemId; + } + + public set entityId(value) { + this.windreamSearchItemId = value; + } + +} + + +export class WindreamSearchItemFilter extends AppBaseFilter { + departmentId: number; + windreamSearchToDepartmentId: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/windream-search-to-department.ts b/ClientApp/staff-db-ui/src/app/shared/models/windream-search-to-department.ts new file mode 100644 index 0000000..dce4058 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/windream-search-to-department.ts @@ -0,0 +1,36 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + +export class WindreamSearchToDepartment extends AppBaseEntity { + typeName = EN_AppEntities.WindreamSearchToDepartment; + get entitytitle(): string { //is used for messages + return this.entityId ? `Windream Suchkachel "${this._name}"` : 'Neue Windream Suchekachel'; + } + windreamSearchToDepartmentId: number; + departmentId: number; + windreamSearchId: number; + seq: number; + departmentName: string; + windreamSearchName: string; + isActive: boolean; + + get _name(): string { + return this.windreamSearchName; + } + + public get entityId() { + return this.windreamSearchToDepartmentId; + } + + public set entityId(value) { + this.windreamSearchToDepartmentId = value; + } + +} + + +export class WindreamSearchToDepartmentFilter extends AppBaseFilter { + departmentId?: number; + windreamSearchId?: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/models/windream-search.ts b/ClientApp/staff-db-ui/src/app/shared/models/windream-search.ts new file mode 100644 index 0000000..05d11c5 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/models/windream-search.ts @@ -0,0 +1,40 @@ +import { EN_AppEntities } from '@app_consts'; +import { AppBaseEntity } from './generic/app.baseentity'; +import { AppBaseFilter } from './generic/app.baseentityfilter'; + + +export class WindreamSearch extends AppBaseEntity { + + typeName = EN_AppEntities.WindreamSearch; + get entitytitle(): string { //is used for messages + return this.entityId ? `Windream Suchkachel "${this._name}"` : 'Neue Windream Suchkachel'; + } + windreamSearchId: number; + name: string; + xmlPath: string; + comment: string; + clientId: number; + color: number; + + + get _name(): string { + return this.name; + } + + get selectionName(): string { + return this.name; + } + + public get entityId() { + return this.windreamSearchId; + } + public set entityId(value) { + this.windreamSearchId = value; + } + +} + + +export class ClientIdFilter extends AppBaseFilter { + clientId: number; +} diff --git a/ClientApp/staff-db-ui/src/app/shared/services/app.baseentity.wrapper.ts b/ClientApp/staff-db-ui/src/app/shared/services/app.baseentity.wrapper.ts new file mode 100644 index 0000000..19c1221 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/services/app.baseentity.wrapper.ts @@ -0,0 +1,5 @@ +import { BaseEntityWrapper } from '@app_core/models/generics/baseentity.wrapper'; +import { AppBaseEntity } from '../models/generic/app.baseentity'; + +export class AppBaseEntityWrapper extends BaseEntityWrapper { +} diff --git a/ClientApp/staff-db-ui/src/app/shared/services/app.baseentitylist.wrapper.ts b/ClientApp/staff-db-ui/src/app/shared/services/app.baseentitylist.wrapper.ts new file mode 100644 index 0000000..33e40d2 --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/services/app.baseentitylist.wrapper.ts @@ -0,0 +1,32 @@ +import { formatDate } from '@angular/common'; +import { AppBaseEntity } from '@app_models/generic/app.baseentity'; +import { AppBaseEntityWrapper } from './app.baseentity.wrapper'; +import { APP_TITLE } from '@app_consts'; +import { ɵDEFAULT_LOCALE_ID } from '@angular/core'; +import { BaseEntityListWrapper } from '@app_core/models/generics/baseentitylist.wrapper'; +import { EN_EntityEditingStates } from '@app_core/consts'; +import { removeSpecialChars } from '@app_core/utils'; + +export class AppBaseEntityListWrapper extends BaseEntityListWrapper { + //here define App specifically properties and methods + public createFocusedShadowEntity(defaultEditMode?: EN_EntityEditingStates): AppBaseEntityWrapper { + const appFocusedShadowEntity: AppBaseEntityWrapper = new AppBaseEntityWrapper(this.TEntity, defaultEditMode); + this.focusedEntityShadowed = appFocusedShadowEntity; + this.focusedEntityShadowed.entityList = this; + this.focusedEntityShadowed.hierarchyLevel = this.hierarchyLevel; + return appFocusedShadowEntity; + } + + public getExportFilename4List(prefix: string = '', postfix: string = '', midFix: string = '', useListName = true): string { + const retFilename = removeSpecialChars( + APP_TITLE + '_' + + (prefix !== '' ? prefix + '_' : '') + + (useListName ? this.translate.instant(this._listName) : '') + + (midFix !== '' ? '_' + midFix + '_' : '') + + formatDate(new Date(), '_yyyyMMdd', ɵDEFAULT_LOCALE_ID /* does not matter a culture, we are using explicit date format*/) + + (postfix !== '' ? '_' + postfix : '')); + console.log(retFilename); + return retFilename; + } + +} diff --git a/ClientApp/staff-db-ui/src/app/shared/services/app.data.service.ts b/ClientApp/staff-db-ui/src/app/shared/services/app.data.service.ts new file mode 100644 index 0000000..2fdf08a --- /dev/null +++ b/ClientApp/staff-db-ui/src/app/shared/services/app.data.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { EN_AppEntities } from '@app_consts'; +import { CostCentre } from '@app_models/basedata/cost-centre'; +import { Department } from '@app_models/basedata/department'; +import { DocumentArt } from '@app_models/basedata/document-art'; +import { EmployeeAttribute } from '@app_models/basedata/employee-attribute'; +import { EmployeeStatus } from '@app_models/basedata/employee-status'; +import { Project } from '@app_models/basedata/project'; +import { Rang } from '@app_models/basedata/rang'; +import { WebApp } from '@app_models/basedata/webapp'; +import { WebAppToWebAppRoleFilter } from '@app_models/basedata/webapp-to-webapprole'; +import { WebAppRole } from '@app_models/basedata/webapprole'; +import { Subsidiary } from '@app_models/subsidiary'; +import { AppBaseEntityListWrapper } from './app.baseentitylist.wrapper'; + +@Injectable({ + providedIn: 'root' +}) + + +export class AppDataService { + costCentreList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(CostCentre, 'Kostenstellenliste', EN_AppEntities.CostCentre + '/all'); + departmentList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(Department, 'Abteilungsliste', EN_AppEntities.Department + '/all'); + documentArtList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(DocumentArt, 'Dokumentartenliste', EN_AppEntities.DocumentArt + '/all'); + employeeStatusList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(EmployeeStatus, 'Mitarbeiterstatusliste', EN_AppEntities.EmployeeStatus + '/all'); + projectList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(Project, 'Projektliste', EN_AppEntities.Project + '/all'); + rangList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(Rang, 'Rangenliste', EN_AppEntities.Rang + '/all'); + webAppList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(WebApp, 'Web Applikationen Liste', EN_AppEntities.WebApp + '/all'); + roleList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(WebAppRole, 'Rolenliste', EN_AppEntities.WebAppRole + '/all'); + employeeAttributeList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(EmployeeAttribute, 'Merkmalliste', EN_AppEntities.EmployeeAttribute + '/all'); + webAppFilter: WebAppToWebAppRoleFilter = new WebAppToWebAppRoleFilter('WebAppFilter'); + subsidiaryList: AppBaseEntityListWrapper = new AppBaseEntityListWrapper(Subsidiary, 'Subsidiary', EN_AppEntities.Subsidiary + '/all'); + + + showIds: boolean = false; + + constructor() { + } + + loadData(listLoadedCallBack: () => void) { + this.costCentreList.load(null, null, listLoadedCallBack); + this.departmentList.load(null, null, listLoadedCallBack); + this.documentArtList.load(null, null, listLoadedCallBack); + this.employeeStatusList.load(null, null, listLoadedCallBack); + this.projectList.load(null, null, listLoadedCallBack); + this.rangList.load(null, null, listLoadedCallBack); + this.webAppList.load(null, null, listLoadedCallBack); + this.roleList.load(null, null, listLoadedCallBack); + this.employeeAttributeList.load(null, null, listLoadedCallBack); + this.subsidiaryList.load(null, null, listLoadedCallBack); + +} +} diff --git a/ClientApp/staff-db-ui/src/assets/.gitkeep b/ClientApp/staff-db-ui/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ClientApp/staff-db-ui/src/assets/icons/Master_Icon.xcf b/ClientApp/staff-db-ui/src/assets/icons/Master_Icon.xcf new file mode 100644 index 0000000..29f4457 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/Master_Icon.xcf differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-128x128.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-128x128.png new file mode 100644 index 0000000..cd16ede Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-128x128.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-144x144.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-144x144.png new file mode 100644 index 0000000..1c66922 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-144x144.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-152x152.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-152x152.png new file mode 100644 index 0000000..f6ef7e2 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-152x152.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-152x152i.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-152x152i.png new file mode 100644 index 0000000..57d930c Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-152x152i.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-16x16.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-16x16.png new file mode 100644 index 0000000..befcc0b Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-16x16.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-192x192.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-192x192.png new file mode 100644 index 0000000..7d4ec9c Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-192x192.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-24x24.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-24x24.png new file mode 100644 index 0000000..78f821a Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-24x24.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-384x384.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-384x384.png new file mode 100644 index 0000000..50e3c21 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-384x384.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-48x48.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-48x48.png new file mode 100644 index 0000000..02e07fc Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-48x48.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-512x512.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-512x512.png new file mode 100644 index 0000000..f84c4b5 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-512x512.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-72x72.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-72x72.png new file mode 100644 index 0000000..aa901aa Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-72x72.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-96x96.png b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-96x96.png new file mode 100644 index 0000000..174c72f Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/develop/dhr-icon-96x96.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/main_48x48.png b/ClientApp/staff-db-ui/src/assets/icons/main_48x48.png new file mode 100644 index 0000000..ebe0c5a Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/main_48x48.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-128x128.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-128x128.png new file mode 100644 index 0000000..b7c9c44 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-128x128.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-144x144.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-144x144.png new file mode 100644 index 0000000..3eed0bd Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-144x144.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-152x152.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-152x152.png new file mode 100644 index 0000000..362d25d Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-152x152.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-152x152i.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-152x152i.png new file mode 100644 index 0000000..56d817f Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-152x152i.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-16x16.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-16x16.png new file mode 100644 index 0000000..b155fbb Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-16x16.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-192x192.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-192x192.png new file mode 100644 index 0000000..1c1e6df Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-192x192.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-24x24.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-24x24.png new file mode 100644 index 0000000..80ad47b Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-24x24.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-384x384.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-384x384.png new file mode 100644 index 0000000..3accaa5 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-384x384.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-48x48.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-48x48.png new file mode 100644 index 0000000..52a9de8 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-48x48.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-512x512.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-512x512.png new file mode 100644 index 0000000..2527e5f Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-512x512.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-72x72.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-72x72.png new file mode 100644 index 0000000..8af157e Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-72x72.png differ diff --git a/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-96x96.png b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-96x96.png new file mode 100644 index 0000000..9706b81 Binary files /dev/null and b/ClientApp/staff-db-ui/src/assets/icons/production/dhr-icon-96x96.png differ diff --git a/ClientApp/staff-db-ui/src/assets/js/environment.js b/ClientApp/staff-db-ui/src/assets/js/environment.js new file mode 100644 index 0000000..949aeaf --- /dev/null +++ b/ClientApp/staff-db-ui/src/assets/js/environment.js @@ -0,0 +1,23 @@ + +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + + +const environment = { + production: false, + // apiUrl: 'https://localhost:60191/api', + // apiUrl: 'https://staffdb.hensel-recycling.com:50001/api', + apiUrl: 'https://staffdb.hensel-recycling.com:50101/api', + sentry_dsn: '', + useLoginWithJWT: true, + translationFolder: './assets/translate/', +}; +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/ClientApp/staff-db-ui/src/assets/translate/de.json b/ClientApp/staff-db-ui/src/assets/translate/de.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/ClientApp/staff-db-ui/src/assets/translate/de.json @@ -0,0 +1,2 @@ +{ +} diff --git a/ClientApp/staff-db-ui/src/assets/translate/en.json b/ClientApp/staff-db-ui/src/assets/translate/en.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/ClientApp/staff-db-ui/src/assets/translate/en.json @@ -0,0 +1,2 @@ +{ +} diff --git a/ClientApp/staff-db-ui/src/assets/translate/fr.json b/ClientApp/staff-db-ui/src/assets/translate/fr.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/ClientApp/staff-db-ui/src/assets/translate/fr.json @@ -0,0 +1,2 @@ +{ +} diff --git a/ClientApp/staff-db-ui/src/browserslist b/ClientApp/staff-db-ui/src/browserslist new file mode 100644 index 0000000..37371cb --- /dev/null +++ b/ClientApp/staff-db-ui/src/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/environments/develop/environment.js b/ClientApp/staff-db-ui/src/environments/develop/environment.js new file mode 100644 index 0000000..627e463 --- /dev/null +++ b/ClientApp/staff-db-ui/src/environments/develop/environment.js @@ -0,0 +1,7 @@ +const environment = { + production: false, + useLoginWithJWT: true, + apiUrl: 'https://staffdb.hensel-recycling.com:50101/api', + sentry_dsn: '', + translationFolder: './assets/translate/' +}; diff --git a/ClientApp/staff-db-ui/src/environments/production/environment.js b/ClientApp/staff-db-ui/src/environments/production/environment.js new file mode 100644 index 0000000..0a7dc32 --- /dev/null +++ b/ClientApp/staff-db-ui/src/environments/production/environment.js @@ -0,0 +1,7 @@ +const environment = { + production: true, + useLoginWithJWT: true, + apiUrl: 'https://staffdb.hensel-recycling.com:50101/api', + sentry_dsn: '', + translationFolder: './assets/translate/', +}; diff --git a/ClientApp/staff-db-ui/src/index.html b/ClientApp/staff-db-ui/src/index.html new file mode 100644 index 0000000..dbdaa17 --- /dev/null +++ b/ClientApp/staff-db-ui/src/index.html @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + info + + + + diff --git a/ClientApp/staff-db-ui/src/json-typings.d.ts b/ClientApp/staff-db-ui/src/json-typings.d.ts new file mode 100644 index 0000000..68275f7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/json-typings.d.ts @@ -0,0 +1,4 @@ +declare module "*.json" { + const value: any; + // export default value; +} \ No newline at end of file diff --git a/ClientApp/staff-db-ui/src/karma.conf.js b/ClientApp/staff-db-ui/src/karma.conf.js new file mode 100644 index 0000000..f8d563c --- /dev/null +++ b/ClientApp/staff-db-ui/src/karma.conf.js @@ -0,0 +1,32 @@ +// 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-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../coverage/staffdb'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/ClientApp/staff-db-ui/src/main.ts b/ClientApp/staff-db-ui/src/main.ts new file mode 100644 index 0000000..323b654 --- /dev/null +++ b/ClientApp/staff-db-ui/src/main.ts @@ -0,0 +1,69 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; +import * as Sentry from '@sentry/angular'; +import { APP_TITLE } from '@app_consts'; +import { IENVIRONMENT } from '@app_core/injection-tokens'; + +declare const environment: IENVIRONMENT; +declare const appVersion: string; +declare const appBuild: string; + +if (environment.sentry_dsn) { + Sentry.init({ + dsn: environment.sentry_dsn, + attachStacktrace: true, + debug: false, + release: APP_TITLE + '_' + appVersion, + integrations: [Sentry.browserTracingIntegration()], + tracePropagationTargets: ['localhost', environment.apiUrl], + // new RewriteFrames(), + // new SentryBrowser.BrowserTracing({ + // tracingOrigins: ['localhost', environment.apiUrl], + // routingInstrumentation: SentryBrowser.routingInstrumentation, + // }), + // ], + + // Set tracesSampleRate to 1.0 to capture 100% + // of transactions for performance monitoring. + // We recommend adjusting this value in production + tracesSampleRate: 0.5, + maxBreadcrumbs: 50, + // ignoreErrors: ['Non-Error exception captured'], + beforeSend(event: any, hint) { + // Note: issue with double entries during http exceptions: https://github.com/getsentry/sentry-javascript/issues/2169 + // Note: issue with a second entry not being set correctly (as a non-error): https://github.com/getsentry/sentry-javascript/issues/2292#issuecomment-554932519 + const isNonErrorException = event.exception?.values[0]?.value?.startsWith('Non-Error exception captured'); + if (isNonErrorException) { + if (!event.extra.__serialized__) { + return null; + } + let realErrMsg = (event.extra.__serialized__ as any).error ? (event.extra.__serialized__ as any).error.message : null; + realErrMsg = realErrMsg || (event.extra.__serialized__ as any).message; + // this is a useless error message that masks the actual error. Lets try to set it properly + event.exception.values[0].value = realErrMsg; + event.message = realErrMsg; + } + return event; + } + }); + Sentry.setTag('AppName', APP_TITLE); + Sentry.setTag('AppVersion', appVersion); + Sentry.setTag('AppBuild', appBuild); +} +// MinimumBreadcrumbLevel=Error +// MinimumEventLevel=Error + + +if (environment.production) { + enableProdMode(); +} + + +platformBrowserDynamic().bootstrapModule(AppModule).then(ref => { + // Ensure Angular destroys itself on hot reloads. + if (window['ngRef']) window['ngRef'].destroy(); + window['ngRef'] = ref; + + // Otherwise, log the boot error +}).catch(err => console.error(err)); diff --git a/ClientApp/staff-db-ui/src/manifest/develop/webmanifest.json b/ClientApp/staff-db-ui/src/manifest/develop/webmanifest.json new file mode 100644 index 0000000..3362f7a --- /dev/null +++ b/ClientApp/staff-db-ui/src/manifest/develop/webmanifest.json @@ -0,0 +1,77 @@ +{ + "name": "StaffDB-Dev", + "short_name": "StaffDB-Dev", + "theme_color": "#1976d2", + "background_color": "#fafafa", + "display": "standalone", + "scope": "./", + "start_url": "./", + "icons": [ + { + "src": "assets/icons/develop/dhr-icon-16x16.png", + "sizes": "16x16", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-24x24.png", + "sizes": "24x24", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-48x48.png", + "sizes": "48x48", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-72x72.png", + "sizes": "72x72", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-96x96.png", + "sizes": "96x96", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-128x128.png", + "sizes": "128x128", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-144x144.png", + "sizes": "144x144", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-152x152.png", + "sizes": "152x152", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-384x384.png", + "sizes": "384x384", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/develop/dhr-icon-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable any" + } + ] +} diff --git a/ClientApp/staff-db-ui/src/manifest/production/webmanifest.json b/ClientApp/staff-db-ui/src/manifest/production/webmanifest.json new file mode 100644 index 0000000..020ee98 --- /dev/null +++ b/ClientApp/staff-db-ui/src/manifest/production/webmanifest.json @@ -0,0 +1,77 @@ +{ + "name": "StaffDB", + "short_name": "StaffDB", + "theme_color": "#1976d2", + "background_color": "#fafafa", + "display": "standalone", + "scope": "./", + "start_url": "./", + "icons": [ + { + "src": "assets/icons/production/dhr-icon-16x16.png", + "sizes": "16x16", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-24x24.png", + "sizes": "24x24", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-48x48.png", + "sizes": "48x48", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-72x72.png", + "sizes": "72x72", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-96x96.png", + "sizes": "96x96", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-128x128.png", + "sizes": "128x128", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-144x144.png", + "sizes": "144x144", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-152x152.png", + "sizes": "152x152", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-384x384.png", + "sizes": "384x384", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable any" + } + ] +} diff --git a/ClientApp/staff-db-ui/src/polyfills.ts b/ClientApp/staff-db-ui/src/polyfills.ts new file mode 100644 index 0000000..aa571da --- /dev/null +++ b/ClientApp/staff-db-ui/src/polyfills.ts @@ -0,0 +1,69 @@ +/*************************************************************************************************** + * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. + */ +import '@angular/localize/init'; +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +// import 'zone.js/dist/zone'; // Included with Angular CLI. +import 'zone.js'; +import 'zone.js/testing'; + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/ClientApp/staff-db-ui/src/styles.scss b/ClientApp/staff-db-ui/src/styles.scss new file mode 100644 index 0000000..9ad987c --- /dev/null +++ b/ClientApp/staff-db-ui/src/styles.scss @@ -0,0 +1,19 @@ +/* You can add global styles to this file, and also import other style files */ + +/*===================================== +import global directory +======================================*/ + +@import 'hr-core.scss'; + + +/* for sidenav to take whole page */ + +html, +body { + margin: 0; + height: 100%; + overflow: hidden !important; + // touch-action: pan-x pan-y; + // touch-action: manipulation; +} diff --git a/ClientApp/staff-db-ui/src/test.ts b/ClientApp/staff-db-ui/src/test.ts new file mode 100644 index 0000000..06aa8e4 --- /dev/null +++ b/ClientApp/staff-db-ui/src/test.ts @@ -0,0 +1,14 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); diff --git a/ClientApp/staff-db-ui/src/theme.scss b/ClientApp/staff-db-ui/src/theme.scss new file mode 100644 index 0000000..e69de29 diff --git a/ClientApp/staff-db-ui/src/tsconfig.app.json b/ClientApp/staff-db-ui/src/tsconfig.app.json new file mode 100644 index 0000000..6ba02cf --- /dev/null +++ b/ClientApp/staff-db-ui/src/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "types": ["node"] + }, + "files": [ + "main.ts", + "polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/ClientApp/staff-db-ui/src/tsconfig.spec.json b/ClientApp/staff-db-ui/src/tsconfig.spec.json new file mode 100644 index 0000000..de77336 --- /dev/null +++ b/ClientApp/staff-db-ui/src/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts", + "polyfills.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/ClientApp/staff-db-ui/src/tslint.json b/ClientApp/staff-db-ui/src/tslint.json new file mode 100644 index 0000000..aa7c3ee --- /dev/null +++ b/ClientApp/staff-db-ui/src/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/ClientApp/staff-db-ui/src/webmanifest.json b/ClientApp/staff-db-ui/src/webmanifest.json new file mode 100644 index 0000000..905f3c7 --- /dev/null +++ b/ClientApp/staff-db-ui/src/webmanifest.json @@ -0,0 +1,77 @@ +{ + "name": "StaffDB-Dev", + "short_name": "StaffDB-Dev", + "theme_color": "#1976d2", + "background_color": "#fafafa", + "display": "standalone", + "scope": "./", + "start_url": "./", + "icons": [ + { + "src": "assets/icons/production/dhr-icon-16x16.png", + "sizes": "16x16", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-24x24.png", + "sizes": "24x24", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-48x48.png", + "sizes": "48x48", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-72x72.png", + "sizes": "72x72", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-96x96.png", + "sizes": "96x96", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-128x128.png", + "sizes": "128x128", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-144x144.png", + "sizes": "144x144", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-152x152.png", + "sizes": "152x152", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-384x384.png", + "sizes": "384x384", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "assets/icons/production/dhr-icon-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable any" + } + ] +} diff --git a/ClientApp/staff-db-ui/tsconfig.json b/ClientApp/staff-db-ui/tsconfig.json new file mode 100644 index 0000000..48bb628 --- /dev/null +++ b/ClientApp/staff-db-ui/tsconfig.json @@ -0,0 +1,57 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": false, + "noImplicitOverride": false, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": false, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "declaration": false, + "module": "es2020", + "moduleResolution": "node", + "downlevelIteration": true, + "emitDecoratorMetadata": false, + "experimentalDecorators": true, + "resolveJsonModule": true, + "importHelpers": true, + "target": "ES2022", + "lib": [ + "es2020", + "dom" + ], + "paths": { + "@app_modules/*": [ + "src/app/modules/*" + ], + "@app_components/*": [ + "src/app/shared/components/*" + ], + "@app_consts": [ + "src/app/shared/app.consts.ts" + ], + "@app_core/*": [ + "src/app/shared/core/*" + ], + "@app_services/*": [ + "src/app/shared/services/*" + ], + "@app_models/*": [ + "src/app/shared/models/*" + ], + "jszip": [ + "node_modules/jszip/dist/jszip.min.js" + ] + }, + "useDefineForClassFields": false + } + // , "angularCompilerOptions": { + // "enableI18nLegacyMessageIdFormat": false, + // "strictInjectionParameters": true, + // "strictInputAccessModifiers": true, + // "strictTemplates": true + // } +} diff --git a/ClientApp/staff-db-ui/tslint.json b/ClientApp/staff-db-ui/tslint.json new file mode 100644 index 0000000..4f6dfca --- /dev/null +++ b/ClientApp/staff-db-ui/tslint.json @@ -0,0 +1,131 @@ +{ + "rulesDirectory": [ + "codelyzer" + ], + "rules": { + "arrow-return-shorthand": true, + "callable-types": true, + "class-name": true, + "comment-format": [ + true + ], + "curly": [ + true, + "ignore-same-line" + ], + "deprecation": { + "severity": "off" + }, + "eofline": false, + "forin": true, + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "import-spacing": true, + "indent": [ + true, + "spaces" + ], + "interface-over-type-literal": true, + "label-position": true, + "max-line-length": [ + true, + 280 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": [ + false, + "ignore-params" + ], + "no-misused-new": true, + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": false, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-catch", + "check-else", + "check-whitespace" + ], + "prefer-const": true, + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "unified-signatures": true, + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "no-output-on-prefix": true, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "directive-class-suffix": true + } +}