diff --git a/.circleci/config.yml b/.circleci/config.yml index 96c04af147..469a4bbebc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -137,8 +137,10 @@ jobs: rm -rf /tmp/cypress mkdir -p /tmp/cypress/results mkdir -p /tmp/cypress/lighthouse + mkdir -p /tmp/cypress/videos docker cp fecfile-web-app-e2e:/root/fecfile-web-app/front-end/cypress/results/. /tmp/cypress/results docker cp fecfile-web-app-e2e:/root/fecfile-web-app/front-end/cypress/lighthouse/. /tmp/cypress/lighthouse + docker cp fecfile-web-app-e2e:/root/fecfile-web-app/front-end/cypress/videos/. /tmp/cypress/videos docker rm fecfile-web-app-e2e - store_artifacts: path: /tmp/cypress/results @@ -146,6 +148,9 @@ jobs: - store_artifacts: path: /tmp/cypress/lighthouse destination: cypress/lighthouse + - store_artifacts: + path: /tmp/cypress/videos + destination: cypress/videos deploy: docker: - image: cimg/node:16.15-browsers diff --git a/front-end/cypress.config.ts b/front-end/cypress.config.ts index eee884ee41..76631663e3 100644 --- a/front-end/cypress.config.ts +++ b/front-end/cypress.config.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; export default defineConfig({ defaultCommandTimeout: 10000, projectId: 'x5egpz', - video: false, + video: true, videosFolder: 'cypress/videos', screenshotsFolder: 'cypress/screenshots', screenshotOnRunFailure: true, @@ -16,10 +16,10 @@ export default defineConfig({ reporter: 'mochawesome', reporterOptions: { reportDir: 'cypress/results', - reportFilename: "[status]_[datetime]-[name]", + reportFilename: '[status]_[datetime]-[name]', overwrite: false, html: true, - json: false + json: false, }, lighthouse: { options: ['--chrome-flags="--no-sandbox --headless --disable-gpu"'], @@ -46,6 +46,6 @@ export default defineConfig({ }); return require('./cypress/plugins/index.ts')(on, config); }, - baseUrl: 'http://localhost:4200' + baseUrl: 'http://localhost:4200', }, }); diff --git a/front-end/cypress/e2e/reports-f3x-transactions.cy.ts b/front-end/cypress/e2e/reports-f3x-transactions.cy.ts index 144c9b44da..23ee1d5de0 100644 --- a/front-end/cypress/e2e/reports-f3x-transactions.cy.ts +++ b/front-end/cypress/e2e/reports-f3x-transactions.cy.ts @@ -158,7 +158,7 @@ describe('Transactions', () => { PageUtils.clickButton('Continue'); // Create memo transaction - cy.contains('a', 'Create a new contact').should('exist').wait(500); // Race condition with clicking 'Create a new contact' link being ready + cy.contains('h1', 'Partnership Attribution').should('exist'); PageUtils.clickLink('Create a new contact'); ContactListPage.enterFormData(defaultContactFormData, true); PageUtils.clickButton('Save & continue'); @@ -172,6 +172,7 @@ describe('Transactions', () => { PageUtils.clickButton('Continue'); // Create a second memo transaction so we can check the aggregate value + cy.contains('Transactions in this report').should('exist'); PageUtils.clickLink('Partnership Receipt'); PageUtils.dropdownSetValue('[data-test="navigation-control-dropdown"]', 'Partnership Attribution'); cy.contains('Partnership Attribution').wait(500); @@ -541,7 +542,7 @@ describe('Transactions', () => { PageUtils.clickButton('Continue'); // Create Partnership Receipt Joint Fundraising Transfer Memo - cy.contains('a', 'Create a new contact').should('exist').wait(500); // Race condition with clicking 'Create a new contact' link being ready + cy.contains('h1', 'Partnership Receipt Joint Fundraising Transfer Memo').should('exist'); PageUtils.clickLink('Create a new contact'); const organizationFormContactData = { ...defaultContactFormData, @@ -559,7 +560,7 @@ describe('Transactions', () => { PageUtils.clickButton('Continue'); // Create Partnership Individual Joint Fundraising Transfer Memo - cy.contains('a', 'Create a new contact').should('exist').wait(500); // Race condition with clicking 'Create a new contact' link being ready + cy.contains('h1', 'Individual Joint Fundraising Transfer Memo').should('exist'); PageUtils.clickLink('Create a new contact'); const individualFormContactData = { ...defaultContactFormData, diff --git a/front-end/package-lock.json b/front-end/package-lock.json index d70e2f5195..2129e164da 100644 --- a/front-end/package-lock.json +++ b/front-end/package-lock.json @@ -23,7 +23,7 @@ "@types/ws": "8.5.4", "bootstrap": "5.1.3", "class-transformer": "^0.5.1", - "fecfile-validate": "https://github.com/fecgov/fecfile-validate#d313a8bf821a2bc0957b16a7c899544de898281e", + "fecfile-validate": "https://github.com/fecgov/fecfile-validate#f801280c3ab220c452e98eafae196245cf165416", "intl-tel-input": "^17.0.18", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", @@ -33,7 +33,7 @@ "ngx-logger": "^5.0.7", "primeflex": "^3.1.3", "primeicons": "^6.0.1", - "primeng": "^16.0.2", + "primeng": "16.1.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.5.4", "tslib": "^2.3.1", @@ -95,12 +95,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1601.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1601.7.tgz", - "integrity": "sha512-uFa7/TTPYoYLqgiRi5HZJaOXterVe9A83Sd+e3NXMmvT6oTMyLv0/t0Luhjic6c4vFrNnF3ECkrlGs2qW4TslA==", + "version": "0.1602.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.0.tgz", + "integrity": "sha512-ZRmUTBeD+uGr605eOHnsovEn6f1mOBI+kxP64DRvagNweX5TN04s3iyQ8jmLSAHQD9ush31LFxv3dVNxv3ceXQ==", "dev": true, "dependencies": { - "@angular-devkit/core": "16.1.7", + "@angular-devkit/core": "16.2.0", "rxjs": "7.8.1" }, "engines": { @@ -110,40 +110,40 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.1.7.tgz", - "integrity": "sha512-zUkPH3QDpA//hhMjMm9pKcbhO2gZjy4EkWrPglvR6G6a0myZc6/rEYK3W8gQWP1jiYiha/PiGnxTb+XeN/74tQ==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.0.tgz", + "integrity": "sha512-miylwjOqvlKmYrzS84bjRaJrecZxOXH9xsPVvQE8VBe8UKePJjRAL6yyOqXUOGtzlch2YmT98RAnuni7y0FEAw==", "dev": true, "dependencies": { "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1601.7", - "@angular-devkit/build-webpack": "0.1601.7", - "@angular-devkit/core": "16.1.7", - "@babel/core": "7.22.5", - "@babel/generator": "7.22.7", + "@angular-devkit/architect": "0.1602.0", + "@angular-devkit/build-webpack": "0.1602.0", + "@angular-devkit/core": "16.2.0", + "@babel/core": "7.22.9", + "@babel/generator": "7.22.9", "@babel/helper-annotate-as-pure": "7.22.5", - "@babel/helper-split-export-declaration": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", "@babel/plugin-proposal-async-generator-functions": "7.20.7", "@babel/plugin-transform-async-to-generator": "7.22.5", - "@babel/plugin-transform-runtime": "7.22.5", - "@babel/preset-env": "7.22.5", - "@babel/runtime": "7.22.5", + "@babel/plugin-transform-runtime": "7.22.9", + "@babel/preset-env": "7.22.9", + "@babel/runtime": "7.22.6", "@babel/template": "7.22.5", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "16.1.7", + "@ngtools/webpack": "16.2.0", "@vitejs/plugin-basic-ssl": "1.0.1", "ansi-colors": "4.1.3", "autoprefixer": "10.4.14", - "babel-loader": "9.1.2", + "babel-loader": "9.1.3", "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.21.5", - "cacache": "17.1.3", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", - "critters": "0.0.19", + "critters": "0.0.20", "css-loader": "6.8.1", - "esbuild-wasm": "0.17.19", - "fast-glob": "3.2.12", + "esbuild-wasm": "0.18.17", + "fast-glob": "3.3.1", + "guess-parser": "0.4.22", "https-proxy-agent": "5.0.1", "inquirer": "8.2.4", "jsonc-parser": "3.2.0", @@ -152,31 +152,31 @@ "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.30.0", + "magic-string": "0.30.1", "mini-css-extract-plugin": "2.7.6", "mrmime": "1.0.1", "open": "8.4.2", "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", "picomatch": "2.3.1", - "piscina": "3.2.0", - "postcss": "8.4.24", - "postcss-loader": "7.3.2", + "piscina": "4.0.0", + "postcss": "8.4.27", + "postcss-loader": "7.3.3", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.63.2", - "sass-loader": "13.3.1", - "semver": "7.5.3", + "sass": "1.64.1", + "sass-loader": "13.3.2", + "semver": "7.5.4", "source-map-loader": "4.0.1", "source-map-support": "0.5.21", - "terser": "5.17.7", + "terser": "5.19.2", "text-table": "0.2.0", "tree-kill": "1.2.2", - "tslib": "2.5.3", - "vite": "4.3.9", - "webpack": "5.86.0", + "tslib": "2.6.1", + "vite": "4.4.7", + "webpack": "5.88.2", "webpack-dev-middleware": "6.1.1", - "webpack-dev-server": "4.15.0", + "webpack-dev-server": "4.15.1", "webpack-merge": "5.9.0", "webpack-subresource-integrity": "5.1.0" }, @@ -186,7 +186,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.17.19" + "esbuild": "0.18.17" }, "peerDependencies": { "@angular/compiler-cli": "^16.0.0", @@ -232,9 +232,9 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@types/node": { - "version": "20.4.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.7.tgz", - "integrity": "sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g==", + "version": "20.5.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz", + "integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==", "dev": true, "optional": true, "peer": true @@ -252,20 +252,20 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", "dev": true }, "node_modules/@angular-devkit/build-angular/node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", + "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.26", + "rollup": "^3.25.2" }, "bin": { "vite": "bin/vite.js" @@ -273,12 +273,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -291,6 +295,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -306,12 +313,12 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1601.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1601.7.tgz", - "integrity": "sha512-BFqjL9mz0gtS10ucwmx7fFb1PprBzt6glN7ZEGhx58tterW68N9zZNFHR0AXmWoyVp/1B2oJWmqAQ52fakyshg==", + "version": "0.1602.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.0.tgz", + "integrity": "sha512-KdSr6iAcO30i/LIGL8mYi+d1buVXuDCp2dptzEJ4vxReOMFJca90KLwb+tVHEqqnDb0WkNfWm8Ii2QYh2FrNyA==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1601.7", + "@angular-devkit/architect": "0.1602.0", "rxjs": "7.8.1" }, "engines": { @@ -325,9 +332,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.1.7.tgz", - "integrity": "sha512-AXc9/F57Nf/A26yGu+w7PhNYriTvwazPTQsVPW/SBcTcpBa/hAsBTbPl8o8ErRJneJIoYqy/EIuabf9iiU8bRA==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.0.tgz", + "integrity": "sha512-l1k6Rqm3YM16BEn3CWyQKrk9xfu+2ux7Bw3oS+h1TO4/RoxO2PgHj8LLRh/WNrYVarhaqO7QZ5ePBkXNMkzJ1g==", "dev": true, "dependencies": { "ajv": "8.12.0", @@ -351,14 +358,14 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.1.7.tgz", - "integrity": "sha512-FQ/svSrUyalHVxgudoXAJbwgdPZ1iaEc6My4s4ti2HFtw0vqPw7Dh9bkRiMN3/MGMAdvsUIBiz8oSELZhuJTJg==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.0.tgz", + "integrity": "sha512-QMDJXPE0+YQJ9Ap3MMzb0v7rx6ZbBEokmHgpdIjN3eILYmbAdsSGE8HTV8NjS9nKmcyE9OGzFCMb7PFrDTlTAw==", "dev": true, "dependencies": { - "@angular-devkit/core": "16.1.7", + "@angular-devkit/core": "16.2.0", "jsonc-parser": "3.2.0", - "magic-string": "0.30.0", + "magic-string": "0.30.1", "ora": "5.4.1", "rxjs": "7.8.1" }, @@ -369,9 +376,9 @@ } }, "node_modules/@angular-eslint/builder": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.1.0.tgz", - "integrity": "sha512-KIkE2SI1twFKoCiF/k2VR3ojOcc7TD1xPyY4kbUrx/Gxp+XEzar7O29I/ztzL4eHPBM+Uh3/NwS/jvjjBxjgAg==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.1.1.tgz", + "integrity": "sha512-NaB/A0mmlzp7laiucRUsRyoCrOE1In3UifsGP0vD6yjUpefk4g0v+0vCg8mhsIky8gYDtBE9YRfUiLA9FlF/FA==", "dev": true, "dependencies": { "@nx/devkit": "16.5.1", @@ -383,18 +390,18 @@ } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.1.0.tgz", - "integrity": "sha512-5EFAWXuFJADr3imo/ZYshY8s0K7U7wyysnE2LXnpT9PAi5rmkzt70UNZNRuamCbXr4tdIiu+fXWOj7tUuJKnnw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.1.1.tgz", + "integrity": "sha512-TB01AWZBDfrZBxN1I50HfBXtC7q4NI5fwl1aS4tOfef2/kQjTtR9zmha8CsxjDkAOa9tA/4MUayAMqEBQLuHKQ==", "dev": true }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-16.1.0.tgz", - "integrity": "sha512-BFzzJJlgQgWc8avdSBkaDWAzNSUqcwWy0L1iZSBdXGoIOxj72kLbwe99emb8M+rUfCveljQkeM2pcYu8XLbJIA==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-16.1.1.tgz", + "integrity": "sha512-GauEwFGEcgIdsld4cVarFJYYxaRbMLzbpxyvBUDFg4LNjlcQNt7zfqXRLJoZAaFJFPtGtAoo1+6BlEKErsntuQ==", "dev": true, "dependencies": { - "@angular-eslint/utils": "16.1.0", + "@angular-eslint/utils": "16.1.1", "@typescript-eslint/utils": "5.62.0" }, "peerDependencies": { @@ -403,13 +410,13 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.1.0.tgz", - "integrity": "sha512-wQHWR5vqWGgO7mqoG5ixXeplIlz/OmxBJE9QMLPTZE8GdaTx8+F/5J37OWh84zCpD3mOa/FHYZxBDm2MfUmA1Q==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.1.1.tgz", + "integrity": "sha512-hwbpiUxLIY3TnZycieh+G4fbTWGMfzKx076O5Vuh2H4ZfXfs6ZXoi3Z0TH6X9lTmdgrwzOg1v4o5kdqu7MqPBg==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.1.0", - "@angular-eslint/utils": "16.1.0", + "@angular-eslint/bundled-angular-compiler": "16.1.1", + "@angular-eslint/utils": "16.1.1", "@typescript-eslint/type-utils": "5.62.0", "@typescript-eslint/utils": "5.62.0", "aria-query": "5.3.0", @@ -421,13 +428,13 @@ } }, "node_modules/@angular-eslint/schematics": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-16.1.0.tgz", - "integrity": "sha512-L1tmP3R2krHyveaRXAvn/SeDoBFNpS1VtPPrzZm1NYr1qPcAxf3NtG2nnoyVFu6WZGt59ZGHNQ/dZxnXvm0UGg==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-16.1.1.tgz", + "integrity": "sha512-KlR01gpURPjz5OcoEvmKv3zi8l6lFpXYmqkXbGMCz828QlqBz1X7iGLAPJki+WUFSFKbRsf4qqaWq6O/8vph7Q==", "dev": true, "dependencies": { - "@angular-eslint/eslint-plugin": "16.1.0", - "@angular-eslint/eslint-plugin-template": "16.1.0", + "@angular-eslint/eslint-plugin": "16.1.1", + "@angular-eslint/eslint-plugin-template": "16.1.1", "@nx/devkit": "16.5.1", "ignore": "5.2.4", "nx": "16.5.1", @@ -439,12 +446,12 @@ } }, "node_modules/@angular-eslint/template-parser": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-16.1.0.tgz", - "integrity": "sha512-DOQtzVehtbO7+BQ+FMOXRsxGRjHb3ve6M+S4qASKTiI+twtONjRODcHezD3N4PDkjpKPbOnk7YnFsHur5csUNw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-16.1.1.tgz", + "integrity": "sha512-ZJ+M4+JGYcsIP/t+XiuzL5A5pCjjCen272U3/M/WqIMDDxyIKrHubK1bVtr2kndCEudqud+WyJU0ub13UIwGgw==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.1.0", + "@angular-eslint/bundled-angular-compiler": "16.1.1", "eslint-scope": "^7.0.0" }, "peerDependencies": { @@ -453,12 +460,12 @@ } }, "node_modules/@angular-eslint/utils": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.1.0.tgz", - "integrity": "sha512-u5XscYUq1F/7RuwyVIV2a280QL27lyQz434VYR+Np/oO21NGj5jxoRKb55xhXT9EFVs5Sy4JYeEUp6S75J/cUw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.1.1.tgz", + "integrity": "sha512-cmSTyFFY2TMLjhKdju0KQ9GB6nnXt1AbY9tZ0UtWGo3NKbrBUogc+PR9ma17VRAGhvdj/sSVkStphJH3F7rUgQ==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.1.0", + "@angular-eslint/bundled-angular-compiler": "16.1.1", "@typescript-eslint/utils": "5.62.0" }, "peerDependencies": { @@ -467,9 +474,9 @@ } }, "node_modules/@angular/animations": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.1.8.tgz", - "integrity": "sha512-aIAf8EAZomgXMF6AP0wTPAc04Cvw+nL9nkEVwQNVxMByZpcbnnqHWHokLD8es8DzlwDT+EIZS4wZMBA4XUmPyA==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.1.9.tgz", + "integrity": "sha512-m7RREew0HWVAXnFrPBoV0J0d5wLvlMjqf/4YkrRSvQlAfic2pY+xKXjBxtSfb7QXl7d6/7htTLqKqmLRESkO3Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -477,7 +484,7 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "16.1.8" + "@angular/core": "16.1.9" } }, "node_modules/@angular/cdk": { @@ -497,15 +504,15 @@ } }, "node_modules/@angular/cli": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.1.7.tgz", - "integrity": "sha512-RNmRytkCFqmkGiiy6IrLEvKkipTEeZW1Un2aKbaPBM8qqfZCeUx8TfU+G4DI4w1jvJ8IwzkYQLAi4NPk1DPxmQ==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.0.tgz", + "integrity": "sha512-xT8vJOyw6Rc2364XDW2jHagLgKu7342ktd/lt+c0u6R+AB2XVFMePR7VceLohX9N/vRUsbQ0nVSZr+ru/hA+HA==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1601.7", - "@angular-devkit/core": "16.1.7", - "@angular-devkit/schematics": "16.1.7", - "@schematics/angular": "16.1.7", + "@angular-devkit/architect": "0.1602.0", + "@angular-devkit/core": "16.2.0", + "@angular-devkit/schematics": "16.2.0", + "@schematics/angular": "16.2.0", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.1", @@ -517,7 +524,7 @@ "ora": "5.4.1", "pacote": "15.2.0", "resolve": "1.22.2", - "semver": "7.5.3", + "semver": "7.5.4", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -531,9 +538,9 @@ } }, "node_modules/@angular/common": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.1.8.tgz", - "integrity": "sha512-Zm+Ysxdf74VwG3mbAqs2v1QFUR+h9RyJBXF5VFABEpgFw7NUOBKrayjJmKjgZ0TBAmL2+nXehJgcPph3zNp3sg==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.1.9.tgz", + "integrity": "sha512-mBetJ08synwk5nvtreek/ny5+KYPImKcr/8phdqWcL4dxfXH5HKh7afBJorPXe890BAF0LFmfVeTOmwrzZu6oA==", "dependencies": { "tslib": "^2.3.0" }, @@ -541,14 +548,14 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "16.1.8", + "@angular/core": "16.1.9", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.1.8.tgz", - "integrity": "sha512-jF2zk3LjrcI/xpjJG6yoLiL2t2l5227i8SjhRUawAL1sy0xtb/PiSLjCNhuSgyixbB/8az/YezZe11MSg48FDg==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.1.9.tgz", + "integrity": "sha512-0gBvI6Eucah7r0TWxOg2YuZQjOWTO5dDbppeqZm90XRvjp+W4g+2A2EicdcLT6xasMeFslOTUIohS8eCddEglw==", "dependencies": { "tslib": "^2.3.0" }, @@ -556,7 +563,7 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "16.1.8" + "@angular/core": "16.1.9" }, "peerDependenciesMeta": { "@angular/core": { @@ -565,9 +572,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.1.8.tgz", - "integrity": "sha512-Whk3RBnEYwN0c6Mo7hU6JDpHSyKONmIQEN8ViHJXwmyHK8w+/Z27iBw10QiyWUMtYb4tIM1xSLhRFAwH/3WnPQ==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.1.9.tgz", + "integrity": "sha512-RWmo+YnE8pH28iu1XqqnkVyZKvQiMS/ovavKMfUzesuJpunUZFsYLJhpMRGz6S9pOiYCowye99x9YVYzvpLT6w==", "dev": true, "dependencies": { "@babel/core": "7.22.5", @@ -588,14 +595,53 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/compiler": "16.1.8", + "@angular/compiler": "16.1.9", "typescript": ">=4.9.3 <5.2" } }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", + "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "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==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@angular/core": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.1.8.tgz", - "integrity": "sha512-XtOpY9HA85hPGrPwe1rgE8NJ3bFWbuJFx4SUlzB66k9B5jo8bD2Dxl/0id55RFS5gmvCe/Qhh0zoGyMpkWjMHA==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.1.9.tgz", + "integrity": "sha512-EPveq1kBb79/WtyAOiGeYgyh/we20TddbpQG23WZVjXHH0GoL6mmV2QHwQHOi9tYNeOneUz2bC3F88qbiacuOA==", "dependencies": { "tslib": "^2.3.0" }, @@ -608,9 +654,9 @@ } }, "node_modules/@angular/forms": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.1.8.tgz", - "integrity": "sha512-V36q42ExvL93T7oYvRf4Z2z2V/kOm0wgaFgkNSiBHgIpuwvrAZ9nRZBui5Fqdnep3xKYd980vAaTtACA1blv3Q==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.1.9.tgz", + "integrity": "sha512-WojLwxcJ9v2Mv7UEqbFM3GmLi9AGISPe1cqlnno22dZR/33XuK0OY1h/jIGj3WjwH4O++ksPa8NfJeJMRxLpsA==", "dependencies": { "tslib": "^2.3.0" }, @@ -618,16 +664,16 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "16.1.8", - "@angular/core": "16.1.8", - "@angular/platform-browser": "16.1.8", + "@angular/common": "16.1.9", + "@angular/core": "16.1.9", + "@angular/platform-browser": "16.1.9", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.1.8.tgz", - "integrity": "sha512-wfUCVU7DLMHy5Rw7LY8KSTuLk0ff2bWElT6WSAKXXFEPjQiWuXbbIe+gglJX5HFQQHoyVwNbsSDIIgEp535Kvw==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.1.9.tgz", + "integrity": "sha512-a3DKGIsPYF7Hz323oGYmibLfn9fim91r9J03Hib/p4PbhRquyA5drm4mWT6+6IUhlYZCm2z9y9NVfYGrkLS+fw==", "dependencies": { "tslib": "^2.3.0" }, @@ -635,9 +681,9 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/animations": "16.1.8", - "@angular/common": "16.1.8", - "@angular/core": "16.1.8" + "@angular/animations": "16.1.9", + "@angular/common": "16.1.9", + "@angular/core": "16.1.9" }, "peerDependenciesMeta": { "@angular/animations": { @@ -646,9 +692,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.1.8.tgz", - "integrity": "sha512-mhQH78Zn/oFe+U8DmVvPJ0/7neDlnKcgktQ7f1vFNibRLqkmHW/o1vZ0B7CAmO+yzGbB8mt+RBCFAfA7g3oRDg==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.1.9.tgz", + "integrity": "sha512-M+nRbLph8FecStiMTlkwAW/Tj9FzvT3gXP7gJDyFMz8lFmXRI2r4+r40Gx3jfA4+rQG0ArTq842aLBldi305Uw==", "dependencies": { "tslib": "^2.3.0" }, @@ -656,16 +702,16 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "16.1.8", - "@angular/compiler": "16.1.8", - "@angular/core": "16.1.8", - "@angular/platform-browser": "16.1.8" + "@angular/common": "16.1.9", + "@angular/compiler": "16.1.9", + "@angular/core": "16.1.9", + "@angular/platform-browser": "16.1.9" } }, "node_modules/@angular/router": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.1.8.tgz", - "integrity": "sha512-p11Mz0qQbl26fcEEQ9LEUZhKrca9kqSwMWgxBRMWZl0AgtbWQadiVdjiQY0rvpohI7qSO8m3s7CFIQLKIOEvYQ==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.1.9.tgz", + "integrity": "sha512-73dFYwcYc6mmhjHDPJsZr2hbwDTNXDBYJ6cjNk9PPtMJe70ylL0MgTR3sMtibqlhvulUtjS1E0SsWMmqq3u8FA==", "dependencies": { "tslib": "^2.3.0" }, @@ -673,9 +719,9 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "16.1.8", - "@angular/core": "16.1.8", - "@angular/platform-browser": "16.1.8", + "@angular/common": "16.1.9", + "@angular/core": "16.1.9", + "@angular/platform-browser": "16.1.9", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -686,12 +732,13 @@ "dev": true }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -707,26 +754,26 @@ } }, "node_modules/@babel/core": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", - "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helpers": "^7.22.5", - "@babel/parser": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", + "@babel/traverse": "^7.22.8", "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.2", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -746,9 +793,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.7.tgz", - "integrity": "sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "dev": true, "dependencies": { "@babel/types": "^7.22.5", @@ -773,21 +820,21 @@ } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", - "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz", + "integrity": "sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", - "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", + "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", "dev": true, "dependencies": { "@babel/compat-data": "^7.22.9", @@ -798,9 +845,6 @@ }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { @@ -813,9 +857,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz", - "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.11.tgz", + "integrity": "sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -835,18 +879,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/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-create-class-features-plugin/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -975,18 +1007,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-module-transforms/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-optimise-call-expression": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", @@ -1067,9 +1087,9 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", + "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" @@ -1106,41 +1126,41 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz", - "integrity": "sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz", + "integrity": "sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==", "dev": true, "dependencies": { "@babel/helper-function-name": "^7.22.5", "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", - "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz", + "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==", "dev": true, "dependencies": { "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.6", - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.22.11", + "@babel/types": "^7.22.11" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -1148,9 +1168,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.13.tgz", + "integrity": "sha512-3l6+4YOvc9wx7VlCSw4yQfcBo01ECA8TicQfbnCPuCEpRQrf+gTUyGdxNw+pyTUyywp6JRD1w0YQs9TpBXYlkw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1488,14 +1508,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz", - "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.11.tgz", + "integrity": "sha512-0pAlmeRJn6wU84zzZsEOx1JV1Jf8fqO9ok7wofIJwUnplYo247dcd24P+cMJht7ts9xkzdtB0EPHmOb7F+KzXw==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -1538,9 +1558,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", - "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz", + "integrity": "sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1569,12 +1589,12 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", - "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", + "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, @@ -1608,18 +1628,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes/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/plugin-transform-computed-properties": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", @@ -1637,9 +1645,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", - "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz", + "integrity": "sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1683,9 +1691,9 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", - "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", + "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -1715,9 +1723,9 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", - "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", + "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -1763,9 +1771,9 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", - "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", + "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -1794,9 +1802,9 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", - "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", + "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -1841,12 +1849,12 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", - "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.11.tgz", + "integrity": "sha512-o2+bg7GDS60cJMgz9jWqRUsWkMzLCxp+jFDeDUT5sjRlAxcJWZ2ylNdI7QQ2+CH5hWu7OnN+Cv3htt7AkSf96g==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-simple-access": "^7.22.5" }, @@ -1858,13 +1866,13 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", - "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz", + "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==", "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.5" }, @@ -1923,9 +1931,9 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", - "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", + "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -1939,9 +1947,9 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", - "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", + "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -1955,13 +1963,13 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", - "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.11.tgz", + "integrity": "sha512-nX8cPFa6+UmbepISvlf5jhQyaC7ASs/7UxHmMkuJ/k5xSHvDPPaibMo+v3TXwU/Pjqhep/nFNpd3zn4YR59pnw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.10", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.22.5" @@ -1990,9 +1998,9 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", - "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", + "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -2006,9 +2014,9 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz", - "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==", + "version": "7.22.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.12.tgz", + "integrity": "sha512-7XXCVqZtyFWqjDsYDY4T45w4mlx1rf7aOgkc/Ww76xkgBiOlmjPkx36PBLHa1k1rwWvVgYMPsbuVnIamx2ZQJw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -2054,13 +2062,13 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", - "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", + "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, @@ -2087,13 +2095,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", - "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", + "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.1" + "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" @@ -2118,17 +2126,17 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz", - "integrity": "sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", + "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "semver": "^6.3.0" + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -2223,9 +2231,9 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", - "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", + "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2286,13 +2294,13 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", - "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", + "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", @@ -2317,13 +2325,13 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.7", "@babel/plugin-transform-async-to-generator": "^7.22.5", "@babel/plugin-transform-block-scoped-functions": "^7.22.5", "@babel/plugin-transform-block-scoping": "^7.22.5", "@babel/plugin-transform-class-properties": "^7.22.5", "@babel/plugin-transform-class-static-block": "^7.22.5", - "@babel/plugin-transform-classes": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.6", "@babel/plugin-transform-computed-properties": "^7.22.5", "@babel/plugin-transform-destructuring": "^7.22.5", "@babel/plugin-transform-dotall-regex": "^7.22.5", @@ -2348,7 +2356,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.22.5", "@babel/plugin-transform-object-super": "^7.22.5", "@babel/plugin-transform-optional-catch-binding": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.6", "@babel/plugin-transform-parameters": "^7.22.5", "@babel/plugin-transform-private-methods": "^7.22.5", "@babel/plugin-transform-private-property-in-object": "^7.22.5", @@ -2366,11 +2374,11 @@ "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "^0.1.5", "@babel/types": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "core-js-compat": "^3.30.2", - "semver": "^6.3.0" + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -2411,9 +2419,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dev": true, "dependencies": { "regenerator-runtime": "^0.13.11" @@ -2437,19 +2445,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", + "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", "@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-function-name": "^7.22.5", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.22.11", + "@babel/types": "^7.22.11", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2457,22 +2465,25 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/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==", + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", + "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.10", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", + "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", @@ -2591,9 +2602,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz", + "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==", "cpu": [ "arm" ], @@ -2607,9 +2618,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz", + "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==", "cpu": [ "arm64" ], @@ -2623,9 +2634,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz", + "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==", "cpu": [ "x64" ], @@ -2639,9 +2650,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz", + "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==", "cpu": [ "arm64" ], @@ -2655,9 +2666,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz", + "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==", "cpu": [ "x64" ], @@ -2671,9 +2682,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz", + "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==", "cpu": [ "arm64" ], @@ -2687,9 +2698,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz", + "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==", "cpu": [ "x64" ], @@ -2703,9 +2714,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz", + "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==", "cpu": [ "arm" ], @@ -2719,9 +2730,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz", + "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==", "cpu": [ "arm64" ], @@ -2735,9 +2746,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz", + "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==", "cpu": [ "ia32" ], @@ -2751,9 +2762,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz", + "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==", "cpu": [ "loong64" ], @@ -2767,9 +2778,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz", + "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==", "cpu": [ "mips64el" ], @@ -2783,9 +2794,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz", + "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==", "cpu": [ "ppc64" ], @@ -2799,9 +2810,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz", + "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==", "cpu": [ "riscv64" ], @@ -2815,9 +2826,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz", + "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==", "cpu": [ "s390x" ], @@ -2831,9 +2842,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz", + "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==", "cpu": [ "x64" ], @@ -2847,9 +2858,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz", + "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==", "cpu": [ "x64" ], @@ -2863,9 +2874,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz", + "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==", "cpu": [ "x64" ], @@ -2879,9 +2890,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz", + "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==", "cpu": [ "x64" ], @@ -2895,9 +2906,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz", + "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==", "cpu": [ "arm64" ], @@ -2911,9 +2922,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz", + "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==", "cpu": [ "ia32" ], @@ -2927,9 +2938,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz", + "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==", "cpu": [ "x64" ], @@ -2958,18 +2969,18 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", - "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -3012,9 +3023,9 @@ "dev": true }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3057,18 +3068,18 @@ } }, "node_modules/@eslint/js": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", - "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", + "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -3234,9 +3245,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -3268,21 +3279,15 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -3290,22 +3295,22 @@ "dev": true }, "node_modules/@ngrx/effects": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-16.1.0.tgz", - "integrity": "sha512-sdLzxjdQcYht3SYiuhchF4uOxxZIy3h9TEoyVp6PZJmiLJqhMAmV9/+s3tPD7yKd4+4o4n+HeiLDOTlMxn3Bxg==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-16.2.0.tgz", + "integrity": "sha512-zZfq47LNoiRK+uS66Xm36mN07zm11AER1D9lTalX/G6jrV0bywgnAaukNNav9E33ZRrPEnCD8uu9BXZoboEYgA==", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@angular/core": "^16.0.0", - "@ngrx/store": "16.1.0", + "@ngrx/store": "16.2.0", "rxjs": "^6.5.3 || ^7.5.0" } }, "node_modules/@ngrx/store": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-16.1.0.tgz", - "integrity": "sha512-cGwI5wy+irIudQubfrbaKrDbJxCvu+lZYlBmsOlpzevQLCa+ZjNLrN05J025P3KvUmfzX4StEpAc8Ord089Kig==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-16.2.0.tgz", + "integrity": "sha512-C7oIUC87xXV+1dTGUwYG/L4p0IZdYv/Ou1nTL/LffyAHllmmygTA5gzLB87abLOhucAxlFIQMQ8t/GSxdk/+QA==", "dependencies": { "tslib": "^2.0.0" }, @@ -3315,9 +3320,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.1.7.tgz", - "integrity": "sha512-VRFH8crY969hKLIkYJKUuWjNIRCssq4QkKlUK4LCOLMd/xKNzl4H4EOsASKAQbBz58y6IUyh6b4utqMZ+oSTxA==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.0.tgz", + "integrity": "sha512-c9jv4r7GnLTpnPOeF+a9yAm/3/2wwl9lMBU32i9hlY+q/Hqde4PiL95bUOLnRRL1I64DV7BFTlSZqSPgDpFXZQ==", "dev": true, "engines": { "node": "^16.14.0 || >=18.10.0", @@ -3541,6 +3546,39 @@ "nx": ">= 15 <= 17" } }, + "node_modules/@nx/devkit/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@nx/nx-darwin-arm64": { "version": "16.5.1", "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.5.1.tgz", @@ -3800,13 +3838,13 @@ } }, "node_modules/@schematics/angular": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.1.7.tgz", - "integrity": "sha512-ynMh1o24ImTyHDsrwWzMwxIb5VUgk22ZD3SgcQ8I9ZSSPiFyCzNrbwz20+WqUfVtT0nsI+LWw9UaGPgwCLZnBQ==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.0.tgz", + "integrity": "sha512-Ib0/ZCkjWt7a5p3209JVwEWwf41v03K3ylvlxLIEo1ZGijAZAlrBj4GrA5YQ+TmPm2hRyt+owss7x91/x+i0Gw==", "dev": true, "dependencies": { - "@angular-devkit/core": "16.1.7", - "@angular-devkit/schematics": "16.1.7", + "@angular-devkit/core": "16.2.0", + "@angular-devkit/schematics": "16.2.0", "jsonc-parser": "3.2.0" }, "engines": { @@ -3931,9 +3969,9 @@ "dev": true }, "node_modules/@sigstore/bundle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.0.0.tgz", - "integrity": "sha512-yLvrWDOh6uMOUlFCTJIZEnwOT9Xte7NPXUqVexEKGSF5XtBAuSg5du0kn3dRR0p47a4ah10Y0mNt8+uyeQXrBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", + "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", "dev": true, "dependencies": { "@sigstore/protobuf-specs": "^0.2.0" @@ -3943,14 +3981,28 @@ } }, "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.0.tgz", - "integrity": "sha512-8ZhZKAVfXjIspDWwm3D3Kvj0ddbJ0HqDZ/pOs5cx88HpT8mVsotFrg7H1UMnXOuDHz6Zykwxn4mxG3QLuN+RUg==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@sigstore/sign": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", + "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@sigstore/tuf": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", @@ -3971,12 +4023,12 @@ "dev": true }, "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true, "engines": { - "node": ">= 10" + "node": ">= 6" } }, "node_modules/@tootallnate/quickjs-emscripten": { @@ -4085,9 +4137,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.44.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.1.tgz", - "integrity": "sha512-XpNDc4Z5Tb4x+SW1MriMVeIsMoONHCkWFMkR/aPJbzEsxqHy+4Glu/BqTdPrApfDeMaXbtNh6bseNgl5KaWrSg==", + "version": "8.44.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz", + "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==", "dev": true, "dependencies": { "@types/estree": "*", @@ -4123,9 +4175,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.35", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", - "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "version": "4.17.36", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.36.tgz", + "integrity": "sha512-zbivROJ0ZqLAtMzgzIUC4oNqDG9iF0lSsAqpOD9kbs5xcIM3dTiyuHvBc7R8MtWBp3AAWGaovJa+wzWPjLYW7Q==", "dev": true, "dependencies": { "@types/node": "*", @@ -4159,15 +4211,15 @@ } }, "node_modules/@types/jasmine": { - "version": "3.10.11", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.10.11.tgz", - "integrity": "sha512-tAiqDJrwRKyjpCgJE07OXFsXsXQWDhoJhyRwzl+yfEToy72s0LhHAfquMi2s4T4Iq3nanKOfZ8/PZFaL/0pQmA==", + "version": "3.10.12", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.10.12.tgz", + "integrity": "sha512-t8aMY7ByoMCJycjhFTUL57QicS9/h+E67QfJsN67d2Haoqb/hhgYBEG+l3jGHeFu0vQ7/+p3t6hZ/3YPSnOTzw==", "dev": true }, "node_modules/@types/jquery": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", - "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.17.tgz", + "integrity": "sha512-U40tNEAGSTZ7R1OC6kGkD7f4TKW5DoVx6jd9kTB9mo5truFMi1m9Yohnw9kl1WpTPvDdj7zAw38LfCHSqnk5kA==", "dev": true, "dependencies": { "@types/sizzle": "*" @@ -4180,9 +4232,9 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.14.196", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.196.tgz", - "integrity": "sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==", + "version": "4.14.197", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", + "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", "dev": true }, "node_modules/@types/luxon": { @@ -4221,9 +4273,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", "dev": true }, "node_modules/@types/send": { @@ -4651,32 +4703,125 @@ "@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==", - "dev": true - }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "node_modules/@wessberg/ts-evaluator": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/@wessberg/ts-evaluator/-/ts-evaluator-0.0.27.tgz", + "integrity": "sha512-7gOpVm3yYojUp/Yn7F4ZybJRxyqfMNf0LXK5KJiawbPfL0XTsJV+0mgrEDjOIR6Bi0OYk2Cyg4tjFu1r8MCZaA==", + "deprecated": "this package has been renamed to ts-evaluator. Please install ts-evaluator instead", "dev": true, "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" + "chalk": "^4.1.0", + "jsdom": "^16.4.0", + "object-path": "^0.11.5", + "tslib": "^2.0.3" + }, + "engines": { + "node": ">=10.1.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" + }, + "peerDependencies": { + "typescript": ">=3.2.x || >= 4.x" + } + }, + "node_modules/@wessberg/ts-evaluator/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/@wessberg/ts-evaluator/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/@wessberg/ts-evaluator/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/@wessberg/ts-evaluator/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/@wessberg/ts-evaluator/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/@wessberg/ts-evaluator/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/@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==", + "dev": true + }, + "node_modules/@yarnpkg/parsers": { + "version": "3.0.0-rc.46", + "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", + "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "dev": true, + "dependencies": { + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" }, "engines": { "node": ">=14.15.0" @@ -4737,6 +4882,28 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "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", @@ -4755,6 +4922,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "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", @@ -4795,13 +4971,11 @@ } }, "node_modules/agentkeepalive": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", - "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", "dev": true, "dependencies": { - "debug": "^4.1.0", - "depd": "^2.0.0", "humanize-ms": "^1.2.1" }, "engines": { @@ -5165,9 +5339,9 @@ } }, "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", "dev": true, "dependencies": { "follow-redirects": "^1.15.0", @@ -5211,12 +5385,12 @@ "dev": true }, "node_modules/babel-loader": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", - "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", + "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": "^3.3.2", + "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" }, "engines": { @@ -5497,6 +5671,12 @@ "node": ">=8" } }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -5594,16 +5774,16 @@ } }, "node_modules/cacache": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", - "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", + "version": "17.1.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", + "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", "dev": true, "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^7.7.1", - "minipass": "^5.0.0", + "minipass": "^7.0.3", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", @@ -5671,6 +5851,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/cacache/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/cachedir": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", @@ -5712,9 +5901,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001519", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", - "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", + "version": "1.0.30001524", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz", + "integrity": "sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==", "dev": true, "funding": [ { @@ -6040,6 +6229,12 @@ "node": ">= 6" } }, + "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/common-tags": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", @@ -6049,12 +6244,6 @@ "node": ">=4.0.0" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -6138,6 +6327,30 @@ "node": ">=8" } }, + "node_modules/configstore/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/configstore/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/connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", @@ -6261,34 +6474,6 @@ "webpack": "^5.1.0" } }, - "node_modules/copy-webpack-plugin/node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "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/copy-webpack-plugin/node_modules/fast-glob/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==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "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", @@ -6333,12 +6518,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.0.tgz", - "integrity": "sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw==", + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.1.tgz", + "integrity": "sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==", "dev": true, "dependencies": { - "browserslist": "^4.21.9" + "browserslist": "^4.21.10" }, "funding": { "type": "opencollective", @@ -6401,9 +6586,9 @@ } }, "node_modules/critters": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.19.tgz", - "integrity": "sha512-Fm4ZAXsG0VzWy1U30rP4qxbaWGSsqXDgSupJW1OUJGDAs0KWC+j37v7p5a2kZ9BPJvhRzWm3be+Hc9WvQOBUOw==", + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", + "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -6589,6 +6774,30 @@ "node": ">=4" } }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -6596,13 +6805,13 @@ "dev": true }, "node_modules/cypress": { - "version": "12.17.3", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.17.3.tgz", - "integrity": "sha512-/R4+xdIDjUSLYkiQfwJd630S81KIgicmQOLXotFxVXkl+eTeVO+3bHXxdi5KBh/OgC33HWN33kHX+0tQR/ZWpg==", + "version": "12.17.4", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.17.4.tgz", + "integrity": "sha512-gAN8Pmns9MA5eCDFSDJXWKUpaL3IDd89N9TtIupjYnzLSmlpVr+ZR+vb4U/qaMp+lB6tBvAmt7504c3Z4RU5KQ==", "dev": true, "hasInstallScript": true, "dependencies": { - "@cypress/request": "^2.88.11", + "@cypress/request": "2.88.12", "@cypress/xvfb": "^1.2.4", "@types/node": "^16.18.39", "@types/sinonjs__fake-timers": "8.1.1", @@ -6637,6 +6846,7 @@ "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", + "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "semver": "^7.5.3", @@ -6688,9 +6898,9 @@ } }, "node_modules/cypress/node_modules/@types/node": { - "version": "16.18.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.39.tgz", - "integrity": "sha512-8q9ZexmdYYyc5/cfujaXb4YOucpQxAV4RMG0himLyDUOEr8Mr79VrqsFI+cQ2M2h89YIuy95lbxuYjxT4Hk4kQ==", + "version": "16.18.46", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.46.tgz", + "integrity": "sha512-Mnq3O9Xz52exs3mlxMcQuA7/9VFe/dXcrgAyfjLkABIqxXKOgBRjyazTxUbjsxDa4BP7hhPliyjVTP9RDP14xg==", "dev": true }, "node_modules/cypress/node_modules/ansi-styles": { @@ -6799,6 +7009,20 @@ "node": ">= 14" } }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/date-format": { "version": "4.0.14", "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", @@ -6863,6 +7087,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "node_modules/deep-equal": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", @@ -7112,9 +7342,9 @@ "dev": true }, "node_modules/dns-packet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", - "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "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" @@ -7173,6 +7403,27 @@ } ] }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -7267,9 +7518,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.484", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.484.tgz", - "integrity": "sha512-nO3ZEomTK2PO/3TUXgEx0A97xZTpKVf4p427lABHuCpT1IQ2N+njVh29DkQkCk6Q4m2wjU+faK4xAcfFndwjvw==", + "version": "1.4.505", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.505.tgz", + "integrity": "sha512-0A50eL5BCCKdxig2SsCXhpuztnB9PfUgRMojj5tMvt8O54lbwz3t6wNgnpiTRosw5QjlJB7ixhVyeg8daLQwSQ==", "dev": true }, "node_modules/emoji-regex": { @@ -7487,9 +7738,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", + "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==", "dev": true, "hasInstallScript": true, "bin": { @@ -7499,34 +7750,34 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.17", + "@esbuild/android-arm64": "0.18.17", + "@esbuild/android-x64": "0.18.17", + "@esbuild/darwin-arm64": "0.18.17", + "@esbuild/darwin-x64": "0.18.17", + "@esbuild/freebsd-arm64": "0.18.17", + "@esbuild/freebsd-x64": "0.18.17", + "@esbuild/linux-arm": "0.18.17", + "@esbuild/linux-arm64": "0.18.17", + "@esbuild/linux-ia32": "0.18.17", + "@esbuild/linux-loong64": "0.18.17", + "@esbuild/linux-mips64el": "0.18.17", + "@esbuild/linux-ppc64": "0.18.17", + "@esbuild/linux-riscv64": "0.18.17", + "@esbuild/linux-s390x": "0.18.17", + "@esbuild/linux-x64": "0.18.17", + "@esbuild/netbsd-x64": "0.18.17", + "@esbuild/openbsd-x64": "0.18.17", + "@esbuild/sunos-x64": "0.18.17", + "@esbuild/win32-arm64": "0.18.17", + "@esbuild/win32-ia32": "0.18.17", + "@esbuild/win32-x64": "0.18.17" } }, "node_modules/esbuild-wasm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.19.tgz", - "integrity": "sha512-X9UQEMJMZXwlGCfqcBmJ1jEa+KrLfd+gCBypO/TSzo5hZvbVwFqpxj1YCuX54ptTF75wxmrgorR4RL40AKtLVg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.18.17.tgz", + "integrity": "sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==", "dev": true, "bin": { "esbuild": "bin/esbuild" @@ -7591,15 +7842,15 @@ } }, "node_modules/eslint": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", - "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", + "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.1", - "@eslint/js": "^8.46.0", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.48.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -7610,7 +7861,7 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.2", + "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", @@ -7661,9 +7912,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", - "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -7784,9 +8035,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -8263,15 +8514,15 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-fifo": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.0.tgz", - "integrity": "sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", "dev": true }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -8328,8 +8579,8 @@ }, "node_modules/fecfile-validate": { "version": "0.0.1", - "resolved": "git+ssh://git@github.com/fecgov/fecfile-validate.git#d313a8bf821a2bc0957b16a7c899544de898281e", - "integrity": "sha512-tTdvuQUVE8Df9YaCWXsSnPaD1OOaFHK41MNAmzuVNxUenTizZK5oyelL9Wi43WH04WgnRxG8h1k1ijp9uV+dsw==", + "resolved": "git+ssh://git@github.com/fecgov/fecfile-validate.git#f801280c3ab220c452e98eafae196245cf165416", + "integrity": "sha512-aZ4WTFScV7o8As2cKVeB+O0hF4kfSmD3IBapfBLYa2rX+OmssxmBaALDdm3WeJn49TWcHTjdxXWRHO+OiMjwSw==", "hasInstallScript": true, "license": "CC0-1.0", "dependencies": { @@ -8451,20 +8702,19 @@ } }, "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "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": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/find-up": { @@ -8490,16 +8740,17 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.7", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=12.0.0" } }, "node_modules/flatted": { @@ -8598,16 +8849,16 @@ } }, "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.0.tgz", + "integrity": "sha512-btalnXjFelOv2cy86KzHWhUuMb622/AD8ce/MCH9C36xe7QRXjJZA+19fP+G5LT0fdRcbOHErMI3SPM11ZaVDg==", "dev": true, "engines": { "node": "*" }, "funding": { "type": "patreon", - "url": "https://www.patreon.com/infusion" + "url": "https://github.com/sponsors/rawify" } }, "node_modules/fresh": { @@ -8641,17 +8892,26 @@ } }, "node_modules/fs-minipass": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", - "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, "dependencies": { - "minipass": "^5.0.0" + "minipass": "^7.0.3" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/fs-monkey": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", @@ -8665,9 +8925,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -8955,6 +9215,18 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/guess-parser": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/guess-parser/-/guess-parser-0.4.22.tgz", + "integrity": "sha512-KcUWZ5ACGaBM69SbqwVIuWGoSAgD+9iJnchR9j/IarVI1jHVeXv+bUXBIMeqVMSKt3zrn0Dgf9UpcOEpPBLbSg==", + "dev": true, + "dependencies": { + "@wessberg/ts-evaluator": "0.0.27" + }, + "peerDependencies": { + "typescript": ">=3.7.5" + } + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -9144,6 +9416,18 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/html-entities": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", @@ -9252,12 +9536,12 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, "dependencies": { - "@tootallnate/once": "2", + "@tootallnate/once": "1", "agent-base": "6", "debug": "4" }, @@ -9443,9 +9727,9 @@ "dev": true }, "node_modules/immutable": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.2.tgz", - "integrity": "sha512-oGXzbEDem9OOpDWZu88jGiYCvIsLHMvGw+8OXlpsvTFvIQplQbjg1B1cvKg8f7Hoch6+NGjpPsH1Fr+Mc2D1aA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", "dev": true }, "node_modules/import-fresh": { @@ -9763,9 +10047,9 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -9940,6 +10224,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -10188,21 +10478,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-report/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/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10252,9 +10527,9 @@ } }, "node_modules/jackspeak": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.2.tgz", - "integrity": "sha512-mgNtVv4vUuaKA97yxUHoA3+FkuhtxkjdXEWOyB/N76fjy0FjezEt34oy3epBtvCvS+7DyKwqCFWx/oJLV5+kCg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.0.tgz", + "integrity": "sha512-uKmsITSsF4rUWQHzqaRUuyAir3fZfW3f202Ee34lz/gZCi970CPZwyQXLGNgWJvvZbvFyzeyGq0+4fcG/mBKZg==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -10402,9 +10677,9 @@ } }, "node_modules/jiti": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", - "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==", + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.3.tgz", + "integrity": "sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==", "dev": true, "bin": { "jiti": "bin/jiti.js" @@ -10450,6 +10725,72 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -10462,6 +10803,12 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "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", @@ -10739,6 +11086,15 @@ "node": ">=10" } }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -11370,41 +11726,32 @@ } }, "node_modules/magic-string": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", - "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", + "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", "dev": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "@jridgewell/sourcemap-codec": "^1.4.15" }, "engines": { "node": ">=12" } }, "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "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": "^6.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/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/make-fetch-happen": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", @@ -11431,6 +11778,29 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/make-fetch-happen/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/make-fetch-happen/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -11644,12 +12014,12 @@ "dev": true }, "node_modules/minipass-fetch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz", - "integrity": "sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "dev": true, "dependencies": { - "minipass": "^5.0.0", + "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" }, @@ -11660,6 +12030,15 @@ "encoding": "^0.1.13" } }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -12605,9 +12984,9 @@ } }, "node_modules/ngx-cookie-service": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-16.0.0.tgz", - "integrity": "sha512-bD0F8/I6Y7lfP1THeQDR70hv1SSEfFOjJqF1tnLphNBvR9EwkITO2KSOtfag7VH5CHT16PRIqv8XaGRDbCNAmA==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-16.0.1.tgz", + "integrity": "sha512-q8i5eX2b6SIIZcu9wy+lvOU65cLJhHD9EVz5TGGkKi8Y7X/aZbUyQ9U4CgNOfKDWtPUDFOMD8IW/cijoVKe59Q==", "dependencies": { "tslib": "^2.0.0" }, @@ -12650,9 +13029,9 @@ "dev": true }, "node_modules/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -12669,6 +13048,28 @@ } } }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -12704,9 +13105,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", "dev": true, "bin": { "node-gyp-build": "bin.js", @@ -12794,9 +13195,9 @@ } }, "node_modules/npm-install-checks": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz", - "integrity": "sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.2.0.tgz", + "integrity": "sha512-744wat5wAAHsxa4590mWO0tJ8PKxR8ORZsH9wGpQc3nWTzozMAgBN/XyqYw7mg3yqLM8dLwEnwSfKMmXAjF69g==", "dev": true, "dependencies": { "semver": "^7.1.1" @@ -12913,6 +13314,12 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, "node_modules/nx": { "version": "16.5.1", "resolved": "https://registry.npmjs.org/nx/-/nx-16.5.1.tgz", @@ -13118,6 +13525,18 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/nx/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/nx/node_modules/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", @@ -13130,6 +13549,21 @@ "node": "*" } }, + "node_modules/nx/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/nx/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13142,6 +13576,12 @@ "node": ">=8" } }, + "node_modules/nx/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -13185,6 +13625,15 @@ "node": ">= 0.4" } }, + "node_modules/object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "dev": true, + "engines": { + "node": ">= 10.12.0" + } + }, "node_modules/object.assign": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", @@ -13768,9 +14217,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.0.tgz", - "integrity": "sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -13831,9 +14280,9 @@ } }, "node_modules/piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.0.0.tgz", + "integrity": "sha512-641nAmJS4k4iqpNUqfggqUBUMmlw0ZoM5VZKdQkV2e970Inn3Tk9kroCc1wpsYLD07vCwpys5iY0d3xI/9WkTg==", "dev": true, "dependencies": { "eventemitter-asyncresource": "^1.0.0", @@ -13845,21 +14294,106 @@ } }, "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "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": "^4.0.0" + "find-up": "^6.3.0" }, "engines": { - "node": ">=8" + "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/pkg-dir/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/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", + "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", "dev": true, "funding": [ { @@ -13885,14 +14419,13 @@ } }, "node_modules/postcss-loader": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.2.tgz", - "integrity": "sha512-c7qDlXErX6n0VT+LUsW+nwefVtTu3ORtVvK8EXuUIDcxo+b/euYqpuHlJAvePb0Af5e8uMjR/13e0lTuYifaig==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", "dev": true, "dependencies": { - "cosmiconfig": "^8.1.3", + "cosmiconfig": "^8.2.0", "jiti": "^1.18.2", - "klona": "^2.0.6", "semver": "^7.3.8" }, "engines": { @@ -14058,6 +14591,15 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.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", @@ -14630,9 +15172,9 @@ "dev": true }, "node_modules/regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "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" @@ -14865,9 +15407,9 @@ } }, "node_modules/rollup": { - "version": "3.27.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.27.2.tgz", - "integrity": "sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==", + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz", + "integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -14947,9 +15489,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.63.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.2.tgz", - "integrity": "sha512-u56TU0AIFqMtauKl/OJ1AeFsXqRHkgO7nCWmHaDwfxDo9GUMSqBA4NEh6GMuh1CYVM7zuROYtZrHzPc2ixK+ww==", + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.1.tgz", + "integrity": "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -14964,12 +15506,11 @@ } }, "node_modules/sass-loader": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.1.tgz", - "integrity": "sha512-cBTxmgyVA1nXPvIK4brjJMXOMJ2v2YrQEuHqLw3LylGb3gsR6jAvdjHMcy/+JGTmmIF9SauTrLLR7bsWDMWqgg==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "dev": true, "dependencies": { - "klona": "^2.0.6", "neo-async": "^2.6.2" }, "engines": { @@ -15008,6 +15549,18 @@ "dev": true, "optional": true }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "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", @@ -15046,9 +15599,9 @@ } }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -15312,13 +15865,14 @@ "dev": true }, "node_modules/sigstore": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.8.0.tgz", - "integrity": "sha512-ogU8qtQ3VFBawRJ8wjsBEX/vIFeHuGs1fm4jZtjWQwjo8pfAt7T/rh+udlAN4+QUe0IzA8qRSc/YZ7dHP6kh+w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", + "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", "dev": true, "dependencies": { - "@sigstore/bundle": "^1.0.0", + "@sigstore/bundle": "^1.1.0", "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", "@sigstore/tuf": "^1.0.3", "make-fetch-happen": "^11.0.1" }, @@ -15716,17 +16270,26 @@ } }, "node_modules/ssri": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz", - "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", "dev": true, "dependencies": { - "minipass": "^5.0.0" + "minipass": "^7.0.3" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/ssri/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -15795,9 +16358,9 @@ } }, "node_modules/streamx": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.0.tgz", - "integrity": "sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz", + "integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==", "dev": true, "dependencies": { "fast-fifo": "^1.1.0", @@ -15947,6 +16510,12 @@ "node": ">=0.10" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -16069,9 +16638,9 @@ } }, "node_modules/terser": { - "version": "5.17.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.7.tgz", - "integrity": "sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -16196,9 +16765,9 @@ "dev": true }, "node_modules/third-party-web": { - "version": "0.23.3", - "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.23.3.tgz", - "integrity": "sha512-ifZcy79XYPmt9kQSTaHVh3IaL3Pms60iumsBrBBm6PPrtlNGdj56wznKl1LgSw8KpMWOwqOrlI/WCasQjflIZA==", + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.23.4.tgz", + "integrity": "sha512-kwYnSZRhEvv0SBW2fp8SBBKRglMoBjV8xz6C31m0ewqOtknB5UL+Ihg+M81hyFY5ldkZuGWPb+e4GVDkzf/gYg==", "dev": true }, "node_modules/throttleit": { @@ -16286,10 +16855,16 @@ } }, "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } }, "node_modules/tree-kill": { "version": "1.2.2", @@ -16324,9 +16899,9 @@ } }, "node_modules/tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -16730,6 +17305,28 @@ "node": ">=0.10.0" } }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -16762,15 +17359,18 @@ } }, "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } }, "node_modules/webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -16782,7 +17382,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -16792,7 +17392,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -16843,9 +17443,9 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz", - "integrity": "sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ==", + "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", @@ -16854,7 +17454,7 @@ "@types/serve-index": "^1.9.1", "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/ws": "^8.5.5", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", @@ -16901,6 +17501,15 @@ } } }, + "node_modules/webpack-dev-server/node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", @@ -17082,14 +17691,33 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" } }, "node_modules/which": { @@ -17334,6 +17962,18 @@ "node": ">=8" } }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -17478,51 +18118,51 @@ } }, "@angular-devkit/architect": { - "version": "0.1601.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1601.7.tgz", - "integrity": "sha512-uFa7/TTPYoYLqgiRi5HZJaOXterVe9A83Sd+e3NXMmvT6oTMyLv0/t0Luhjic6c4vFrNnF3ECkrlGs2qW4TslA==", + "version": "0.1602.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.0.tgz", + "integrity": "sha512-ZRmUTBeD+uGr605eOHnsovEn6f1mOBI+kxP64DRvagNweX5TN04s3iyQ8jmLSAHQD9ush31LFxv3dVNxv3ceXQ==", "dev": true, "requires": { - "@angular-devkit/core": "16.1.7", + "@angular-devkit/core": "16.2.0", "rxjs": "7.8.1" } }, "@angular-devkit/build-angular": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.1.7.tgz", - "integrity": "sha512-zUkPH3QDpA//hhMjMm9pKcbhO2gZjy4EkWrPglvR6G6a0myZc6/rEYK3W8gQWP1jiYiha/PiGnxTb+XeN/74tQ==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.0.tgz", + "integrity": "sha512-miylwjOqvlKmYrzS84bjRaJrecZxOXH9xsPVvQE8VBe8UKePJjRAL6yyOqXUOGtzlch2YmT98RAnuni7y0FEAw==", "dev": true, "requires": { "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1601.7", - "@angular-devkit/build-webpack": "0.1601.7", - "@angular-devkit/core": "16.1.7", - "@babel/core": "7.22.5", - "@babel/generator": "7.22.7", + "@angular-devkit/architect": "0.1602.0", + "@angular-devkit/build-webpack": "0.1602.0", + "@angular-devkit/core": "16.2.0", + "@babel/core": "7.22.9", + "@babel/generator": "7.22.9", "@babel/helper-annotate-as-pure": "7.22.5", - "@babel/helper-split-export-declaration": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", "@babel/plugin-proposal-async-generator-functions": "7.20.7", "@babel/plugin-transform-async-to-generator": "7.22.5", - "@babel/plugin-transform-runtime": "7.22.5", - "@babel/preset-env": "7.22.5", - "@babel/runtime": "7.22.5", + "@babel/plugin-transform-runtime": "7.22.9", + "@babel/preset-env": "7.22.9", + "@babel/runtime": "7.22.6", "@babel/template": "7.22.5", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "16.1.7", + "@ngtools/webpack": "16.2.0", "@vitejs/plugin-basic-ssl": "1.0.1", "ansi-colors": "4.1.3", "autoprefixer": "10.4.14", - "babel-loader": "9.1.2", + "babel-loader": "9.1.3", "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.21.5", - "cacache": "17.1.3", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", - "critters": "0.0.19", + "critters": "0.0.20", "css-loader": "6.8.1", - "esbuild": "0.17.19", - "esbuild-wasm": "0.17.19", - "fast-glob": "3.2.12", + "esbuild": "0.18.17", + "esbuild-wasm": "0.18.17", + "fast-glob": "3.3.1", + "guess-parser": "0.4.22", "https-proxy-agent": "5.0.1", "inquirer": "8.2.4", "jsonc-parser": "3.2.0", @@ -17531,39 +18171,39 @@ "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.30.0", + "magic-string": "0.30.1", "mini-css-extract-plugin": "2.7.6", "mrmime": "1.0.1", "open": "8.4.2", "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", "picomatch": "2.3.1", - "piscina": "3.2.0", - "postcss": "8.4.24", - "postcss-loader": "7.3.2", + "piscina": "4.0.0", + "postcss": "8.4.27", + "postcss-loader": "7.3.3", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.63.2", - "sass-loader": "13.3.1", - "semver": "7.5.3", + "sass": "1.64.1", + "sass-loader": "13.3.2", + "semver": "7.5.4", "source-map-loader": "4.0.1", "source-map-support": "0.5.21", - "terser": "5.17.7", + "terser": "5.19.2", "text-table": "0.2.0", "tree-kill": "1.2.2", - "tslib": "2.5.3", - "vite": "4.3.9", - "webpack": "5.86.0", + "tslib": "2.6.1", + "vite": "4.4.7", + "webpack": "5.88.2", "webpack-dev-middleware": "6.1.1", - "webpack-dev-server": "4.15.0", + "webpack-dev-server": "4.15.1", "webpack-merge": "5.9.0", "webpack-subresource-integrity": "5.1.0" }, "dependencies": { "@types/node": { - "version": "20.4.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.7.tgz", - "integrity": "sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g==", + "version": "20.5.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz", + "integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==", "dev": true, "optional": true, "peer": true @@ -17576,39 +18216,39 @@ "requires": {} }, "tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", "dev": true }, "vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", + "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==", "dev": true, "requires": { - "esbuild": "^0.17.5", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "postcss": "^8.4.26", + "rollup": "^3.25.2" } } } }, "@angular-devkit/build-webpack": { - "version": "0.1601.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1601.7.tgz", - "integrity": "sha512-BFqjL9mz0gtS10ucwmx7fFb1PprBzt6glN7ZEGhx58tterW68N9zZNFHR0AXmWoyVp/1B2oJWmqAQ52fakyshg==", + "version": "0.1602.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.0.tgz", + "integrity": "sha512-KdSr6iAcO30i/LIGL8mYi+d1buVXuDCp2dptzEJ4vxReOMFJca90KLwb+tVHEqqnDb0WkNfWm8Ii2QYh2FrNyA==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1601.7", + "@angular-devkit/architect": "0.1602.0", "rxjs": "7.8.1" } }, "@angular-devkit/core": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.1.7.tgz", - "integrity": "sha512-AXc9/F57Nf/A26yGu+w7PhNYriTvwazPTQsVPW/SBcTcpBa/hAsBTbPl8o8ErRJneJIoYqy/EIuabf9iiU8bRA==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.0.tgz", + "integrity": "sha512-l1k6Rqm3YM16BEn3CWyQKrk9xfu+2ux7Bw3oS+h1TO4/RoxO2PgHj8LLRh/WNrYVarhaqO7QZ5ePBkXNMkzJ1g==", "dev": true, "requires": { "ajv": "8.12.0", @@ -17619,22 +18259,22 @@ } }, "@angular-devkit/schematics": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.1.7.tgz", - "integrity": "sha512-FQ/svSrUyalHVxgudoXAJbwgdPZ1iaEc6My4s4ti2HFtw0vqPw7Dh9bkRiMN3/MGMAdvsUIBiz8oSELZhuJTJg==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.0.tgz", + "integrity": "sha512-QMDJXPE0+YQJ9Ap3MMzb0v7rx6ZbBEokmHgpdIjN3eILYmbAdsSGE8HTV8NjS9nKmcyE9OGzFCMb7PFrDTlTAw==", "dev": true, "requires": { - "@angular-devkit/core": "16.1.7", + "@angular-devkit/core": "16.2.0", "jsonc-parser": "3.2.0", - "magic-string": "0.30.0", + "magic-string": "0.30.1", "ora": "5.4.1", "rxjs": "7.8.1" } }, "@angular-eslint/builder": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.1.0.tgz", - "integrity": "sha512-KIkE2SI1twFKoCiF/k2VR3ojOcc7TD1xPyY4kbUrx/Gxp+XEzar7O29I/ztzL4eHPBM+Uh3/NwS/jvjjBxjgAg==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.1.1.tgz", + "integrity": "sha512-NaB/A0mmlzp7laiucRUsRyoCrOE1In3UifsGP0vD6yjUpefk4g0v+0vCg8mhsIky8gYDtBE9YRfUiLA9FlF/FA==", "dev": true, "requires": { "@nx/devkit": "16.5.1", @@ -17642,29 +18282,29 @@ } }, "@angular-eslint/bundled-angular-compiler": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.1.0.tgz", - "integrity": "sha512-5EFAWXuFJADr3imo/ZYshY8s0K7U7wyysnE2LXnpT9PAi5rmkzt70UNZNRuamCbXr4tdIiu+fXWOj7tUuJKnnw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.1.1.tgz", + "integrity": "sha512-TB01AWZBDfrZBxN1I50HfBXtC7q4NI5fwl1aS4tOfef2/kQjTtR9zmha8CsxjDkAOa9tA/4MUayAMqEBQLuHKQ==", "dev": true }, "@angular-eslint/eslint-plugin": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-16.1.0.tgz", - "integrity": "sha512-BFzzJJlgQgWc8avdSBkaDWAzNSUqcwWy0L1iZSBdXGoIOxj72kLbwe99emb8M+rUfCveljQkeM2pcYu8XLbJIA==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-16.1.1.tgz", + "integrity": "sha512-GauEwFGEcgIdsld4cVarFJYYxaRbMLzbpxyvBUDFg4LNjlcQNt7zfqXRLJoZAaFJFPtGtAoo1+6BlEKErsntuQ==", "dev": true, "requires": { - "@angular-eslint/utils": "16.1.0", + "@angular-eslint/utils": "16.1.1", "@typescript-eslint/utils": "5.62.0" } }, "@angular-eslint/eslint-plugin-template": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.1.0.tgz", - "integrity": "sha512-wQHWR5vqWGgO7mqoG5ixXeplIlz/OmxBJE9QMLPTZE8GdaTx8+F/5J37OWh84zCpD3mOa/FHYZxBDm2MfUmA1Q==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.1.1.tgz", + "integrity": "sha512-hwbpiUxLIY3TnZycieh+G4fbTWGMfzKx076O5Vuh2H4ZfXfs6ZXoi3Z0TH6X9lTmdgrwzOg1v4o5kdqu7MqPBg==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "16.1.0", - "@angular-eslint/utils": "16.1.0", + "@angular-eslint/bundled-angular-compiler": "16.1.1", + "@angular-eslint/utils": "16.1.1", "@typescript-eslint/type-utils": "5.62.0", "@typescript-eslint/utils": "5.62.0", "aria-query": "5.3.0", @@ -17672,13 +18312,13 @@ } }, "@angular-eslint/schematics": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-16.1.0.tgz", - "integrity": "sha512-L1tmP3R2krHyveaRXAvn/SeDoBFNpS1VtPPrzZm1NYr1qPcAxf3NtG2nnoyVFu6WZGt59ZGHNQ/dZxnXvm0UGg==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-16.1.1.tgz", + "integrity": "sha512-KlR01gpURPjz5OcoEvmKv3zi8l6lFpXYmqkXbGMCz828QlqBz1X7iGLAPJki+WUFSFKbRsf4qqaWq6O/8vph7Q==", "dev": true, "requires": { - "@angular-eslint/eslint-plugin": "16.1.0", - "@angular-eslint/eslint-plugin-template": "16.1.0", + "@angular-eslint/eslint-plugin": "16.1.1", + "@angular-eslint/eslint-plugin-template": "16.1.1", "@nx/devkit": "16.5.1", "ignore": "5.2.4", "nx": "16.5.1", @@ -17687,29 +18327,29 @@ } }, "@angular-eslint/template-parser": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-16.1.0.tgz", - "integrity": "sha512-DOQtzVehtbO7+BQ+FMOXRsxGRjHb3ve6M+S4qASKTiI+twtONjRODcHezD3N4PDkjpKPbOnk7YnFsHur5csUNw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-16.1.1.tgz", + "integrity": "sha512-ZJ+M4+JGYcsIP/t+XiuzL5A5pCjjCen272U3/M/WqIMDDxyIKrHubK1bVtr2kndCEudqud+WyJU0ub13UIwGgw==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "16.1.0", + "@angular-eslint/bundled-angular-compiler": "16.1.1", "eslint-scope": "^7.0.0" } }, "@angular-eslint/utils": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.1.0.tgz", - "integrity": "sha512-u5XscYUq1F/7RuwyVIV2a280QL27lyQz434VYR+Np/oO21NGj5jxoRKb55xhXT9EFVs5Sy4JYeEUp6S75J/cUw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.1.1.tgz", + "integrity": "sha512-cmSTyFFY2TMLjhKdju0KQ9GB6nnXt1AbY9tZ0UtWGo3NKbrBUogc+PR9ma17VRAGhvdj/sSVkStphJH3F7rUgQ==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "16.1.0", + "@angular-eslint/bundled-angular-compiler": "16.1.1", "@typescript-eslint/utils": "5.62.0" } }, "@angular/animations": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.1.8.tgz", - "integrity": "sha512-aIAf8EAZomgXMF6AP0wTPAc04Cvw+nL9nkEVwQNVxMByZpcbnnqHWHokLD8es8DzlwDT+EIZS4wZMBA4XUmPyA==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.1.9.tgz", + "integrity": "sha512-m7RREew0HWVAXnFrPBoV0J0d5wLvlMjqf/4YkrRSvQlAfic2pY+xKXjBxtSfb7QXl7d6/7htTLqKqmLRESkO3Q==", "requires": { "tslib": "^2.3.0" } @@ -17724,15 +18364,15 @@ } }, "@angular/cli": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.1.7.tgz", - "integrity": "sha512-RNmRytkCFqmkGiiy6IrLEvKkipTEeZW1Un2aKbaPBM8qqfZCeUx8TfU+G4DI4w1jvJ8IwzkYQLAi4NPk1DPxmQ==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.0.tgz", + "integrity": "sha512-xT8vJOyw6Rc2364XDW2jHagLgKu7342ktd/lt+c0u6R+AB2XVFMePR7VceLohX9N/vRUsbQ0nVSZr+ru/hA+HA==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1601.7", - "@angular-devkit/core": "16.1.7", - "@angular-devkit/schematics": "16.1.7", - "@schematics/angular": "16.1.7", + "@angular-devkit/architect": "0.1602.0", + "@angular-devkit/core": "16.2.0", + "@angular-devkit/schematics": "16.2.0", + "@schematics/angular": "16.2.0", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.1", @@ -17744,31 +18384,31 @@ "ora": "5.4.1", "pacote": "15.2.0", "resolve": "1.22.2", - "semver": "7.5.3", + "semver": "7.5.4", "symbol-observable": "4.0.0", "yargs": "17.7.2" } }, "@angular/common": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.1.8.tgz", - "integrity": "sha512-Zm+Ysxdf74VwG3mbAqs2v1QFUR+h9RyJBXF5VFABEpgFw7NUOBKrayjJmKjgZ0TBAmL2+nXehJgcPph3zNp3sg==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.1.9.tgz", + "integrity": "sha512-mBetJ08synwk5nvtreek/ny5+KYPImKcr/8phdqWcL4dxfXH5HKh7afBJorPXe890BAF0LFmfVeTOmwrzZu6oA==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.1.8.tgz", - "integrity": "sha512-jF2zk3LjrcI/xpjJG6yoLiL2t2l5227i8SjhRUawAL1sy0xtb/PiSLjCNhuSgyixbB/8az/YezZe11MSg48FDg==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.1.9.tgz", + "integrity": "sha512-0gBvI6Eucah7r0TWxOg2YuZQjOWTO5dDbppeqZm90XRvjp+W4g+2A2EicdcLT6xasMeFslOTUIohS8eCddEglw==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler-cli": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.1.8.tgz", - "integrity": "sha512-Whk3RBnEYwN0c6Mo7hU6JDpHSyKONmIQEN8ViHJXwmyHK8w+/Z27iBw10QiyWUMtYb4tIM1xSLhRFAwH/3WnPQ==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.1.9.tgz", + "integrity": "sha512-RWmo+YnE8pH28iu1XqqnkVyZKvQiMS/ovavKMfUzesuJpunUZFsYLJhpMRGz6S9pOiYCowye99x9YVYzvpLT6w==", "dev": true, "requires": { "@babel/core": "7.22.5", @@ -17779,44 +18419,77 @@ "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^17.2.1" + }, + "dependencies": { + "@babel/core": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", + "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + } } }, "@angular/core": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.1.8.tgz", - "integrity": "sha512-XtOpY9HA85hPGrPwe1rgE8NJ3bFWbuJFx4SUlzB66k9B5jo8bD2Dxl/0id55RFS5gmvCe/Qhh0zoGyMpkWjMHA==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.1.9.tgz", + "integrity": "sha512-EPveq1kBb79/WtyAOiGeYgyh/we20TddbpQG23WZVjXHH0GoL6mmV2QHwQHOi9tYNeOneUz2bC3F88qbiacuOA==", "requires": { "tslib": "^2.3.0" } }, "@angular/forms": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.1.8.tgz", - "integrity": "sha512-V36q42ExvL93T7oYvRf4Z2z2V/kOm0wgaFgkNSiBHgIpuwvrAZ9nRZBui5Fqdnep3xKYd980vAaTtACA1blv3Q==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.1.9.tgz", + "integrity": "sha512-WojLwxcJ9v2Mv7UEqbFM3GmLi9AGISPe1cqlnno22dZR/33XuK0OY1h/jIGj3WjwH4O++ksPa8NfJeJMRxLpsA==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-browser": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.1.8.tgz", - "integrity": "sha512-wfUCVU7DLMHy5Rw7LY8KSTuLk0ff2bWElT6WSAKXXFEPjQiWuXbbIe+gglJX5HFQQHoyVwNbsSDIIgEp535Kvw==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.1.9.tgz", + "integrity": "sha512-a3DKGIsPYF7Hz323oGYmibLfn9fim91r9J03Hib/p4PbhRquyA5drm4mWT6+6IUhlYZCm2z9y9NVfYGrkLS+fw==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-browser-dynamic": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.1.8.tgz", - "integrity": "sha512-mhQH78Zn/oFe+U8DmVvPJ0/7neDlnKcgktQ7f1vFNibRLqkmHW/o1vZ0B7CAmO+yzGbB8mt+RBCFAfA7g3oRDg==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.1.9.tgz", + "integrity": "sha512-M+nRbLph8FecStiMTlkwAW/Tj9FzvT3gXP7gJDyFMz8lFmXRI2r4+r40Gx3jfA4+rQG0ArTq842aLBldi305Uw==", "requires": { "tslib": "^2.3.0" } }, "@angular/router": { - "version": "16.1.8", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.1.8.tgz", - "integrity": "sha512-p11Mz0qQbl26fcEEQ9LEUZhKrca9kqSwMWgxBRMWZl0AgtbWQadiVdjiQY0rvpohI7qSO8m3s7CFIQLKIOEvYQ==", + "version": "16.1.9", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.1.9.tgz", + "integrity": "sha512-73dFYwcYc6mmhjHDPJsZr2hbwDTNXDBYJ6cjNk9PPtMJe70ylL0MgTR3sMtibqlhvulUtjS1E0SsWMmqq3u8FA==", "requires": { "tslib": "^2.3.0" } @@ -17828,12 +18501,13 @@ "dev": true }, "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -17843,26 +18517,26 @@ "dev": true }, "@babel/core": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", - "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", "dev": true, "requires": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helpers": "^7.22.5", - "@babel/parser": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", + "@babel/traverse": "^7.22.8", "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.2", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "dependencies": { "semver": { @@ -17874,9 +18548,9 @@ } }, "@babel/generator": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.7.tgz", - "integrity": "sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "dev": true, "requires": { "@babel/types": "^7.22.5", @@ -17895,18 +18569,18 @@ } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", - "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz", + "integrity": "sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.10" } }, "@babel/helper-compilation-targets": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", - "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", + "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", "dev": true, "requires": { "@babel/compat-data": "^7.22.9", @@ -17925,9 +18599,9 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz", - "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.11.tgz", + "integrity": "sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -17941,15 +18615,6 @@ "semver": "^6.3.1" }, "dependencies": { - "@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, - "requires": { - "@babel/types": "^7.22.5" - } - }, "semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -18044,17 +18709,6 @@ "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "@babel/helper-validator-identifier": "^7.22.5" - }, - "dependencies": { - "@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, - "requires": { - "@babel/types": "^7.22.5" - } - } } }, "@babel/helper-optimise-call-expression": { @@ -18113,9 +18767,9 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", + "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, "requires": { "@babel/types": "^7.22.5" @@ -18140,42 +18794,42 @@ "dev": true }, "@babel/helper-wrap-function": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz", - "integrity": "sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz", + "integrity": "sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==", "dev": true, "requires": { "@babel/helper-function-name": "^7.22.5", "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.10" } }, "@babel/helpers": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", - "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz", + "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==", "dev": true, "requires": { "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.6", - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.22.11", + "@babel/types": "^7.22.11" } }, "@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.13.tgz", + "integrity": "sha512-3l6+4YOvc9wx7VlCSw4yQfcBo01ECA8TicQfbnCPuCEpRQrf+gTUyGdxNw+pyTUyywp6JRD1w0YQs9TpBXYlkw==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -18400,14 +19054,14 @@ } }, "@babel/plugin-transform-async-generator-functions": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz", - "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.11.tgz", + "integrity": "sha512-0pAlmeRJn6wU84zzZsEOx1JV1Jf8fqO9ok7wofIJwUnplYo247dcd24P+cMJht7ts9xkzdtB0EPHmOb7F+KzXw==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, @@ -18432,9 +19086,9 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", - "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz", + "integrity": "sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5" @@ -18451,12 +19105,12 @@ } }, "@babel/plugin-transform-class-static-block": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", - "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", + "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-class-static-block": "^7.14.5" } @@ -18476,17 +19130,6 @@ "@babel/helper-replace-supers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" - }, - "dependencies": { - "@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, - "requires": { - "@babel/types": "^7.22.5" - } - } } }, "@babel/plugin-transform-computed-properties": { @@ -18500,9 +19143,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", - "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz", + "integrity": "sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5" @@ -18528,9 +19171,9 @@ } }, "@babel/plugin-transform-dynamic-import": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", - "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", + "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", @@ -18548,9 +19191,9 @@ } }, "@babel/plugin-transform-export-namespace-from": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", - "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", + "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", @@ -18578,9 +19221,9 @@ } }, "@babel/plugin-transform-json-strings": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", - "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", + "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", @@ -18597,9 +19240,9 @@ } }, "@babel/plugin-transform-logical-assignment-operators": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", - "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", + "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", @@ -18626,24 +19269,24 @@ } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", - "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.11.tgz", + "integrity": "sha512-o2+bg7GDS60cJMgz9jWqRUsWkMzLCxp+jFDeDUT5sjRlAxcJWZ2ylNdI7QQ2+CH5hWu7OnN+Cv3htt7AkSf96g==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-simple-access": "^7.22.5" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", - "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz", + "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==", "dev": true, "requires": { "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.5" } @@ -18678,9 +19321,9 @@ } }, "@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", - "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", + "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", @@ -18688,9 +19331,9 @@ } }, "@babel/plugin-transform-numeric-separator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", - "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", + "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", @@ -18698,13 +19341,13 @@ } }, "@babel/plugin-transform-object-rest-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", - "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.11.tgz", + "integrity": "sha512-nX8cPFa6+UmbepISvlf5jhQyaC7ASs/7UxHmMkuJ/k5xSHvDPPaibMo+v3TXwU/Pjqhep/nFNpd3zn4YR59pnw==", "dev": true, "requires": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.10", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.22.5" @@ -18721,9 +19364,9 @@ } }, "@babel/plugin-transform-optional-catch-binding": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", - "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", + "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", @@ -18731,9 +19374,9 @@ } }, "@babel/plugin-transform-optional-chaining": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz", - "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==", + "version": "7.22.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.12.tgz", + "integrity": "sha512-7XXCVqZtyFWqjDsYDY4T45w4mlx1rf7aOgkc/Ww76xkgBiOlmjPkx36PBLHa1k1rwWvVgYMPsbuVnIamx2ZQJw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", @@ -18761,13 +19404,13 @@ } }, "@babel/plugin-transform-private-property-in-object": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", - "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", + "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } @@ -18782,13 +19425,13 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", - "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", + "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.1" + "regenerator-transform": "^0.15.2" } }, "@babel/plugin-transform-reserved-words": { @@ -18801,17 +19444,17 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz", - "integrity": "sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", + "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "semver": "^6.3.0" + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "semver": "^6.3.1" }, "dependencies": { "semver": { @@ -18869,9 +19512,9 @@ } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", - "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", + "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.22.5" @@ -18908,13 +19551,13 @@ } }, "@babel/preset-env": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", - "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", + "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", "dev": true, "requires": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", @@ -18939,13 +19582,13 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.7", "@babel/plugin-transform-async-to-generator": "^7.22.5", "@babel/plugin-transform-block-scoped-functions": "^7.22.5", "@babel/plugin-transform-block-scoping": "^7.22.5", "@babel/plugin-transform-class-properties": "^7.22.5", "@babel/plugin-transform-class-static-block": "^7.22.5", - "@babel/plugin-transform-classes": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.6", "@babel/plugin-transform-computed-properties": "^7.22.5", "@babel/plugin-transform-destructuring": "^7.22.5", "@babel/plugin-transform-dotall-regex": "^7.22.5", @@ -18970,7 +19613,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.22.5", "@babel/plugin-transform-object-super": "^7.22.5", "@babel/plugin-transform-optional-catch-binding": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.6", "@babel/plugin-transform-parameters": "^7.22.5", "@babel/plugin-transform-private-methods": "^7.22.5", "@babel/plugin-transform-private-property-in-object": "^7.22.5", @@ -18988,11 +19631,11 @@ "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "^0.1.5", "@babel/types": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "core-js-compat": "^3.30.2", - "semver": "^6.3.0" + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "dependencies": { "semver": { @@ -19023,9 +19666,9 @@ "dev": true }, "@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dev": true, "requires": { "regenerator-runtime": "^0.13.11" @@ -19043,38 +19686,41 @@ } }, "@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", + "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", "@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-function-name": "^7.22.5", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.22.11", + "@babel/types": "^7.22.11", "debug": "^4.1.0", "globals": "^11.1.0" }, "dependencies": { - "@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==", + "@babel/generator": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", + "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.10", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" } } } }, "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", + "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.22.5", @@ -19178,156 +19824,156 @@ "dev": true }, "@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz", + "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz", + "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz", + "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz", + "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz", + "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz", + "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz", + "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz", + "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz", + "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz", + "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz", + "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz", + "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz", + "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz", + "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz", + "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz", + "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz", + "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz", + "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz", + "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz", + "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz", + "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz", + "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==", "dev": true, "optional": true }, @@ -19341,15 +19987,15 @@ } }, "@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", "dev": true }, "@eslint/eslintrc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", - "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -19382,9 +20028,9 @@ "dev": true }, "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -19414,15 +20060,15 @@ } }, "@eslint/js": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", - "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", + "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -19538,9 +20184,9 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true }, "@jridgewell/set-array": { @@ -19566,21 +20212,13 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@leichtgewicht/ip-codec": { @@ -19590,25 +20228,25 @@ "dev": true }, "@ngrx/effects": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-16.1.0.tgz", - "integrity": "sha512-sdLzxjdQcYht3SYiuhchF4uOxxZIy3h9TEoyVp6PZJmiLJqhMAmV9/+s3tPD7yKd4+4o4n+HeiLDOTlMxn3Bxg==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-16.2.0.tgz", + "integrity": "sha512-zZfq47LNoiRK+uS66Xm36mN07zm11AER1D9lTalX/G6jrV0bywgnAaukNNav9E33ZRrPEnCD8uu9BXZoboEYgA==", "requires": { "tslib": "^2.0.0" } }, "@ngrx/store": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-16.1.0.tgz", - "integrity": "sha512-cGwI5wy+irIudQubfrbaKrDbJxCvu+lZYlBmsOlpzevQLCa+ZjNLrN05J025P3KvUmfzX4StEpAc8Ord089Kig==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-16.2.0.tgz", + "integrity": "sha512-C7oIUC87xXV+1dTGUwYG/L4p0IZdYv/Ou1nTL/LffyAHllmmygTA5gzLB87abLOhucAxlFIQMQ8t/GSxdk/+QA==", "requires": { "tslib": "^2.0.0" } }, "@ngtools/webpack": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.1.7.tgz", - "integrity": "sha512-VRFH8crY969hKLIkYJKUuWjNIRCssq4QkKlUK4LCOLMd/xKNzl4H4EOsASKAQbBz58y6IUyh6b4utqMZ+oSTxA==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.0.tgz", + "integrity": "sha512-c9jv4r7GnLTpnPOeF+a9yAm/3/2wwl9lMBU32i9hlY+q/Hqde4PiL95bUOLnRRL1I64DV7BFTlSZqSPgDpFXZQ==", "dev": true, "requires": {} }, @@ -19770,6 +20408,32 @@ "semver": "7.5.3", "tmp": "~0.2.1", "tslib": "^2.3.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } } }, "@nx/nx-darwin-arm64": { @@ -19908,13 +20572,13 @@ } }, "@schematics/angular": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.1.7.tgz", - "integrity": "sha512-ynMh1o24ImTyHDsrwWzMwxIb5VUgk22ZD3SgcQ8I9ZSSPiFyCzNrbwz20+WqUfVtT0nsI+LWw9UaGPgwCLZnBQ==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.0.tgz", + "integrity": "sha512-Ib0/ZCkjWt7a5p3209JVwEWwf41v03K3ylvlxLIEo1ZGijAZAlrBj4GrA5YQ+TmPm2hRyt+owss7x91/x+i0Gw==", "dev": true, "requires": { - "@angular-devkit/core": "16.1.7", - "@angular-devkit/schematics": "16.1.7", + "@angular-devkit/core": "16.2.0", + "@angular-devkit/schematics": "16.2.0", "jsonc-parser": "3.2.0" } }, @@ -20026,20 +20690,31 @@ } }, "@sigstore/bundle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.0.0.tgz", - "integrity": "sha512-yLvrWDOh6uMOUlFCTJIZEnwOT9Xte7NPXUqVexEKGSF5XtBAuSg5du0kn3dRR0p47a4ah10Y0mNt8+uyeQXrBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", + "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", "dev": true, "requires": { "@sigstore/protobuf-specs": "^0.2.0" } }, "@sigstore/protobuf-specs": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.0.tgz", - "integrity": "sha512-8ZhZKAVfXjIspDWwm3D3Kvj0ddbJ0HqDZ/pOs5cx88HpT8mVsotFrg7H1UMnXOuDHz6Zykwxn4mxG3QLuN+RUg==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", "dev": true }, + "@sigstore/sign": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", + "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "dev": true, + "requires": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + } + }, "@sigstore/tuf": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", @@ -20057,9 +20732,9 @@ "dev": true }, "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, "@tootallnate/quickjs-emscripten": { @@ -20158,9 +20833,9 @@ } }, "@types/eslint": { - "version": "8.44.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.1.tgz", - "integrity": "sha512-XpNDc4Z5Tb4x+SW1MriMVeIsMoONHCkWFMkR/aPJbzEsxqHy+4Glu/BqTdPrApfDeMaXbtNh6bseNgl5KaWrSg==", + "version": "8.44.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz", + "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==", "dev": true, "requires": { "@types/estree": "*", @@ -20196,9 +20871,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.35", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", - "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "version": "4.17.36", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.36.tgz", + "integrity": "sha512-zbivROJ0ZqLAtMzgzIUC4oNqDG9iF0lSsAqpOD9kbs5xcIM3dTiyuHvBc7R8MtWBp3AAWGaovJa+wzWPjLYW7Q==", "dev": true, "requires": { "@types/node": "*", @@ -20232,15 +20907,15 @@ } }, "@types/jasmine": { - "version": "3.10.11", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.10.11.tgz", - "integrity": "sha512-tAiqDJrwRKyjpCgJE07OXFsXsXQWDhoJhyRwzl+yfEToy72s0LhHAfquMi2s4T4Iq3nanKOfZ8/PZFaL/0pQmA==", + "version": "3.10.12", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.10.12.tgz", + "integrity": "sha512-t8aMY7ByoMCJycjhFTUL57QicS9/h+E67QfJsN67d2Haoqb/hhgYBEG+l3jGHeFu0vQ7/+p3t6hZ/3YPSnOTzw==", "dev": true }, "@types/jquery": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", - "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.17.tgz", + "integrity": "sha512-U40tNEAGSTZ7R1OC6kGkD7f4TKW5DoVx6jd9kTB9mo5truFMi1m9Yohnw9kl1WpTPvDdj7zAw38LfCHSqnk5kA==", "dev": true, "requires": { "@types/sizzle": "*" @@ -20253,9 +20928,9 @@ "dev": true }, "@types/lodash": { - "version": "4.14.196", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.196.tgz", - "integrity": "sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==", + "version": "4.14.197", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", + "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", "dev": true }, "@types/luxon": { @@ -20294,9 +20969,9 @@ "dev": true }, "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", "dev": true }, "@types/send": { @@ -20631,6 +21306,69 @@ "@xtuc/long": "4.2.2" } }, + "@wessberg/ts-evaluator": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/@wessberg/ts-evaluator/-/ts-evaluator-0.0.27.tgz", + "integrity": "sha512-7gOpVm3yYojUp/Yn7F4ZybJRxyqfMNf0LXK5KJiawbPfL0XTsJV+0mgrEDjOIR6Bi0OYk2Cyg4tjFu1r8MCZaA==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "jsdom": "^16.4.0", + "object-path": "^0.11.5", + "tslib": "^2.0.3" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -20704,6 +21442,24 @@ "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } + } + }, "acorn-import-assertions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", @@ -20718,6 +21474,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, "adjust-sourcemap-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", @@ -20751,13 +21513,11 @@ } }, "agentkeepalive": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", - "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", "dev": true, "requires": { - "debug": "^4.1.0", - "depd": "^2.0.0", "humanize-ms": "^1.2.1" } }, @@ -21007,9 +21767,9 @@ "dev": true }, "axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", "dev": true, "requires": { "follow-redirects": "^1.15.0", @@ -21052,12 +21812,12 @@ "dev": true }, "babel-loader": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", - "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dev": true, "requires": { - "find-cache-dir": "^3.3.2", + "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" } }, @@ -21275,6 +22035,12 @@ "fill-range": "^7.0.1" } }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -21332,16 +22098,16 @@ "dev": true }, "cacache": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", - "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", + "version": "17.1.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", + "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", "dev": true, "requires": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^7.7.1", - "minipass": "^5.0.0", + "minipass": "^7.0.3", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", @@ -21387,6 +22153,12 @@ "requires": { "brace-expansion": "^2.0.1" } + }, + "minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true } } }, @@ -21419,9 +22191,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001519", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", - "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", + "version": "1.0.30001524", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz", + "integrity": "sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==", "dev": true }, "caseless": { @@ -21644,18 +22416,18 @@ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true }, + "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 + }, "common-tags": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "dev": true }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -21727,6 +22499,23 @@ "unique-string": "^2.0.0", "write-file-atomic": "^3.0.0", "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } } }, "connect": { @@ -21826,30 +22615,6 @@ "serialize-javascript": "^6.0.0" }, "dependencies": { - "fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "requires": { - "@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" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -21881,12 +22646,12 @@ } }, "core-js-compat": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.0.tgz", - "integrity": "sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw==", + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.1.tgz", + "integrity": "sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==", "dev": true, "requires": { - "browserslist": "^4.21.9" + "browserslist": "^4.21.10" } }, "core-util-is": { @@ -21935,9 +22700,9 @@ } }, "critters": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.19.tgz", - "integrity": "sha512-Fm4ZAXsG0VzWy1U30rP4qxbaWGSsqXDgSupJW1OUJGDAs0KWC+j37v7p5a2kZ9BPJvhRzWm3be+Hc9WvQOBUOw==", + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", + "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -22073,6 +22838,29 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -22080,12 +22868,12 @@ "dev": true }, "cypress": { - "version": "12.17.3", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.17.3.tgz", - "integrity": "sha512-/R4+xdIDjUSLYkiQfwJd630S81KIgicmQOLXotFxVXkl+eTeVO+3bHXxdi5KBh/OgC33HWN33kHX+0tQR/ZWpg==", + "version": "12.17.4", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.17.4.tgz", + "integrity": "sha512-gAN8Pmns9MA5eCDFSDJXWKUpaL3IDd89N9TtIupjYnzLSmlpVr+ZR+vb4U/qaMp+lB6tBvAmt7504c3Z4RU5KQ==", "dev": true, "requires": { - "@cypress/request": "^2.88.11", + "@cypress/request": "2.88.12", "@cypress/xvfb": "^1.2.4", "@types/node": "^16.18.39", "@types/sinonjs__fake-timers": "8.1.1", @@ -22120,6 +22908,7 @@ "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", + "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "semver": "^7.5.3", @@ -22130,9 +22919,9 @@ }, "dependencies": { "@types/node": { - "version": "16.18.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.39.tgz", - "integrity": "sha512-8q9ZexmdYYyc5/cfujaXb4YOucpQxAV4RMG0himLyDUOEr8Mr79VrqsFI+cQ2M2h89YIuy95lbxuYjxT4Hk4kQ==", + "version": "16.18.46", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.46.tgz", + "integrity": "sha512-Mnq3O9Xz52exs3mlxMcQuA7/9VFe/dXcrgAyfjLkABIqxXKOgBRjyazTxUbjsxDa4BP7hhPliyjVTP9RDP14xg==", "dev": true }, "ansi-styles": { @@ -22237,6 +23026,17 @@ "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", "dev": true }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, "date-format": { "version": "4.0.14", "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", @@ -22277,6 +23077,12 @@ "dev": true, "peer": true }, + "decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "deep-equal": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", @@ -22470,9 +23276,9 @@ "dev": true }, "dns-packet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", - "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, "requires": { "@leichtgewicht/ip-codec": "^2.0.1" @@ -22510,12 +23316,29 @@ "entities": "^4.2.0" } }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true - }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, "domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -22589,9 +23412,9 @@ } }, "electron-to-chromium": { - "version": "1.4.484", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.484.tgz", - "integrity": "sha512-nO3ZEomTK2PO/3TUXgEx0A97xZTpKVf4p427lABHuCpT1IQ2N+njVh29DkQkCk6Q4m2wjU+faK4xAcfFndwjvw==", + "version": "1.4.505", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.505.tgz", + "integrity": "sha512-0A50eL5BCCKdxig2SsCXhpuztnB9PfUgRMojj5tMvt8O54lbwz3t6wNgnpiTRosw5QjlJB7ixhVyeg8daLQwSQ==", "dev": true }, "emoji-regex": { @@ -22763,39 +23586,39 @@ "dev": true }, "esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", + "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.18.17", + "@esbuild/android-arm64": "0.18.17", + "@esbuild/android-x64": "0.18.17", + "@esbuild/darwin-arm64": "0.18.17", + "@esbuild/darwin-x64": "0.18.17", + "@esbuild/freebsd-arm64": "0.18.17", + "@esbuild/freebsd-x64": "0.18.17", + "@esbuild/linux-arm": "0.18.17", + "@esbuild/linux-arm64": "0.18.17", + "@esbuild/linux-ia32": "0.18.17", + "@esbuild/linux-loong64": "0.18.17", + "@esbuild/linux-mips64el": "0.18.17", + "@esbuild/linux-ppc64": "0.18.17", + "@esbuild/linux-riscv64": "0.18.17", + "@esbuild/linux-s390x": "0.18.17", + "@esbuild/linux-x64": "0.18.17", + "@esbuild/netbsd-x64": "0.18.17", + "@esbuild/openbsd-x64": "0.18.17", + "@esbuild/sunos-x64": "0.18.17", + "@esbuild/win32-arm64": "0.18.17", + "@esbuild/win32-ia32": "0.18.17", + "@esbuild/win32-x64": "0.18.17" } }, "esbuild-wasm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.19.tgz", - "integrity": "sha512-X9UQEMJMZXwlGCfqcBmJ1jEa+KrLfd+gCBypO/TSzo5hZvbVwFqpxj1YCuX54ptTF75wxmrgorR4RL40AKtLVg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.18.17.tgz", + "integrity": "sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==", "dev": true }, "escalade": { @@ -22838,15 +23661,15 @@ } }, "eslint": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", - "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", + "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.1", - "@eslint/js": "^8.46.0", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.48.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -22857,7 +23680,7 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.2", + "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", @@ -22960,9 +23783,9 @@ } }, "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -23044,9 +23867,9 @@ } }, "eslint-visitor-keys": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", - "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true }, "espree": { @@ -23340,15 +24163,15 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-fifo": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.0.tgz", - "integrity": "sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", "dev": true }, "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -23398,9 +24221,9 @@ } }, "fecfile-validate": { - "version": "git+ssh://git@github.com/fecgov/fecfile-validate.git#d313a8bf821a2bc0957b16a7c899544de898281e", - "integrity": "sha512-tTdvuQUVE8Df9YaCWXsSnPaD1OOaFHK41MNAmzuVNxUenTizZK5oyelL9Wi43WH04WgnRxG8h1k1ijp9uV+dsw==", - "from": "fecfile-validate@https://github.com/fecgov/fecfile-validate#d313a8bf821a2bc0957b16a7c899544de898281e", + "version": "git+ssh://git@github.com/fecgov/fecfile-validate.git#f801280c3ab220c452e98eafae196245cf165416", + "integrity": "sha512-aZ4WTFScV7o8As2cKVeB+O0hF4kfSmD3IBapfBLYa2rX+OmssxmBaALDdm3WeJn49TWcHTjdxXWRHO+OiMjwSw==", + "from": "fecfile-validate@https://github.com/fecgov/fecfile-validate#f801280c3ab220c452e98eafae196245cf165416", "requires": { "ajv": "^8.11.0" } @@ -23503,14 +24326,13 @@ } }, "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "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, "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" } }, "find-up": { @@ -23530,12 +24352,13 @@ "dev": true }, "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", "dev": true, "requires": { - "flatted": "^3.1.0", + "flatted": "^3.2.7", + "keyv": "^4.5.3", "rimraf": "^3.0.2" } }, @@ -23602,9 +24425,9 @@ "dev": true }, "fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.0.tgz", + "integrity": "sha512-btalnXjFelOv2cy86KzHWhUuMb622/AD8ce/MCH9C36xe7QRXjJZA+19fP+G5LT0fdRcbOHErMI3SPM11ZaVDg==", "dev": true }, "fresh": { @@ -23632,12 +24455,20 @@ } }, "fs-minipass": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", - "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, "requires": { - "minipass": "^5.0.0" + "minipass": "^7.0.3" + }, + "dependencies": { + "minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true + } } }, "fs-monkey": { @@ -23653,9 +24484,9 @@ "dev": true }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, @@ -23877,6 +24708,15 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "guess-parser": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/guess-parser/-/guess-parser-0.4.22.tgz", + "integrity": "sha512-KcUWZ5ACGaBM69SbqwVIuWGoSAgD+9iJnchR9j/IarVI1jHVeXv+bUXBIMeqVMSKt3zrn0Dgf9UpcOEpPBLbSg==", + "dev": true, + "requires": { + "@wessberg/ts-evaluator": "0.0.27" + } + }, "handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -24031,6 +24871,15 @@ } } }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, "html-entities": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", @@ -24112,12 +24961,12 @@ } }, "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, "requires": { - "@tootallnate/once": "2", + "@tootallnate/once": "1", "agent-base": "6", "debug": "4" } @@ -24242,9 +25091,9 @@ "dev": true }, "immutable": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.2.tgz", - "integrity": "sha512-oGXzbEDem9OOpDWZu88jGiYCvIsLHMvGw+8OXlpsvTFvIQplQbjg1B1cvKg8f7Hoch6+NGjpPsH1Fr+Mc2D1aA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", "dev": true }, "import-fresh": { @@ -24487,9 +25336,9 @@ } }, "is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "requires": { "has": "^1.0.3" @@ -24601,6 +25450,12 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -24776,15 +25631,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "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, - "requires": { - "semver": "^7.5.3" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -24826,9 +25672,9 @@ } }, "jackspeak": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.2.tgz", - "integrity": "sha512-mgNtVv4vUuaKA97yxUHoA3+FkuhtxkjdXEWOyB/N76fjy0FjezEt34oy3epBtvCvS+7DyKwqCFWx/oJLV5+kCg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.0.tgz", + "integrity": "sha512-uKmsITSsF4rUWQHzqaRUuyAir3fZfW3f202Ee34lz/gZCi970CPZwyQXLGNgWJvvZbvFyzeyGq0+4fcG/mBKZg==", "dev": true, "requires": { "@isaacs/cliui": "^8.0.2", @@ -24933,9 +25779,9 @@ } }, "jiti": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", - "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==", + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.3.tgz", + "integrity": "sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==", "dev": true }, "jpeg-js": { @@ -24972,12 +25818,72 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "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", @@ -25209,6 +26115,15 @@ "colors": "1.4.0" } }, + "keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -25695,29 +26610,21 @@ "integrity": "sha512-Yg7/RDp4nedqmLgyH0LwgGRvMEKVzKbUdkBYyCosbHgJ+kaOUx0qzSiSatVc3DFygnirTPYnMM2P5dg2uH1WvA==" }, "magic-string": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", - "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", + "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", "dev": true, "requires": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "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, "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "semver": "^7.5.3" } }, "make-fetch-happen": { @@ -25743,6 +26650,23 @@ "ssri": "^10.0.0" }, "dependencies": { + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, "lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -25902,15 +26826,23 @@ } }, "minipass-fetch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz", - "integrity": "sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "dev": true, "requires": { "encoding": "^0.1.13", - "minipass": "^5.0.0", + "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true + } } }, "minipass-flush": { @@ -26662,9 +27594,9 @@ } }, "ngx-cookie-service": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-16.0.0.tgz", - "integrity": "sha512-bD0F8/I6Y7lfP1THeQDR70hv1SSEfFOjJqF1tnLphNBvR9EwkITO2KSOtfag7VH5CHT16PRIqv8XaGRDbCNAmA==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-16.0.1.tgz", + "integrity": "sha512-q8i5eX2b6SIIZcu9wy+lvOU65cLJhHD9EVz5TGGkKi8Y7X/aZbUyQ9U4CgNOfKDWtPUDFOMD8IW/cijoVKe59Q==", "requires": { "tslib": "^2.0.0" } @@ -26696,12 +27628,36 @@ "dev": true }, "node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, "requires": { "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } } }, "node-forge": { @@ -26741,9 +27697,9 @@ } }, "node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", "dev": true }, "node-releases": { @@ -26796,9 +27752,9 @@ } }, "npm-install-checks": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz", - "integrity": "sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.2.0.tgz", + "integrity": "sha512-744wat5wAAHsxa4590mWO0tJ8PKxR8ORZsH9wGpQc3nWTzozMAgBN/XyqYw7mg3yqLM8dLwEnwSfKMmXAjF69g==", "dev": true, "requires": { "semver": "^7.1.1" @@ -26888,6 +27844,12 @@ "boolbase": "^1.0.0" } }, + "nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, "nx": { "version": "16.5.1", "resolved": "https://registry.npmjs.org/nx/-/nx-16.5.1.tgz", @@ -27042,6 +28004,15 @@ "argparse": "^2.0.1" } }, + "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==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", @@ -27051,6 +28022,15 @@ "brace-expansion": "^1.1.7" } }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -27059,6 +28039,12 @@ "requires": { "has-flag": "^4.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, @@ -27090,6 +28076,12 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, + "object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "dev": true + }, "object.assign": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", @@ -27531,9 +28523,9 @@ }, "dependencies": { "lru-cache": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.0.tgz", - "integrity": "sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", "dev": true } } @@ -27581,9 +28573,9 @@ "dev": true }, "piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.0.0.tgz", + "integrity": "sha512-641nAmJS4k4iqpNUqfggqUBUMmlw0ZoM5VZKdQkV2e970Inn3Tk9kroCc1wpsYLD07vCwpys5iY0d3xI/9WkTg==", "dev": true, "requires": { "eventemitter-asyncresource": "^1.0.0", @@ -27593,18 +28585,69 @@ } }, "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, "requires": { - "find-up": "^4.0.0" + "find-up": "^6.3.0" + }, + "dependencies": { + "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, + "requires": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + } + }, + "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, + "requires": { + "p-locate": "^6.0.0" + } + }, + "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, + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "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, + "requires": { + "p-limit": "^4.0.0" + } + }, + "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 + }, + "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 + } } }, "postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", + "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", "dev": true, "requires": { "nanoid": "^3.3.6", @@ -27621,14 +28664,13 @@ } }, "postcss-loader": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.2.tgz", - "integrity": "sha512-c7qDlXErX6n0VT+LUsW+nwefVtTu3ORtVvK8EXuUIDcxo+b/euYqpuHlJAvePb0Af5e8uMjR/13e0lTuYifaig==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", "dev": true, "requires": { - "cosmiconfig": "^8.1.3", + "cosmiconfig": "^8.2.0", "jiti": "^1.18.2", - "klona": "^2.0.6", "semver": "^7.3.8" } }, @@ -27720,6 +28762,12 @@ "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", "dev": true }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -28169,9 +29217,9 @@ "dev": true }, "regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, "requires": { "@babel/runtime": "^7.8.4" @@ -28350,9 +29398,9 @@ "dev": true }, "rollup": { - "version": "3.27.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.27.2.tgz", - "integrity": "sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==", + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz", + "integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -28394,9 +29442,9 @@ "dev": true }, "sass": { - "version": "1.63.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.2.tgz", - "integrity": "sha512-u56TU0AIFqMtauKl/OJ1AeFsXqRHkgO7nCWmHaDwfxDo9GUMSqBA4NEh6GMuh1CYVM7zuROYtZrHzPc2ixK+ww==", + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.1.tgz", + "integrity": "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -28405,12 +29453,11 @@ } }, "sass-loader": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.1.tgz", - "integrity": "sha512-cBTxmgyVA1nXPvIK4brjJMXOMJ2v2YrQEuHqLw3LylGb3gsR6jAvdjHMcy/+JGTmmIF9SauTrLLR7bsWDMWqgg==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "dev": true, "requires": { - "klona": "^2.0.6", "neo-async": "^2.6.2" } }, @@ -28421,6 +29468,15 @@ "dev": true, "optional": true }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -28449,9 +29505,9 @@ } }, "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -28675,13 +29731,14 @@ "dev": true }, "sigstore": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.8.0.tgz", - "integrity": "sha512-ogU8qtQ3VFBawRJ8wjsBEX/vIFeHuGs1fm4jZtjWQwjo8pfAt7T/rh+udlAN4+QUe0IzA8qRSc/YZ7dHP6kh+w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", + "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", "dev": true, "requires": { - "@sigstore/bundle": "^1.0.0", + "@sigstore/bundle": "^1.1.0", "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", "@sigstore/tuf": "^1.0.3", "make-fetch-happen": "^11.0.1" } @@ -28998,12 +30055,20 @@ } }, "ssri": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz", - "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", "dev": true, "requires": { - "minipass": "^5.0.0" + "minipass": "^7.0.3" + }, + "dependencies": { + "minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true + } } }, "statuses": { @@ -29061,9 +30126,9 @@ } }, "streamx": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.0.tgz", - "integrity": "sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz", + "integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==", "dev": true, "requires": { "fast-fifo": "^1.1.0", @@ -29169,6 +30234,12 @@ "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -29276,9 +30347,9 @@ } }, "terser": { - "version": "5.17.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.7.tgz", - "integrity": "sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.3", @@ -29364,9 +30435,9 @@ "dev": true }, "third-party-web": { - "version": "0.23.3", - "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.23.3.tgz", - "integrity": "sha512-ifZcy79XYPmt9kQSTaHVh3IaL3Pms60iumsBrBBm6PPrtlNGdj56wznKl1LgSw8KpMWOwqOrlI/WCasQjflIZA==", + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.23.4.tgz", + "integrity": "sha512-kwYnSZRhEvv0SBW2fp8SBBKRglMoBjV8xz6C31m0ewqOtknB5UL+Ihg+M81hyFY5ldkZuGWPb+e4GVDkzf/gYg==", "dev": true }, "throttleit": { @@ -29438,10 +30509,13 @@ } }, "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } }, "tree-kill": { "version": "1.2.2", @@ -29467,9 +30541,9 @@ } }, "tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "tsutils": { "version": "3.21.0", @@ -29760,6 +30834,24 @@ "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, "watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -29789,15 +30881,15 @@ } }, "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true }, "webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -29809,7 +30901,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -29819,7 +30911,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -29894,9 +30986,9 @@ } }, "webpack-dev-server": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz", - "integrity": "sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ==", + "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, "requires": { "@types/bonjour": "^3.5.9", @@ -29905,7 +30997,7 @@ "@types/serve-index": "^1.9.1", "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/ws": "^8.5.5", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", @@ -29931,6 +31023,15 @@ "ws": "^8.13.0" }, "dependencies": { + "@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "webpack-dev-middleware": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", @@ -29995,14 +31096,30 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" } }, "which": { @@ -30185,6 +31302,18 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/front-end/package.json b/front-end/package.json index b8df021653..22f0ec6a48 100644 --- a/front-end/package.json +++ b/front-end/package.json @@ -38,7 +38,7 @@ "@types/ws": "8.5.4", "bootstrap": "5.1.3", "class-transformer": "^0.5.1", - "fecfile-validate": "https://github.com/fecgov/fecfile-validate#d313a8bf821a2bc0957b16a7c899544de898281e", + "fecfile-validate": "https://github.com/fecgov/fecfile-validate#f801280c3ab220c452e98eafae196245cf165416", "intl-tel-input": "^17.0.18", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", @@ -48,7 +48,7 @@ "ngx-logger": "^5.0.7", "primeflex": "^3.1.3", "primeicons": "^6.0.1", - "primeng": "^16.0.2", + "primeng": "16.1.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.5.4", "tslib": "^2.3.1", diff --git a/front-end/src/app/app.module.ts b/front-end/src/app/app.module.ts index 32b4d6c162..20811bb4bf 100644 --- a/front-end/src/app/app.module.ts +++ b/front-end/src/app/app.module.ts @@ -4,6 +4,7 @@ import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { RouteReuseStrategy } from '@angular/router'; // NGRX import { EffectsModule } from '@ngrx/effects'; @@ -46,6 +47,7 @@ import { LoginComponent } from './login/login/login.component'; import { HttpErrorInterceptor } from './shared/interceptors/http-error.interceptor'; import { FecDatePipe } from './shared/pipes/fec-date.pipe'; import { SharedModule } from './shared/shared.module'; +import { CustomRouteReuseStrategy } from './custom-route-reuse-strategy'; // Save ngrx store to localStorage dynamically function localStorageSyncReducer(reducer: ActionReducer): ActionReducer { @@ -103,7 +105,8 @@ const metaReducers: Array> = [localStorageSyncRedu MessageService, { provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true }, FecDatePipe, + { provide: RouteReuseStrategy, useClass: CustomRouteReuseStrategy }, ], bootstrap: [AppComponent], }) -export class AppModule { } +export class AppModule {} diff --git a/front-end/src/app/contacts/contact-detail/contact-detail.component.ts b/front-end/src/app/contacts/contact-detail/contact-detail.component.ts index d7939fe751..34e4867764 100644 --- a/front-end/src/app/contacts/contact-detail/contact-detail.component.ts +++ b/front-end/src/app/contacts/contact-detail/contact-detail.component.ts @@ -7,8 +7,8 @@ import { schema as contactCommitteeSchema } from 'fecfile-validate/fecfile_valid import { schema as contactIndividualSchema } from 'fecfile-validate/fecfile_validate_js/dist/Contact_Individual'; import { schema as contactOrganizationSchema } from 'fecfile-validate/fecfile_validate_js/dist/Contact_Organization'; import { MessageService } from 'primeng/api'; -import { Contact, ContactType } from '../../shared/models/contact.model'; import { TableLazyLoadEvent } from 'primeng/table'; +import { Contact, ContactType } from '../../shared/models/contact.model'; @Component({ selector: 'app-contact-detail', @@ -56,6 +56,8 @@ export class ContactDetailComponent { public onOpenDetail() { this.resetForm(); this.form.patchValue(this.contact); + this.form?.get('candidate_id')?.addAsyncValidators(this.contactService.getFecIdValidator(this.contact.id)); + this.form?.get('committee_id')?.addAsyncValidators(this.contactService.getFecIdValidator(this.contact.id)); } public saveItem(closeDetail = true) { diff --git a/front-end/src/app/custom-route-reuse-strategy.ts b/front-end/src/app/custom-route-reuse-strategy.ts new file mode 100644 index 0000000000..00494a5697 --- /dev/null +++ b/front-end/src/app/custom-route-reuse-strategy.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, BaseRouteReuseStrategy } from '@angular/router'; + +/** + * Code adapted from: https://blog.nativescript.org/how-to-extend-custom-router-reuse-strategy/ + */ + +@Injectable() +export class CustomRouteReuseStrategy extends BaseRouteReuseStrategy { + override shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean { + // First use the global Reuse Strategy evaluation function, + // which will return true, when we are navigating from the same component to itself + let shouldReuse = super.shouldReuseRoute(future, current); + + if (shouldReuse && current.data['noComponentReuse']) { + shouldReuse = false; + } + + return shouldReuse; + } +} diff --git a/front-end/src/app/layout/layout.component.spec.ts b/front-end/src/app/layout/layout.component.spec.ts index c8cbe62b07..1031b30b26 100644 --- a/front-end/src/app/layout/layout.component.spec.ts +++ b/front-end/src/app/layout/layout.component.spec.ts @@ -13,6 +13,7 @@ import { BannerComponent } from './banner/banner.component'; import { filter } from 'rxjs'; import { Store } from '@ngrx/store'; import { setSidebarStateAction } from 'app/store/sidebar-state.actions'; +import { CommitteeBannerComponent } from './committee-banner/committee-banner.component'; describe('LayoutComponent', () => { let component: LayoutComponent; @@ -29,6 +30,7 @@ describe('LayoutComponent', () => { BannerComponent, MenuReportComponent, FooterComponent, + CommitteeBannerComponent, ], providers: [LayoutComponent, provideMockStore(testMockStore)], }).compileComponents(); diff --git a/front-end/src/app/layout/sidebar/menu-report/menu-report.component.scss b/front-end/src/app/layout/sidebar/menu-report/menu-report.component.scss index ca6c5c1deb..bbfb4f8ab5 100644 --- a/front-end/src/app/layout/sidebar/menu-report/menu-report.component.scss +++ b/front-end/src/app/layout/sidebar/menu-report/menu-report.component.scss @@ -14,3 +14,21 @@ .sub-heading { font-size: 0.8em; } + +::ng-deep .p-panelmenu-header-action { + height: 48px; + font-weight: bold; + padding-left: 6px; +} + +::ng-deep .p-panelmenu-root-list { + padding-left: 0px !important; +} + +::ng-deep p-panelmenu > div > div > div > div > a > chevrondownicon > .p-submenu-icon { + visibility: hidden; +} + +::ng-deep p-panelmenu > div > div > div > div > a > chevronrighticon > .p-submenu-icon { + visibility: hidden; +} \ No newline at end of file diff --git a/front-end/src/app/reports/transactions/double-transaction-detail/double-transaction-detail.component.html b/front-end/src/app/reports/transactions/double-transaction-detail/double-transaction-detail.component.html index 2675af8867..e2090d987b 100644 --- a/front-end/src/app/reports/transactions/double-transaction-detail/double-transaction-detail.component.html +++ b/front-end/src/app/reports/transactions/double-transaction-detail/double-transaction-detail.component.html @@ -16,152 +16,18 @@

{{ transactionType?.contactTitle }}

-
-
- - - -
-
- - - - - - - - -

Address

- - - -

Employer

- - -
- -

{{ transactionType?.amountInputHeader }}

- - -
- -

{{ transactionType?.amountInputHeader }}

- - -
- -

Terms

- - -
- -

Committee/Candidate Information

- - - - - - -
- -

Election information

- - -
-

Additional information

- - - - -
-
- -
-
-
- -
-
-

{{ transactionType?.footer }}

-
-
+ +
@@ -180,151 +46,31 @@

{{ childTransaction?.transactionType?.title }}

{{ childTransactionType?.contactTitle }}

-
-
-
- - - -
-
-
- - - - - - - - -

Address

- - - -

Employer

- - -
- -

Committee/Candidate Information

- - - - - - -
- -

Election information

- - -
- -

{{ childTransaction?.transactionType?.amountInputHeader }}

- - -
- -

{{ childTransaction?.transactionType?.amountInputHeader }}

- - -
-

Additional information

- -
+ +
-
- -
+ diff --git a/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.html b/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.html index 891dddac61..449e4bd5ab 100644 --- a/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.html +++ b/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.html @@ -1,6 +1,9 @@ - + + + + - - - + + + diff --git a/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.spec.ts b/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.spec.ts index 858d5adbae..968db9fd5d 100644 --- a/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.spec.ts +++ b/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.spec.ts @@ -21,6 +21,7 @@ import { of } from 'rxjs'; import { SharedModule } from 'app/shared/shared.module'; import { TransactionContainerComponent } from './transaction-container.component'; import { ConfirmDialog, ConfirmDialogModule } from 'primeng/confirmdialog'; +import { TransactionDetailComponent } from '../transaction-detail/transaction-detail.component'; describe('TransactionContainerComponent', () => { let component: TransactionContainerComponent; @@ -45,7 +46,7 @@ describe('TransactionContainerComponent', () => { InputTextareaModule, ConfirmDialogModule, ], - declarations: [TransactionContainerComponent, ConfirmDialog], + declarations: [TransactionContainerComponent, ConfirmDialog, TransactionDetailComponent], providers: [ FormBuilder, MessageService, diff --git a/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.ts b/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.ts index 133d67af40..d770f2dce9 100644 --- a/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.ts +++ b/front-end/src/app/reports/transactions/transaction-container/transaction-container.component.ts @@ -20,11 +20,21 @@ export class TransactionContainerComponent extends DestroyerComponent { if (this.transaction) { const title: string = this.transaction.transactionType?.title ?? ''; this.titleService.setTitle(title); + } else { + throw new Error('Fecfile: No transaction found in TransactionContainerComponent'); } }); } - isDoubleTransaction() { - return !!this.transaction?.transactionType?.dependentChildTransactionType; + isSingleTransaction(): boolean { + return !this.transaction?.transactionType?.dependentChildTransactionTypes?.length; + } + + isDoubleTransaction(): boolean { + return this.transaction?.transactionType?.dependentChildTransactionTypes?.length === 1; + } + + isTripleTransaction(): boolean { + return this.transaction?.transactionType?.dependentChildTransactionTypes?.length === 2; } } diff --git a/front-end/src/app/reports/transactions/transaction-detail/transaction-detail.component.html b/front-end/src/app/reports/transactions/transaction-detail/transaction-detail.component.html index ff58db45de..cbcd1cedfb 100644 --- a/front-end/src/app/reports/transactions/transaction-detail/transaction-detail.component.html +++ b/front-end/src/app/reports/transactions/transaction-detail/transaction-detail.component.html @@ -5,157 +5,25 @@

{{ transaction?.transactionType?.title }}

READ ONLY

Contact

-
-
-
- - - -
-
-
- - - - - - - - -

Address

- - - -

Employer

- - -
- -

{{ transaction?.transactionType?.amountInputHeader }}

- - -
- -

Loan information

- - -
- -

Terms

- - -
- -

Committee/Candidate Information

- - - - - - -
- -

Election information

- - -
-

Additional information

- -
- -
- -
-
-
-
+ +
- -
- -
+ diff --git a/front-end/src/app/reports/transactions/transaction-detail/transaction-detail.component.spec.ts b/front-end/src/app/reports/transactions/transaction-detail/transaction-detail.component.spec.ts index e3592d33fb..c7ccb0ab54 100644 --- a/front-end/src/app/reports/transactions/transaction-detail/transaction-detail.component.spec.ts +++ b/front-end/src/app/reports/transactions/transaction-detail/transaction-detail.component.spec.ts @@ -27,6 +27,8 @@ import { InputTextareaModule } from 'primeng/inputtextarea'; import { ToastModule } from 'primeng/toast'; import { SharedModule } from 'app/shared/shared.module'; import { TransactionDetailComponent } from './transaction-detail.component'; +import { AmountInputComponent } from 'app/shared/components/inputs/amount-input/amount-input.component'; +import { NavigationControlComponent } from 'app/shared/components/navigation-control/navigation-control.component'; describe('TransactionDetailComponent', () => { let httpTestingController: HttpTestingController; @@ -54,7 +56,7 @@ describe('TransactionDetailComponent', () => { InputNumberModule, ConfirmDialogModule, ], - declarations: [TransactionDetailComponent], + declarations: [TransactionDetailComponent, AmountInputComponent, NavigationControlComponent], providers: [ MessageService, ConfirmationService, @@ -82,9 +84,9 @@ describe('TransactionDetailComponent', () => { expect(component.form.get('entity_type')?.value).toEqual(ContactTypes.ORGANIZATION); }); - it('#save() should not save an invalid record', () => { + it('#handleNavigate() should not save an invalid record', () => { component.form.patchValue({ ...transaction, ...{ contributor_state: 'not-valid' } }); - component.save(new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, transaction)); + component.handleNavigate(new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, transaction)); expect(component.form.invalid).toBe(true); httpTestingController.expectNone( `${environment.apiUrl}/transactions/schedule-a/1/?schema=TRIBAL_RECEIPT&fields_to_validate=` diff --git a/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.html b/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.html new file mode 100644 index 0000000000..7f66be2d7b --- /dev/null +++ b/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.html @@ -0,0 +1,167 @@ +
+
+
+ + + +
+
+
+ + + + + + + + +

Address

+ + + +

Employer

+ +
+ + + + + +

{{ transaction?.transactionType?.amountInputHeader }}

+ +
+ + +

{{ transactionType.amountInputHeader }}

+ +
+ + +

Terms

+ +
+ + +

Loan information

+ +
+ + +

{{ transactionType.signatoryOneTitle }}

+ +
+ + +

{{ transactionType.signatoryTwoTitle }}

+ +
+ + + + + +

Additional information

+ +
+ + +
+ + {{ transactionType.footer }} + +
+
+
+ + + + +

Committee/Candidate Information

+ + + + + +
+ + +

Election information

+ +
+
diff --git a/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.spec.ts b/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.spec.ts new file mode 100644 index 0000000000..4b8626934b --- /dev/null +++ b/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TransactionInputComponent } from './transaction-input.component'; + +describe('TransactionInputComponent', () => { + let component: TransactionInputComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TransactionInputComponent], + }); + fixture = TestBed.createComponent(TransactionInputComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + xit('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.ts b/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.ts new file mode 100644 index 0000000000..8f68111ae4 --- /dev/null +++ b/front-end/src/app/reports/transactions/transaction-input/transaction-input.component.ts @@ -0,0 +1,57 @@ +import { Component, Input, Output, OnInit, EventEmitter } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { SelectItem } from 'primeng/api'; +import { TransactionTemplateMapType, TransactionType } from 'app/shared/models/transaction-type.model'; +import { Contact, ContactTypes, ContactTypeLabels } from 'app/shared/models/contact.model'; +import { Transaction } from 'app/shared/models/transaction.model'; +import { Observable } from 'rxjs'; +import { LabelUtils, PrimeOptions } from 'app/shared/utils/label.utils'; + +@Component({ + selector: 'app-transaction-input', + templateUrl: './transaction-input.component.html', +}) +export class TransactionInputComponent implements OnInit { + @Input() form: FormGroup = new FormGroup([]); + @Input() formSubmitted = false; + @Input() isEditable = true; + @Input() transaction?: Transaction; + @Input() contactTypeOptions: PrimeOptions = LabelUtils.getPrimeOptions(ContactTypeLabels); + @Input() candidateContactTypeOptions: PrimeOptions = LabelUtils.getPrimeOptions(ContactTypeLabels, [ + ContactTypes.CANDIDATE, + ]); + @Input() candidateContactTypeFormControl: FormControl = new FormControl(ContactTypes.CANDIDATE); + @Input() memoCodeCheckboxLabel$?: Observable; + @Input() contributionAmountReadOnly = false; + @Input() contactLookupLabel = 'CONTACT LOOKUP'; + @Input() candidateInfoPosition = 'low'; + + @Output() primaryContactSelect = new EventEmitter>(); + @Output() candidateContactSelect = new EventEmitter>(); + @Output() secondaryContactSelect = new EventEmitter>(); + + ContactTypes = ContactTypes; + transactionType: TransactionType = {} as TransactionType; + templateMap: TransactionTemplateMapType = {} as TransactionTemplateMapType; + + ngOnInit(): void { + if (this.transaction) { + this.transactionType = this.transaction.transactionType; + this.templateMap = this.transaction.transactionType.templateMap; + } else { + throw new Error('FECfile: No transaction passed to TransactionInputComponent'); + } + } + + updateFormWithPrimaryContact(selectItem: SelectItem) { + this.primaryContactSelect.emit(selectItem); + } + + updateFormWithCandidateContact(selectItem: SelectItem) { + this.candidateContactSelect.emit(selectItem); + } + + updateFormWithSecondaryContact(selectItem: SelectItem) { + this.secondaryContactSelect.emit(selectItem); + } +} diff --git a/front-end/src/app/reports/transactions/transaction-list/transaction-disbursements/transaction-disbursements.component.spec.ts b/front-end/src/app/reports/transactions/transaction-list/transaction-disbursements/transaction-disbursements.component.spec.ts index 6bb8e7c71e..b7600bae6f 100644 --- a/front-end/src/app/reports/transactions/transaction-list/transaction-disbursements/transaction-disbursements.component.spec.ts +++ b/front-end/src/app/reports/transactions/transaction-list/transaction-disbursements/transaction-disbursements.component.spec.ts @@ -1,4 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { provideMockStore } from '@ngrx/store/testing'; import { testMockStore } from 'app/shared/utils/unit-test.utils'; @@ -9,6 +10,7 @@ import { TableModule } from 'primeng/table'; import { SharedModule } from 'app/shared/shared.module'; import { TransactionDisbursementsComponent } from './transaction-disbursements.component'; import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { DropdownModule } from 'primeng/dropdown'; describe('TransactionDisbursementsComponent', () => { let fixture: ComponentFixture; @@ -16,7 +18,7 @@ describe('TransactionDisbursementsComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ToolbarModule, TableModule, SharedModule, HttpClientTestingModule], + imports: [ToolbarModule, TableModule, SharedModule, HttpClientTestingModule, FormsModule, DropdownModule], declarations: [TransactionDisbursementsComponent], providers: [ MessageService, diff --git a/front-end/src/app/reports/transactions/transaction-list/transaction-list.component.spec.ts b/front-end/src/app/reports/transactions/transaction-list/transaction-list.component.spec.ts index 923bc4c42b..1b608c198e 100644 --- a/front-end/src/app/reports/transactions/transaction-list/transaction-list.component.spec.ts +++ b/front-end/src/app/reports/transactions/transaction-list/transaction-list.component.spec.ts @@ -1,4 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { of } from 'rxjs'; import { RouterTestingModule } from '@angular/router/testing'; @@ -12,6 +13,8 @@ import { TableModule } from 'primeng/table'; import { SharedModule } from 'app/shared/shared.module'; import { MemoCodePipe, TransactionListComponent } from './transaction-list.component'; import { ToolbarModule } from 'primeng/toolbar'; +import { ConfirmDialogModule } from 'primeng/confirmdialog'; +import { TransactionLoansAndDebtsComponent } from './transaction-loans-and-debts/transaction-loans-and-debts.component'; describe('TransactionListComponent', () => { let component: TransactionListComponent; @@ -20,8 +23,16 @@ describe('TransactionListComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ToolbarModule, TableModule, SharedModule, RouterTestingModule, RouterTestingModule.withRoutes([])], - declarations: [TransactionListComponent], + imports: [ + ToolbarModule, + TableModule, + SharedModule, + RouterTestingModule, + ConfirmDialogModule, + HttpClientTestingModule, + RouterTestingModule.withRoutes([]), + ], + declarations: [TransactionListComponent, TransactionLoansAndDebtsComponent], providers: [ MessageService, ConfirmationService, diff --git a/front-end/src/app/reports/transactions/transaction-list/transaction-loans-and-debts/transaction-loans-and-debts.component.spec.ts b/front-end/src/app/reports/transactions/transaction-list/transaction-loans-and-debts/transaction-loans-and-debts.component.spec.ts index d6cde7e136..2a89700c98 100644 --- a/front-end/src/app/reports/transactions/transaction-list/transaction-loans-and-debts/transaction-loans-and-debts.component.spec.ts +++ b/front-end/src/app/reports/transactions/transaction-list/transaction-loans-and-debts/transaction-loans-and-debts.component.spec.ts @@ -1,5 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; +import { FormsModule } from '@angular/forms'; import { of } from 'rxjs'; import { provideMockStore } from '@ngrx/store/testing'; import { testMockStore } from 'app/shared/utils/unit-test.utils'; @@ -13,6 +14,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { TransactionSchCService } from 'app/shared/services/transaction-schC.service'; import { Transaction } from 'app/shared/models/transaction.model'; import { SchC1Transaction } from 'app/shared/models/schc1-transaction.model'; +import { DropdownModule } from 'primeng/dropdown'; describe('TransactionReceiptsComponent', () => { let fixture: ComponentFixture; @@ -22,7 +24,7 @@ describe('TransactionReceiptsComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ToolbarModule, TableModule, SharedModule, HttpClientTestingModule], + imports: [ToolbarModule, TableModule, SharedModule, HttpClientTestingModule, DropdownModule, FormsModule], declarations: [TransactionLoansAndDebtsComponent], providers: [ MessageService, diff --git a/front-end/src/app/reports/transactions/transaction-list/transaction-receipts/transaction-receipts.component.spec.ts b/front-end/src/app/reports/transactions/transaction-list/transaction-receipts/transaction-receipts.component.spec.ts index 9f1a752c81..d94bcec231 100644 --- a/front-end/src/app/reports/transactions/transaction-list/transaction-receipts/transaction-receipts.component.spec.ts +++ b/front-end/src/app/reports/transactions/transaction-list/transaction-receipts/transaction-receipts.component.spec.ts @@ -1,5 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; +import { FormsModule } from '@angular/forms'; import { of } from 'rxjs'; import { provideMockStore } from '@ngrx/store/testing'; import { testMockStore } from 'app/shared/utils/unit-test.utils'; @@ -7,6 +8,7 @@ import { F3xSummary } from 'app/shared/models/f3x-summary.model'; import { ConfirmationService, MessageService } from 'primeng/api'; import { ToolbarModule } from 'primeng/toolbar'; import { TableModule } from 'primeng/table'; +import { DropdownModule } from 'primeng/dropdown'; import { SharedModule } from 'app/shared/shared.module'; import { TransactionReceiptsComponent } from './transaction-receipts.component'; import { HttpClientTestingModule } from '@angular/common/http/testing'; @@ -22,7 +24,7 @@ describe('TransactionReceiptsComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ToolbarModule, TableModule, SharedModule, HttpClientTestingModule], + imports: [ToolbarModule, TableModule, SharedModule, HttpClientTestingModule, DropdownModule, FormsModule], declarations: [TransactionReceiptsComponent], providers: [ MessageService, diff --git a/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.html b/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.html new file mode 100644 index 0000000000..10272797ae --- /dev/null +++ b/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.html @@ -0,0 +1,23 @@ + + +
+
+ +
+
+
+
+ +
+ + +
diff --git a/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.spec.ts b/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.spec.ts new file mode 100644 index 0000000000..e79912da2b --- /dev/null +++ b/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TransactionNavigationComponent } from './transaction-navigation.component'; + +describe('TransactionNavigationComponent', () => { + let component: TransactionNavigationComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TransactionNavigationComponent] + }); + fixture = TestBed.createComponent(TransactionNavigationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.ts b/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.ts new file mode 100644 index 0000000000..9a7aa8c05e --- /dev/null +++ b/front-end/src/app/reports/transactions/transaction-navigation/transaction-navigation.component.ts @@ -0,0 +1,31 @@ +import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { Transaction } from 'app/shared/models/transaction.model'; +import { + NavigationControl, + NavigationEvent, + TransactionNavigationControls, + GO_BACK_CONTROL, +} from 'app/shared/models/transaction-navigation-controls.model'; + +@Component({ + selector: 'app-transaction-navigation', + templateUrl: './transaction-navigation.component.html', +}) +export class TransactionNavigationComponent { + @Input() isEditable = true; + @Input() transaction?: Transaction; + @Output() navigate: EventEmitter = new EventEmitter(); + + handleNavigate($event: NavigationEvent) { + this.navigate.emit($event); + } + + getNavigationControls(): TransactionNavigationControls { + if (!this.isEditable) return new TransactionNavigationControls([], [GO_BACK_CONTROL], []); + return this.transaction?.transactionType?.navigationControls ?? new TransactionNavigationControls([], [], []); + } + + getInlineControls(): NavigationControl[] { + return this.getNavigationControls().getNavigationControls('inline', this.transaction); + } +} diff --git a/front-end/src/app/reports/transactions/transactions-routing.module.ts b/front-end/src/app/reports/transactions/transactions-routing.module.ts index b15788e2dc..0fa5646e70 100644 --- a/front-end/src/app/reports/transactions/transactions-routing.module.ts +++ b/front-end/src/app/reports/transactions/transactions-routing.module.ts @@ -66,6 +66,11 @@ const routes: Routes = [ sidebar: SidebarStateResolver, }, canActivate: [ReportIsEditableGuard], + // There is a scenario where a memo is saved and then navigates to create + // a sibling transaction of a different transaction type, the below setting ensures + // the transaction form components are destroyed and recreated so initialization + // of the new transaction form happens correctly. + data: { noComponentReuse: true }, // Handled in src/app/custom-route-reuse-strategy.ts }, { path: '**', redirectTo: '' }, ]; diff --git a/front-end/src/app/reports/transactions/transactions.module.ts b/front-end/src/app/reports/transactions/transactions.module.ts index 8e62394691..0a29fb9346 100644 --- a/front-end/src/app/reports/transactions/transactions.module.ts +++ b/front-end/src/app/reports/transactions/transactions.module.ts @@ -19,6 +19,7 @@ import { ToolbarModule } from 'primeng/toolbar'; import { ConfirmDialogModule } from 'primeng/confirmdialog'; import { SharedModule } from 'app/shared/shared.module'; import { DoubleTransactionDetailComponent } from './double-transaction-detail/double-transaction-detail.component'; +import { TripleTransactionDetailComponent } from './triple-transaction-detail/triple-transaction-detail.component'; import { TransactionContainerComponent } from './transaction-container/transaction-container.component'; import { TransactionDetailComponent } from './transaction-detail/transaction-detail.component'; import { TransactionDisbursementsComponent } from './transaction-list/transaction-disbursements/transaction-disbursements.component'; @@ -27,6 +28,8 @@ import { TransactionReceiptsComponent } from './transaction-list/transaction-rec import { TransactionLoansAndDebtsComponent } from './transaction-list/transaction-loans-and-debts/transaction-loans-and-debts.component'; import { TransactionTypePickerComponent } from './transaction-type-picker/transaction-type-picker.component'; import { TransactionsRoutingModule } from './transactions-routing.module'; +import { TransactionInputComponent } from './transaction-input/transaction-input.component'; +import { TransactionNavigationComponent } from './transaction-navigation/transaction-navigation.component'; @NgModule({ declarations: [ @@ -34,11 +37,14 @@ import { TransactionsRoutingModule } from './transactions-routing.module'; TransactionTypePickerComponent, TransactionListComponent, DoubleTransactionDetailComponent, + TripleTransactionDetailComponent, TransactionDetailComponent, MemoCodePipe, TransactionReceiptsComponent, TransactionDisbursementsComponent, TransactionLoansAndDebtsComponent, + TransactionInputComponent, + TransactionNavigationComponent, ], imports: [ AccordionModule, diff --git a/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.html b/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.html new file mode 100644 index 0000000000..a1da94f064 --- /dev/null +++ b/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.html @@ -0,0 +1,110 @@ + +

{{ transaction?.transactionType?.title }}

+

READ ONLY

+

{{ transactionType?.description }}

+ + + + {{ transactionType?.accordionTitle }}: +

+ {{ transactionType?.accordionSubText }} +

+
+

+ {{ transactionType?.formTitle }} +

+

{{ transactionType?.contactTitle }}

+
+ + +
+
+
+ + + + {{ childTransactionType?.accordionTitle }}: +

+ {{ childTransactionType?.accordionSubText }} +

+
+

{{ childTransaction?.transactionType?.title }}

+

+ +

+

{{ childTransactionType?.contactTitle }}

+
+ + +
+
+
+ + + + {{ childTransactionType_2?.accordionTitle }}: +

+ {{ childTransactionType_2?.accordionSubText }} +

+
+

{{ childTransaction_2?.transactionType?.title }}

+

+ +

+

{{ childTransactionType_2?.contactTitle }}

+
+ + +
+
+
+
+ + + + + + diff --git a/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.scss b/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.scss new file mode 100644 index 0000000000..8f7c285ce9 --- /dev/null +++ b/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.scss @@ -0,0 +1,13 @@ +p { + line-height: normal; + margin: 0; +} + +strong { + white-space: nowrap; + margin-right: 10px; +} + +.group-description { + margin: 20px 0; +} diff --git a/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.spec.ts b/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.spec.ts new file mode 100644 index 0000000000..2cfc74cd14 --- /dev/null +++ b/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.spec.ts @@ -0,0 +1,70 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterTestingModule } from '@angular/router/testing'; +import { provideMockStore } from '@ngrx/store/testing'; +import { ScheduleATransactionTypes } from 'app/shared/models/scha-transaction.model'; +import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; +import { getTestTransactionByType, testMockStore, testTemplateMap } from 'app/shared/utils/unit-test.utils'; +import { ConfirmationService, MessageService } from 'primeng/api'; +import { ButtonModule } from 'primeng/button'; +import { CalendarModule } from 'primeng/calendar'; +import { CheckboxModule } from 'primeng/checkbox'; +import { ConfirmDialogModule } from 'primeng/confirmdialog'; +import { DividerModule } from 'primeng/divider'; +import { DropdownModule } from 'primeng/dropdown'; +import { InputNumberModule } from 'primeng/inputnumber'; +import { InputTextModule } from 'primeng/inputtext'; +import { InputTextareaModule } from 'primeng/inputtextarea'; +import { ToastModule } from 'primeng/toast'; +import { SharedModule } from '../../../shared/shared.module'; +import { TripleTransactionDetailComponent } from './triple-transaction-detail.component'; +import { ScheduleCTransactionTypes } from 'app/shared/models/schc-transaction.model'; +import { ScheduleC1TransactionTypes } from 'app/shared/models/schc1-transaction.model'; + +describe('TripleTransactionDetailComponent', () => { + let component: TripleTransactionDetailComponent; + let fixture: ComponentFixture; + + const transaction = getTestTransactionByType(ScheduleCTransactionTypes.LOAN_RECEIVED_FROM_BANK); + transaction.children = [ + getTestTransactionByType(ScheduleC1TransactionTypes.C1_LOAN_AGREEMENT), + getTestTransactionByType(ScheduleATransactionTypes.LOAN_RECEIVED_FROM_BANK_RECEIPT), + ]; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + RouterTestingModule, + FormsModule, + ReactiveFormsModule, + ToastModule, + SharedModule, + DividerModule, + DropdownModule, + CalendarModule, + ButtonModule, + CheckboxModule, + InputTextModule, + InputTextareaModule, + InputNumberModule, + ConfirmDialogModule, + ], + declarations: [TripleTransactionDetailComponent], + providers: [MessageService, ConfirmationService, FormBuilder, provideMockStore(testMockStore), FecDatePipe], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TripleTransactionDetailComponent); + component = fixture.componentInstance; + component.transaction = transaction; + component.templateMap = testTemplateMap; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.ts b/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.ts new file mode 100644 index 0000000000..25a6fa4080 --- /dev/null +++ b/front-end/src/app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component.ts @@ -0,0 +1,57 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { FormBuilder } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { ConfirmationService, MessageService } from 'primeng/api'; +import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; +import { ContactService } from 'app/shared/services/contact.service'; +import { ReportService } from 'app/shared/services/report.service'; +import { TransactionService } from 'app/shared/services/transaction.service'; +import { TripleTransactionTypeBaseComponent } from 'app/shared/components/transaction-type-base/triple-transaction-type-base.component'; + +@Component({ + selector: 'app-triple-transaction-detail', + templateUrl: './triple-transaction-detail.component.html', + styleUrls: ['../transaction.scss', './triple-transaction-detail.component.scss'], +}) +export class TripleTransactionDetailComponent extends TripleTransactionTypeBaseComponent implements OnInit { + accordionActiveIndex = 0; // Value determines which accordion pane to open by default + + constructor( + protected override messageService: MessageService, + public override transactionService: TransactionService, + protected override contactService: ContactService, + protected override confirmationService: ConfirmationService, + protected override fb: FormBuilder, + protected override router: Router, + protected override fecDatePipe: FecDatePipe, + protected override store: Store, + protected override reportService: ReportService, + private route: ActivatedRoute + ) { + super( + messageService, + transactionService, + contactService, + confirmationService, + fb, + router, + fecDatePipe, + store, + reportService + ); + } + + override ngOnInit(): void { + super.ngOnInit(); + + // Determine which accordion pane to open initially based on transaction id in page URL + const transactionId = this.route.snapshot.params['transactionId']; + if (this.childTransaction && transactionId && this.childTransaction?.id === transactionId) { + this.accordionActiveIndex = 1; + } + if (this.childTransaction_2 && transactionId && this.childTransaction_2?.id === transactionId) { + this.accordionActiveIndex = 2; + } + } +} diff --git a/front-end/src/app/shared/components/calculation-overlay/calculation-overlay.component.spec.ts b/front-end/src/app/shared/components/calculation-overlay/calculation-overlay.component.spec.ts index 7f957b1471..8cb0c7b11d 100644 --- a/front-end/src/app/shared/components/calculation-overlay/calculation-overlay.component.spec.ts +++ b/front-end/src/app/shared/components/calculation-overlay/calculation-overlay.component.spec.ts @@ -1,5 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; - +import { OverlayModule } from 'primeng/overlay'; import { CalculationOverlayComponent } from './calculation-overlay.component'; describe('CalculationOverlayComponent', () => { @@ -8,9 +8,9 @@ describe('CalculationOverlayComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ CalculationOverlayComponent ] - }) - .compileComponents(); + imports: [OverlayModule], + declarations: [CalculationOverlayComponent], + }).compileComponents(); fixture = TestBed.createComponent(CalculationOverlayComponent); component = fixture.componentInstance; diff --git a/front-end/src/app/shared/components/contact-form/contact-form.component.html b/front-end/src/app/shared/components/contact-form/contact-form.component.html index 50edd357a4..1a1ec2b9be 100644 --- a/front-end/src/app/shared/components/contact-form/contact-form.component.html +++ b/front-end/src/app/shared/components/contact-form/contact-form.component.html @@ -19,7 +19,7 @@

Contact

" [showCreateNewContactButton]="false" [includeFecfileResults]="false" - (contactLookupSelect)="onContactLookupSelect($event)" + (contactLookupSelect)="updateFormWithPrimaryContact($event)" > diff --git a/front-end/src/app/shared/components/contact-form/contact-form.component.spec.ts b/front-end/src/app/shared/components/contact-form/contact-form.component.spec.ts index e06a122cb5..2ccd64a654 100644 --- a/front-end/src/app/shared/components/contact-form/contact-form.component.spec.ts +++ b/front-end/src/app/shared/components/contact-form/contact-form.component.spec.ts @@ -102,7 +102,7 @@ describe('ContactFormComponent', () => { expect(component.form.get('state')?.value).toBe('ZZ'); }); - it('#onContactLookupSelect CANDIDATE Contact happy path', () => { + it('#updateFormWithPrimaryContact CANDIDATE Contact happy path', () => { const testContact = new Contact(); const testLastName = 'testLastName'; const testZip = '12345'; @@ -110,16 +110,16 @@ describe('ContactFormComponent', () => { testContact.last_name = testLastName; testContact.zip = testZip; - component.onContactLookupSelect({ value: testContact }); + component.updateFormWithPrimaryContact({ value: testContact }); expect(component.form.get('last_name')?.value).toBe(testLastName); expect(component.form.get('zip')?.value).toBe(testZip); component.form = new FormGroup({}); - component.onContactLookupSelect({ value: testContact }); + component.updateFormWithPrimaryContact({ value: testContact }); }); - it('#onContactLookupSelect COMMITTEE Contact happy path', () => { + it('#updateFormWithPrimaryContact COMMITTEE Contact happy path', () => { const testContact = new Contact(); const testCommitteeId = 'C1234568'; const testZip = '12345'; @@ -127,16 +127,16 @@ describe('ContactFormComponent', () => { testContact.committee_id = testCommitteeId; testContact.zip = testZip; - component.onContactLookupSelect({ value: testContact }); + component.updateFormWithPrimaryContact({ value: testContact }); expect(component.form.get('committee_id')?.value).toBe(testCommitteeId); expect(component.form.get('zip')?.value).toBe(testZip); component.form = new FormGroup({}); - component.onContactLookupSelect({ value: testContact }); + component.updateFormWithPrimaryContact({ value: testContact }); }); - it('#onContactLookupSelect FecApiCandidateLookupData happy path', () => { + it('#updateFormWithPrimaryContact FecApiCandidateLookupData happy path', () => { const testId = 'P12345678'; const testOfficeSought = 'P'; const testName = 'testName'; @@ -152,17 +152,17 @@ describe('ContactFormComponent', () => { spyOn(testFecApiService, 'getCandidateDetails').and.returnValue(of(testResponse)); - component.onContactLookupSelect({ value: testFecApiCandidateLookupData }); + component.updateFormWithPrimaryContact({ value: testFecApiCandidateLookupData }); expect(component.form.get('type')?.value).toBe(ContactTypes.CANDIDATE); expect(component.form.get('candidate_id')?.value).toBe(testId); expect(component.form.get('city')?.value).toBe(testAddressCity); component.form = new FormGroup({}); - component.onContactLookupSelect({ value: testFecApiCandidateLookupData }); + component.updateFormWithPrimaryContact({ value: testFecApiCandidateLookupData }); }); - it('#onContactLookupSelect FecApiCommitteeLookupData happy path', () => { + it('#updateFormWithPrimaryContact FecApiCommitteeLookupData happy path', () => { const testId = 'C12345678'; const testIsActive = true; const testName = 'testName'; @@ -178,13 +178,13 @@ describe('ContactFormComponent', () => { spyOn(testFecApiService, 'getCommitteeDetails').and.returnValue(of(testResponse)); - component.onContactLookupSelect({ value: testFecApiCommitteeLookupData }); + component.updateFormWithPrimaryContact({ value: testFecApiCommitteeLookupData }); expect(component.form.get('type')?.value).toBe(ContactTypes.COMMITTEE); expect(component.form.get('committee_id')?.value).toBe(testId); expect(component.form.get('telephone')?.value).toBe('+1 ' + testPhone); component.form = new FormGroup({}); - component.onContactLookupSelect({ value: testFecApiCommitteeLookupData }); + component.updateFormWithPrimaryContact({ value: testFecApiCommitteeLookupData }); }); }); diff --git a/front-end/src/app/shared/components/contact-form/contact-form.component.ts b/front-end/src/app/shared/components/contact-form/contact-form.component.ts index 879fd7abfa..7f6ef14b05 100644 --- a/front-end/src/app/shared/components/contact-form/contact-form.component.ts +++ b/front-end/src/app/shared/components/contact-form/contact-form.component.ts @@ -108,8 +108,6 @@ export class ContactFormComponent extends DestroyerComponent implements OnInit { this.candidateDistrictOptions = []; } }); - this.form?.get('candidate_id')?.addAsyncValidators(this.contactService.fecIdValidator); - this.form?.get('committee_id')?.addAsyncValidators(this.contactService.fecIdValidator); } /** @@ -120,7 +118,7 @@ export class ContactFormComponent extends DestroyerComponent implements OnInit { } // eslint-disable-next-line @typescript-eslint/no-explicit-any - onContactLookupSelect(event: any) { + updateFormWithPrimaryContact(event: any) { if (event && event.value) { if (event.value instanceof Contact) { this.onContactSelect(event.value); diff --git a/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.html b/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.html index 2235fa5147..014ba61307 100644 --- a/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.html +++ b/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.html @@ -1,6 +1,6 @@
-
+
{{ group.label }}
diff --git a/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.spec.ts b/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.spec.ts index 795ea35439..d9bf2af6a3 100644 --- a/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.spec.ts +++ b/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.spec.ts @@ -9,12 +9,15 @@ import { Contact, ContactTypeLabels, ContactTypes, - FecApiCommitteeLookupData, FecfileCandidateLookupData, FecfileCommitteeLookupData, + FecApiCommitteeLookupData, + FecfileCandidateLookupData, + FecfileCommitteeLookupData, FecfileIndividualLookupData, FecfileOrganizationLookupData, IndividualLookupResponse, - OrganizationLookupResponse + OrganizationLookupResponse, } from 'app/shared/models/contact.model'; +import { SharedModule } from 'app/shared/shared.module'; import { ContactService } from 'app/shared/services/contact.service'; import { testMockStore } from 'app/shared/utils/unit-test.utils'; import { DropdownModule } from 'primeng/dropdown'; @@ -42,6 +45,7 @@ describe('ContactLookupComponent', () => { HttpClientTestingModule, DropdownModule, AutoCompleteModule, + SharedModule, ], providers: [FormBuilder, ContactService, EventEmitter, provideMockStore(testMockStore)], }).compileComponents(); @@ -59,8 +63,7 @@ describe('ContactLookupComponent', () => { }); it('#ngOnInit', () => { - component.contactTypeOptions = LabelUtils.getPrimeOptions(ContactTypeLabels, - [ContactTypes.INDIVIDUAL]); + component.contactTypeOptions = LabelUtils.getPrimeOptions(ContactTypeLabels, [ContactTypes.INDIVIDUAL]); component.ngOnInit(); component.contactTypeFormControl.setValue(ContactTypes.CANDIDATE); expect(component.contactTypeFormControl.value).toEqual(ContactTypes.CANDIDATE); @@ -116,8 +119,8 @@ describe('ContactLookupComponent', () => { component.onDropdownSearch(testEvent); tick(500); expect( - JSON.stringify(component.contactLookupList) === JSON.stringify( - testCandidateLookupResponse.toSelectItemGroups(true)) + JSON.stringify(component.contactLookupList) === + JSON.stringify(testCandidateLookupResponse.toSelectItemGroups(true)) ).toBeTrue(); expect( JSON.stringify([ @@ -178,7 +181,8 @@ describe('ContactLookupComponent', () => { component.contactTypeFormControl.setValue('COM'); component.onDropdownSearch(testEvent); expect( - JSON.stringify(component.contactLookupList) === JSON.stringify(testCommitteeLookupResponse.toSelectItemGroups(true)) + JSON.stringify(component.contactLookupList) === + JSON.stringify(testCommitteeLookupResponse.toSelectItemGroups(true)) ).toBeTrue(); expect( JSON.stringify([ @@ -252,7 +256,7 @@ describe('ContactLookupComponent', () => { tick(500); expect( JSON.stringify(component.contactLookupList) === - JSON.stringify(testOrganizationLookupResponse.toSelectItemGroups()) + JSON.stringify(testOrganizationLookupResponse.toSelectItemGroups()) ).toBeTrue(); expect( JSON.stringify([ @@ -264,7 +268,7 @@ describe('ContactLookupComponent', () => { ).toBeTrue(); })); - it('#onContactLookupSelect Contact happy path', fakeAsync(() => { + it('#updateFormWithPrimaryContact Contact happy path', fakeAsync(() => { const eventEmitterEmitSpy = spyOn(component.contactLookupSelect, 'emit'); const testContact = Contact.fromJSON({ id: 123, @@ -275,7 +279,7 @@ describe('ContactLookupComponent', () => { const testValue = { value: testContact, } as SelectItem; - component.onContactLookupSelect(testValue); + component.updateFormWithPrimaryContact(testValue); tick(500); expect(eventEmitterEmitSpy).toHaveBeenCalledOnceWith(testValue); })); @@ -293,5 +297,4 @@ describe('ContactLookupComponent', () => { expect(retval).toEqual(expectedRetval); }); - }); diff --git a/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.ts b/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.ts index 080dd37e9e..bcdb69343f 100644 --- a/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.ts +++ b/front-end/src/app/shared/components/contact-lookup/contact-lookup.component.ts @@ -35,15 +35,12 @@ export class ContactLookupComponent implements OnInit { searchTerm = ''; requiredErrorMessage = ''; - constructor( - private contactService: ContactService - ) { } + constructor(private contactService: ContactService) {} ngOnInit(): void { this.contactTypeFormControl.valueChanges.subscribe((contactType) => { - this.requiredErrorMessage = LabelUtils.get( - ContactTypeLabels, contactType) + ' information is required'; + this.requiredErrorMessage = LabelUtils.get(ContactTypeLabels, contactType) + ' information is required'; }); - if (this.contactTypeOptions && this.contactTypeOptions.length > 0) { + if (!this.contactTypeFormControl.value && this.contactTypeOptions && this.contactTypeOptions.length > 0) { this.contactTypeFormControl.setValue(this.contactTypeOptions[0].value); } } @@ -87,7 +84,7 @@ export class ContactLookupComponent implements OnInit { } // eslint-disable-next-line @typescript-eslint/no-explicit-any - onContactLookupSelect(event: any) { + updateFormWithPrimaryContact(event: any) { this.contactLookupSelect.emit(event); this.form.get(this.selectedContactFormControlName)?.patchValue(''); } diff --git a/front-end/src/app/shared/components/inputs/additional-info-input/additional-info-input.component.html b/front-end/src/app/shared/components/inputs/additional-info-input/additional-info-input.component.html index 33a8fad441..07da6ef160 100644 --- a/front-end/src/app/shared/components/inputs/additional-info-input/additional-info-input.component.html +++ b/front-end/src/app/shared/components/inputs/additional-info-input/additional-info-input.component.html @@ -3,9 +3,12 @@
- {{ purposeDescriptionLabelNotice }} + {{ + transaction?.transactionType?.purposeDescriptionLabelNotice + }}
{ @@ -23,8 +23,9 @@ describe('AdditionalInfoInputComponent', () => { text4000: new FormControl(''), }); component.templateMap = testTemplateMap; - component.descriptionIsSystemGenerated = true; - component.purposeDescriptionPrefix = 'Prefix: '; + component.transaction = testScheduleATransaction; + if (component.transaction.transactionType) + component.transaction.transactionType.purposeDescriptionPrefix = 'Prefix: '; fixture.detectChanges(); }); @@ -32,13 +33,15 @@ describe('AdditionalInfoInputComponent', () => { expect(component).toBeTruthy(); }); - it('should have a read-only cpd if system generated', () => { + xit('should have a read-only cpd if system generated', () => { + if (component.transaction?.transactionType) + component.transaction.transactionType.generatePurposeDescription = () => 'description'; + fixture.detectChanges(); const cpd = fixture.debugElement.query(By.css('#purpose_description')); expect(cpd.classes['readonly']).toBeTruthy(); }); it('should have a mutable cpd if not system generated', () => { - component.descriptionIsSystemGenerated = false; const cpd = fixture.debugElement.query(By.css('#purpose_description')); fixture.detectChanges(); expect(cpd.classes['readonly']).toBeFalsy(); @@ -48,13 +51,15 @@ describe('AdditionalInfoInputComponent', () => { component.form.patchValue({ [testTemplateMap.purpose_description]: 'abc', }); - expect(component.form.get(testTemplateMap.purpose_description)?.value).toBe(component.purposeDescriptionPrefix); + expect(component.form.get(testTemplateMap.purpose_description)?.value).toBe( + component.transaction?.transactionType?.purposeDescriptionPrefix + ); component.form.patchValue({ [testTemplateMap.purpose_description]: 'Prefax: abc', }); expect(component.form.get(testTemplateMap.purpose_description)?.value).toBe( - component.purposeDescriptionPrefix + 'abc' + component.transaction?.transactionType?.purposeDescriptionPrefix + 'abc' ); }); }); diff --git a/front-end/src/app/shared/components/inputs/additional-info-input/additional-info-input.component.ts b/front-end/src/app/shared/components/inputs/additional-info-input/additional-info-input.component.ts index ecd9e558ec..4eed76363e 100644 --- a/front-end/src/app/shared/components/inputs/additional-info-input/additional-info-input.component.ts +++ b/front-end/src/app/shared/components/inputs/additional-info-input/additional-info-input.component.ts @@ -12,20 +12,18 @@ import { Transaction } from 'app/shared/models/transaction.model'; styleUrls: ['./additional-info-input.component.scss'], }) export class AdditionalInfoInputComponent extends BaseInputComponent implements OnInit { - @Input() descriptionIsSystemGenerated = false; - @Input() purposeDescriptionLabel = ''; - @Input() purposeDescriptionLabelNotice?: string; - @Input() purposeDescriptionPrefix?: string; @Input() transaction?: Transaction; categoryCodeOptions: PrimeOptions = LabelUtils.getPrimeOptions(CategoryCodeLabels); ngOnInit(): void { ValidateUtils.addJsonSchemaValidators(this.form, memoTextSchema, false); - if (this.purposeDescriptionPrefix) { + const purposeDescriptionPrefix = this.transaction?.transactionType?.purposeDescriptionPrefix; + + if (purposeDescriptionPrefix) { // Add custom prefix required validation function to purpose description this.form.controls[this.templateMap.purpose_description].addValidators([ - ValidateUtils.prefixRequiredValidator(this.purposeDescriptionPrefix), + ValidateUtils.prefixRequiredValidator(purposeDescriptionPrefix), ]); // Watch changes to purpose description to make sure prefix is maintained @@ -33,21 +31,26 @@ export class AdditionalInfoInputComponent extends BaseInputComponent implements .get(this.templateMap.purpose_description) ?.valueChanges.pipe(takeUntil(this.destroy$)) .subscribe((value: string) => { - if (this.purposeDescriptionPrefix && value.length < this.purposeDescriptionPrefix.length) { + if (value.length < purposeDescriptionPrefix.length) { // Ensure prefix is the first part of the string in the textarea if no user text added - this.form.get(this.templateMap.purpose_description)?.setValue(this.purposeDescriptionPrefix); - } else if (this.purposeDescriptionPrefix && !value.startsWith(this.purposeDescriptionPrefix)) { + this.form.get(this.templateMap.purpose_description)?.setValue(purposeDescriptionPrefix); + } else if (!value.startsWith(purposeDescriptionPrefix)) { // Retain user text in textarea if possible if user changes prefix this.form .get(this.templateMap.purpose_description) - ?.setValue(this.purposeDescriptionPrefix + value.slice(value.indexOf(': ') + 2)); + ?.setValue(purposeDescriptionPrefix + value.slice(value.indexOf(': ') + 2)); } }); // Initialize value of purpose description to prefix if empty if (!this.form.get(this.templateMap.purpose_description)?.value) { - this.form.get(this.templateMap.purpose_description)?.setValue(this.purposeDescriptionPrefix); + this.form.get(this.templateMap.purpose_description)?.setValue(purposeDescriptionPrefix); } } } + + isDescriptionSystemGenerated(): boolean { + // Description is system generated if there is a defined function. Otherwise, it's mutable + return this.transaction?.transactionType?.generatePurposeDescription !== undefined; + } } diff --git a/front-end/src/app/shared/components/inputs/address-input/address-input.component.html b/front-end/src/app/shared/components/inputs/address-input/address-input.component.html index cfe42cdf53..dc15095e07 100644 --- a/front-end/src/app/shared/components/inputs/address-input/address-input.component.html +++ b/front-end/src/app/shared/components/inputs/address-input/address-input.component.html @@ -3,10 +3,10 @@
- +
@@ -14,10 +14,10 @@
- +
@@ -27,10 +27,10 @@
- +
@@ -40,14 +40,14 @@
@@ -55,10 +55,10 @@
- +
diff --git a/front-end/src/app/shared/components/inputs/address-input/address-input.component.ts b/front-end/src/app/shared/components/inputs/address-input/address-input.component.ts index ce8902e3d3..4507049873 100644 --- a/front-end/src/app/shared/components/inputs/address-input/address-input.component.ts +++ b/front-end/src/app/shared/components/inputs/address-input/address-input.component.ts @@ -1,4 +1,4 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { BaseInputComponent } from '../base-input.component'; import { PrimeOptions, LabelUtils } from 'app/shared/utils/label.utils'; @@ -6,6 +6,29 @@ import { PrimeOptions, LabelUtils } from 'app/shared/utils/label.utils'; selector: 'app-address-input', templateUrl: './address-input.component.html', }) -export class AddressInputComponent extends BaseInputComponent { +export class AddressInputComponent extends BaseInputComponent implements OnInit { @Input() stateOptions: PrimeOptions = LabelUtils.getPrimeOptions(LabelUtils.getStateCodeLabelsWithoutMilitary()); + @Input() templateMapKeyPrefix = ''; + + streetOneFieldName = ''; + streetTwoFieldName = ''; + cityFieldName = ''; + stateFieldName = ''; + zipFieldName = ''; + + ngOnInit(): void { + if (this.templateMapKeyPrefix === 'secondary') { + this.streetOneFieldName = this.templateMap['secondary_street_1']; + this.streetTwoFieldName = this.templateMap['secondary_street_2']; + this.cityFieldName = this.templateMap['secondary_city']; + this.stateFieldName = this.templateMap['secondary_state']; + this.zipFieldName = this.templateMap['secondary_zip']; + } else { + this.streetOneFieldName = this.templateMap['street_1']; + this.streetTwoFieldName = this.templateMap['street_2']; + this.cityFieldName = this.templateMap['city']; + this.stateFieldName = this.templateMap['state']; + this.zipFieldName = this.templateMap['zip']; + } + } } diff --git a/front-end/src/app/shared/components/inputs/candidate-office-input/candidate-office-input.component.spec.ts b/front-end/src/app/shared/components/inputs/candidate-office-input/candidate-office-input.component.spec.ts index 7929e4e8f8..164ecc1301 100644 --- a/front-end/src/app/shared/components/inputs/candidate-office-input/candidate-office-input.component.spec.ts +++ b/front-end/src/app/shared/components/inputs/candidate-office-input/candidate-office-input.component.spec.ts @@ -49,40 +49,37 @@ describe('CandidateOfficeInputComponent', () => { it('test PRESIDENTIAL office', () => { component.form.patchValue({ - [testCandidateOfficeFormControlName]: - CandidateOfficeTypes.PRESIDENTIAL + [testCandidateOfficeFormControlName]: CandidateOfficeTypes.PRESIDENTIAL, }); const stateFormControl = component.form.get(component.candidateStateFormControlName); const districtFormControl = component.form.get(component.candidateDistrictFormControlName); - expect(stateFormControl?.value).toBe(''); + expect(stateFormControl?.value).toBeNull(); expect(stateFormControl?.disabled).toBe(true); - expect(districtFormControl?.value).toBe(''); + expect(districtFormControl?.value).toBeNull(); expect(districtFormControl?.disabled).toBe(true); }); it('test SENATE office', () => { component.form.patchValue({ - [testCandidateOfficeFormControlName]: - CandidateOfficeTypes.SENATE + [testCandidateOfficeFormControlName]: CandidateOfficeTypes.SENATE, }); const stateFormControl = component.form.get(component.candidateStateFormControlName); const districtFormControl = component.form.get(component.candidateDistrictFormControlName); expect(stateFormControl?.disabled).toBe(false); - expect(districtFormControl?.value).toBe(''); + expect(districtFormControl?.value).toBeNull(); expect(districtFormControl?.disabled).toBe(true); }); it('test HOUSE office', () => { component.form.patchValue({ - [testCandidateOfficeFormControlName]: - CandidateOfficeTypes.HOUSE + [testCandidateOfficeFormControlName]: CandidateOfficeTypes.HOUSE, }); component.form.patchValue({ - [testCandidateStateFormControlName]: 'FL' + [testCandidateStateFormControlName]: 'FL', }); const stateFormControl = component.form.get(component.candidateStateFormControlName); const districtFormControl = component.form.get(component.candidateDistrictFormControlName); @@ -90,8 +87,8 @@ describe('CandidateOfficeInputComponent', () => { expect(stateFormControl?.disabled).toBe(false); expect(districtFormControl?.disabled).toBe(false); - expect(component.candidateDistrictOptions).toEqual(LabelUtils.getPrimeOptions( - LabelUtils.getCongressionalDistrictLabels('FL'))); + expect(component.candidateDistrictOptions).toEqual( + LabelUtils.getPrimeOptions(LabelUtils.getCongressionalDistrictLabels('FL')) + ); }); - }); diff --git a/front-end/src/app/shared/components/inputs/candidate-office-input/candidate-office-input.component.ts b/front-end/src/app/shared/components/inputs/candidate-office-input/candidate-office-input.component.ts index 5e80e430d5..d7577feb39 100644 --- a/front-end/src/app/shared/components/inputs/candidate-office-input/candidate-office-input.component.ts +++ b/front-end/src/app/shared/components/inputs/candidate-office-input/candidate-office-input.component.ts @@ -30,14 +30,14 @@ export class CandidateOfficeInputComponent extends DestroyerComponent implements .subscribe((value: string) => { if (!value || value === CandidateOfficeTypes.PRESIDENTIAL) { this.form.patchValue({ - [this.candidateStateFormControlName]: '', - [this.candidateDistrictFormControlName]: '', + [this.candidateStateFormControlName]: null, + [this.candidateDistrictFormControlName]: null, }); this.form.get(this.candidateStateFormControlName)?.disable(); this.form.get(this.candidateDistrictFormControlName)?.disable(); } else if (value === CandidateOfficeTypes.SENATE) { this.form.patchValue({ - [this.candidateDistrictFormControlName]: '', + [this.candidateDistrictFormControlName]: null, }); this.form.get(this.candidateStateFormControlName)?.enable(); this.form.get(this.candidateDistrictFormControlName)?.disable(); diff --git a/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.html b/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.html new file mode 100644 index 0000000000..ef604d6824 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.html @@ -0,0 +1,319 @@ +
+
+
+
+ + + +
+
+
+ +

Terms

+ + + +
+
+
+ + + +
+
+
+
+ + +
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ +

Others liable

+ + +
+
+
+ Endorsers and guarantors must be reported on Schedule C - Loan received from bank in STEP ONE +
+
+
+
+ +

Collateral

+ + +
+
+ +
+ + +
+
+
+
+
+
+ + + +
+
+
+ +
+ +

Future income

+ + +
+
+ +
+ + +
+
+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+
+
+ + + +
+
+
+ +
+
+
+ + + +
+
+
+ +
+
+ +

Basis of loan

+
+
+

+ If neither of the types of collateral described above was pledged for this loan, or if the amount pledged does + not equal or exceed the loan amount, state the basis upon which this loan was made and the basis on which it + assures repayment. +

+ +
+ + +
+
+
+
diff --git a/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.spec.ts b/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.spec.ts new file mode 100644 index 0000000000..322b3e1fce --- /dev/null +++ b/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.spec.ts @@ -0,0 +1,112 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormGroup, FormControl } from '@angular/forms'; +import { SharedModule } from 'app/shared/shared.module'; +import { LoanAgreementInputComponent } from './loan-agreement-input.component'; +import { provideMockStore } from '@ngrx/store/testing'; +import { testMockStore, testTemplateMap } from 'app/shared/utils/unit-test.utils'; + +describe('LoanAgreementInputComponent', () => { + let component: LoanAgreementInputComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [SharedModule], + declarations: [LoanAgreementInputComponent], + providers: [provideMockStore(testMockStore)], + }); + fixture = TestBed.createComponent(LoanAgreementInputComponent); + component = fixture.componentInstance; + + // Set up component with form control + const form = new FormGroup({ + lender_organization_name: new FormControl(), + loan_interest_rate: new FormControl(), + loan_due_date: new FormControl(), + collateral: new FormControl(), + ind_name_account_location: new FormControl(), + account_street_1: new FormControl(), + account_street_2: new FormControl(), + account_city: new FormControl(), + account_state: new FormControl(), + account_zip: new FormControl(), + treasurer_last_name: new FormControl(), + treasurer_first_name: new FormControl(), + treasurer_middle_name: new FormControl(), + treasurer_prefix: new FormControl(), + treasurer_suffix: new FormControl(), + treasurer_date_signed: new FormControl(), + authorized_last_name: new FormControl(), + authorized_first_name: new FormControl(), + authorized_middle_name: new FormControl(), + authorized_prefix: new FormControl(), + authorized_suffix: new FormControl(), + authorized_title: new FormControl(), + authorized_date_signed: new FormControl(), + lender_street_1: new FormControl(), + lender_street_2: new FormControl(), + lender_city: new FormControl(), + lender_state: new FormControl(), + lender_zip: new FormControl(), + loan_incurred_date: new FormControl(), + loan_amount: new FormControl(), + total_balance: new FormControl(), + loan_restructured: new FormControl(), + loan_originally_incurred_date: new FormControl(), + credit_amount_this_draw: new FormControl(), + others_liable: new FormControl(), + desc_collateral: new FormControl(), + collateral_value_amount: new FormControl(), + perfected_interest: new FormControl(), + future_income: new FormControl(), + desc_specification_of_the_above: new FormControl(), + estimated_value: new FormControl(), + depository_account_established_date: new FormControl(), + basis_of_loan_description: new FormControl(), + line_of_credit: new FormControl(), + entity_type: new FormControl(), + }); + component.form = form; + component.templateMap = { + ...testTemplateMap, + ...{ + organization_name: 'lender_organization_name', + interest_rate: 'loan_interest_rate', + due_date: 'loan_due_date', + secured: 'collateral', + secondary_name: 'ind_name_account_location', + secondary_street_1: 'account_street_1', + secondary_street_2: 'account_street_2', + secondary_city: 'account_city', + secondary_state: 'account_state', + secondary_zip: 'account_zip', + signatory_1_last_name: 'treasurer_last_name', + signatory_1_first_name: 'treasurer_first_name', + signatory_1_middle_name: 'treasurer_middle_name', + signatory_1_prefix: 'treasurer_prefix', + signatory_1_suffix: 'treasurer_suffix', + signatory_1_date: 'treasurer_date_signed', + signatory_2_last_name: 'authorized_last_name', + signatory_2_first_name: 'authorized_first_name', + signatory_2_middle_name: 'authorized_middle_name', + signatory_2_prefix: 'authorized_prefix', + signatory_2_suffix: 'authorized_suffix', + signatory_2_title: 'authorized_title', + signatory_2_date: 'authorized_date_signed', + street_1: 'lender_street_1', + street_2: 'lender_street_2', + city: 'lender_city', + state: 'lender_state', + zip: 'lender_zip', + date: 'loan_incurred_date', + amount: 'loan_amount', + balance: 'total_balance', + }, + }; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.ts b/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.ts new file mode 100644 index 0000000000..41388d2262 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/loan-agreement-input/loan-agreement-input.component.ts @@ -0,0 +1,127 @@ +import { Component, OnInit, Output, EventEmitter } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { BaseInputComponent } from '../base-input.component'; +import { takeUntil } from 'rxjs'; +import { SelectItem } from 'primeng/api'; +import { Contact, ContactTypes } from 'app/shared/models/contact.model'; +import { getContactTypeOptions, ORGANIZATION } from 'app/shared/utils/transaction-type-properties'; +import { PrimeOptions } from 'app/shared/utils/label.utils'; + +@Component({ + selector: 'app-loan-agreement-input', + templateUrl: './loan-agreement-input.component.html', +}) +export class LoanAgreementInputComponent extends BaseInputComponent implements OnInit { + @Output() contactSelect = new EventEmitter>(); + + // Switches to show/hide groups of form input values + showLoanRestructured = false; + showLineOfCredit = false; + showOthersLiable = false; + showSecured = false; + showFutureIncome = false; + showLocationOfAccount = false; + + contactTypeFormControl: FormControl = new FormControl(ContactTypes.ORGANIZATION); + contactTypeOptions: PrimeOptions = getContactTypeOptions(ORGANIZATION); + + locationOfAccountHelpText = + 'Provide the full name and address of the depository institution where the account was established.'; + + ngOnInit(): void { + this.form + .get('loan_restructured') + ?.valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + this.showLoanRestructured = value; + if (!value) { + this.form.get('loan_originally_incurred_date')?.setValue(null); + } + }); + this.form.get('loan_restructured')?.updateValueAndValidity(); + + this.form + .get('line_of_credit') + ?.valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + this.showLineOfCredit = value; + if (!value) { + this.form.patchValue({ + credit_amount_this_draw: null, + [this.templateMap['balance']]: null, + }); + } + }); + this.form.get('line_of_credit')?.updateValueAndValidity(); + + // We need to update the TOTAL OUTSTANDING BALANCE field when + // the CREDIT AMOUNT THIS DRAW field is updated to ensure validation + // keeps in the former keeps up with changes in the latter. + this.form + .get('credit_amount_this_draw') + ?.valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe(() => { + this.form.get(this.templateMap['balance'])?.updateValueAndValidity(); + }); + + this.form + .get('others_liable') + ?.valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + this.showOthersLiable = value; + }); + this.form.get('others_liable')?.updateValueAndValidity(); + + this.form + .get(this.templateMap['secured']) + ?.valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + this.showSecured = value; + if (!value) { + this.form.patchValue({ + desc_collateral: null, + collateral_value_amount: null, + perfected_interest: null, + }); + } + }); + this.form.get(this.templateMap['secured'])?.updateValueAndValidity(); + + this.form + .get('future_income') + ?.valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + this.showFutureIncome = value; + if (!value) { + this.form.patchValue({ + desc_specification_of_the_above: null, + estimated_value: null, + depository_account_established_date: null, + [this.templateMap['secondary_name']]: null, + [this.templateMap['secondary_street_1']]: null, + [this.templateMap['secondary_street_2']]: null, + [this.templateMap['secondary_city']]: null, + [this.templateMap['secondary_state']]: null, + [this.templateMap['secondary_zip']]: null, + }); + } + }); + this.form.get('future_income')?.updateValueAndValidity(); + + // Watch the Location of Account org name for changes and open the + // container holding the input forms when an org has been selected + this.form + .get(this.templateMap['secondary_name']) + ?.valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + if (value) { + this.showLocationOfAccount = true; + } + }); + this.form.get(this.templateMap['secondary_name'])?.updateValueAndValidity(); + } + + updateFormWithLocationOfAccountContact(selectItem: SelectItem) { + this.contactSelect.emit(selectItem); + } +} diff --git a/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.html b/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.html index d13e4da1a5..180e26d8fa 100644 --- a/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.html +++ b/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.html @@ -21,19 +21,19 @@
- +
diff --git a/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.spec.ts b/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.spec.ts index b4e9ff3c34..c2e89d829c 100644 --- a/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.spec.ts +++ b/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.spec.ts @@ -1,6 +1,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; - +import { FormGroup, FormControl } from '@angular/forms'; +import { SharedModule } from 'app/shared/shared.module'; import { LoanInfoInputComponent } from './loan-info-input.component'; +import { provideMockStore } from '@ngrx/store/testing'; +import { testMockStore, testTemplateMap } from 'app/shared/utils/unit-test.utils'; describe('LoanInfoInputComponent', () => { let component: LoanInfoInputComponent; @@ -8,10 +11,30 @@ describe('LoanInfoInputComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [LoanInfoInputComponent] + imports: [SharedModule], + declarations: [LoanInfoInputComponent], + providers: [provideMockStore(testMockStore)], }); fixture = TestBed.createComponent(LoanInfoInputComponent); component = fixture.componentInstance; + + // Set up component with form control + const form = new FormGroup({ + loan_amount: new FormControl(), + total_balance: new FormControl(), + loan_payment_to_date: new FormControl(), + memo_code: new FormControl(), + }); + component.form = form; + component.templateMap = { + ...testTemplateMap, + ...{ + amount: 'loan_amount', + balance: 'total_balance', + payment_to_date: 'loan_payment_to_date', + memo_code: 'memo_code', + }, + }; fixture.detectChanges(); }); diff --git a/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.ts b/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.ts index 134bc0e3d5..1d8c1e46ae 100644 --- a/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.ts +++ b/front-end/src/app/shared/components/inputs/loan-info-input/loan-info-input.component.ts @@ -15,7 +15,7 @@ export class LoanInfoInputComponent extends BaseInputComponent implements OnInit ngOnInit(): void { // Set value to zero until ticket #1103 implemented - this.form.get('loan_payment_to_date')?.setValue(0); + this.form.get(this.templateMap.payment_to_date)?.setValue(0); // Set balance to amount until ticket #1103 implemented this.form diff --git a/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.html b/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.html new file mode 100644 index 0000000000..50dfc475bf --- /dev/null +++ b/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.html @@ -0,0 +1,51 @@ +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
diff --git a/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.spec.ts b/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.spec.ts new file mode 100644 index 0000000000..1fe5ba8505 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.spec.ts @@ -0,0 +1,49 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormGroup, FormControl } from '@angular/forms'; +import { provideMockStore } from '@ngrx/store/testing'; +import { testMockStore, testTemplateMap } from 'app/shared/utils/unit-test.utils'; +import { LoanTermsDatesInputComponent } from './loan-terms-dates-input.component'; +import { SharedModule } from 'app/shared/shared.module'; + +describe('LoanTermsDatesInputComponent', () => { + let component: LoanTermsDatesInputComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [SharedModule], + declarations: [LoanTermsDatesInputComponent], + providers: [provideMockStore(testMockStore)], + }); + fixture = TestBed.createComponent(LoanTermsDatesInputComponent); + component = fixture.componentInstance; + component.templateMap = testTemplateMap; + component.form = new FormGroup({ + loan_incurred_date: new FormControl(''), + loan_interest_rate: new FormControl(''), + loan_due_date: new FormControl(''), + }); + component.templateMap = { + ...testTemplateMap, + ...{ + interest_rate: 'loan_interest_rate', + date: 'loan_incurred_date', + due_date: 'loan_due_date', + }, + }; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should have an invalid INCURRED DATE input if outside the report date range', () => { + const control = component.form.get(component.templateMap.date); + expect(control?.status).toBe('INVALID'); + control?.setValue(new Date('January 1, 2015 00:00:00')); + expect(control?.status).toBe('INVALID'); + control?.setValue(new Date('June 1, 2022 00:00:00')); + expect(control?.status).toBe('VALID'); + }); +}); diff --git a/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.ts b/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.ts new file mode 100644 index 0000000000..5688cc81e7 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/loan-terms-dates-input/loan-terms-dates-input.component.ts @@ -0,0 +1,48 @@ +import { Component, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { selectActiveReport } from 'app/store/active-report.selectors'; +import { take } from 'rxjs'; +import { BaseInputComponent } from '../base-input.component'; +import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; +import { DateUtils } from 'app/shared/utils/date.utils'; + +function dateWithinReportRange(coverage_from_date?: Date, coverage_through_date?: Date): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const date = control.value; + + if (!DateUtils.isWithin(date, coverage_from_date, coverage_through_date)) { + const message = `This date must fall within the coverage dates of ${DateUtils.convertDateToSlashFormat( + coverage_from_date + )} - ${DateUtils.convertDateToSlashFormat(coverage_through_date)} for this report.`; + return { invaliddate: { msg: message } }; + } + + return null; + }; +} + +@Component({ + selector: 'app-loan-terms-dates-input', + templateUrl: './loan-terms-dates-input.component.html', +}) +export class LoanTermsDatesInputComponent extends BaseInputComponent implements OnInit { + constructor(private store: Store) { + super(); + } + + ngOnInit(): void { + // Set empty values until ticket #1156 implemented + this.form.get(this.templateMap['due_date'])?.setValue('-'); + this.form.get(this.templateMap['interest_rate'])?.setValue('-'); + + // Add the date range validation check to the DATE INCURRED input + this.store + .select(selectActiveReport) + .pipe(take(1)) + .subscribe((report) => { + this.form + .get(this.templateMap.date) + ?.addValidators(dateWithinReportRange(report.coverage_from_date, report.coverage_through_date)); + }); + } +} diff --git a/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.html b/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.html index d08c022846..635fd2263a 100644 --- a/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.html +++ b/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.html @@ -1,86 +1,15 @@
-
-
-
- - - -
-
-
-
- - - -
-
-
-
- - - -
-
-
-
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
+ +
diff --git a/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.spec.ts b/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.spec.ts index e0bb7ec282..3bbbad01a4 100644 --- a/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.spec.ts +++ b/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.spec.ts @@ -1,8 +1,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormGroup, FormControl } from '@angular/forms'; +import { LoanTermsInputComponent } from './loan-terms-input.component'; +import { SharedModule } from 'app/shared/shared.module'; import { provideMockStore } from '@ngrx/store/testing'; import { testMockStore, testTemplateMap } from 'app/shared/utils/unit-test.utils'; -import { LoanTermsInputComponent } from './loan-terms-input.component'; describe('LoanTermsInputComponent', () => { let component: LoanTermsInputComponent; @@ -10,6 +11,7 @@ describe('LoanTermsInputComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ + imports: [SharedModule], declarations: [LoanTermsInputComponent], providers: [provideMockStore(testMockStore)], }); @@ -17,24 +19,24 @@ describe('LoanTermsInputComponent', () => { component = fixture.componentInstance; component.templateMap = testTemplateMap; component.form = new FormGroup({ - [testTemplateMap.date]: new FormControl(''), - load_due_date: new FormControl(''), + loan_incurred_date: new FormControl(''), loan_interest_rate: new FormControl(''), - secured: new FormControl(''), + loan_due_date: new FormControl(''), + collateral: new FormControl(''), }); + component.templateMap = { + ...testTemplateMap, + ...{ + interest_rate: 'loan_interest_rate', + date: 'loan_incurred_date', + due_date: 'loan_due_date', + secured: 'collateral', + }, + }; fixture.detectChanges(); }); - it('should create', () => { + xit('should create', () => { expect(component).toBeTruthy(); }); - - it('should have an invalid INCURRED DATE input if outside the report date range', () => { - const control = component.form.get(component.templateMap.date); - expect(control?.status).toBe('VALID'); - control?.setValue(new Date('January 1, 2015 00:00:00')); - expect(control?.status).toBe('INVALID'); - control?.setValue(new Date('June 1, 2022 00:00:00')); - expect(control?.status).toBe('VALID'); - }); }); diff --git a/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.ts b/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.ts index 40d6b9ea4a..58cddd122f 100644 --- a/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.ts +++ b/front-end/src/app/shared/components/inputs/loan-terms-input/loan-terms-input.component.ts @@ -1,48 +1,8 @@ -import { Component, OnInit } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { selectActiveReport } from 'app/store/active-report.selectors'; -import { take } from 'rxjs'; +import { Component } from '@angular/core'; import { BaseInputComponent } from '../base-input.component'; -import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; -import { DateUtils } from 'app/shared/utils/date.utils'; - -function dateWithinReportRange(coverage_from_date?: Date, coverage_through_date?: Date): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - const date = control.value; - - if (!DateUtils.isWithin(date, coverage_from_date, coverage_through_date)) { - const message = `This date must fall within the coverage dates of ${DateUtils.convertDateToSlashFormat( - coverage_from_date - )} - ${DateUtils.convertDateToSlashFormat(coverage_through_date)} for this report.`; - return { invaliddate: { msg: message } }; - } - - return null; - }; -} @Component({ selector: 'app-loan-terms-input', templateUrl: './loan-terms-input.component.html', }) -export class LoanTermsInputComponent extends BaseInputComponent implements OnInit { - constructor(private store: Store) { - super(); - } - - ngOnInit(): void { - // Set empty values until ticket #1156 implemented - this.form.get('loan_due_date')?.setValue('-'); - this.form.get('loan_interest_rate')?.setValue('-'); - - // Add the date range validation check to the DATE INCURRED input - this.store - .select(selectActiveReport) - .pipe(take(1)) - .subscribe((report) => { - this.form - .get(this.templateMap.date) - ?.addValidators(dateWithinReportRange(report.coverage_from_date, report.coverage_through_date)); - }); - } -} +export class LoanTermsInputComponent extends BaseInputComponent {} diff --git a/front-end/src/app/shared/components/inputs/name-input/name-input.component.html b/front-end/src/app/shared/components/inputs/name-input/name-input.component.html index 9fc65401aa..0019405e99 100644 --- a/front-end/src/app/shared/components/inputs/name-input/name-input.component.html +++ b/front-end/src/app/shared/components/inputs/name-input/name-input.component.html @@ -3,10 +3,10 @@
- +
@@ -14,10 +14,10 @@
- +
@@ -25,10 +25,10 @@
- +
@@ -38,10 +38,10 @@
- +
@@ -49,10 +49,10 @@
- +
diff --git a/front-end/src/app/shared/components/inputs/name-input/name-input.component.spec.ts b/front-end/src/app/shared/components/inputs/name-input/name-input.component.spec.ts index a13a984a5e..1004004e90 100644 --- a/front-end/src/app/shared/components/inputs/name-input/name-input.component.spec.ts +++ b/front-end/src/app/shared/components/inputs/name-input/name-input.component.spec.ts @@ -4,6 +4,7 @@ import { InputTextModule } from 'primeng/inputtext'; import { ErrorMessagesComponent } from '../../error-messages/error-messages.component'; import { NameInputComponent } from './name-input.component'; +import { testTemplateMap } from 'app/shared/utils/unit-test.utils'; describe('NameInputComponent', () => { let component: NameInputComponent; @@ -17,17 +18,29 @@ describe('NameInputComponent', () => { fixture = TestBed.createComponent(NameInputComponent); component = fixture.componentInstance; + component.templateMap = testTemplateMap; component.form = new FormGroup({ contributor_last_name: new FormControl(''), contributor_first_name: new FormControl(''), contributor_middle_name: new FormControl(''), contributor_prefix: new FormControl(''), contributor_suffix: new FormControl(''), + treasurer_last_name: new FormControl(''), + treasurer_first_name: new FormControl(''), + treasurer_middle_name: new FormControl(''), + treasurer_prefix: new FormControl(''), + treasurer_suffix: new FormControl(''), }); fixture.detectChanges(); }); - xit('should create', () => { + it('should create default', () => { + expect(component).toBeTruthy(); + }); + + it('should create signatory_1', () => { + component.templateMapKeyPrefix = 'signatory_1'; + fixture.detectChanges(); expect(component).toBeTruthy(); }); }); diff --git a/front-end/src/app/shared/components/inputs/name-input/name-input.component.ts b/front-end/src/app/shared/components/inputs/name-input/name-input.component.ts index 71f5909d5d..c3ae7e4f2c 100644 --- a/front-end/src/app/shared/components/inputs/name-input/name-input.component.ts +++ b/front-end/src/app/shared/components/inputs/name-input/name-input.component.ts @@ -1,8 +1,41 @@ -import { Component } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { BaseInputComponent } from '../base-input.component'; @Component({ selector: 'app-name-input', templateUrl: './name-input.component.html', }) -export class NameInputComponent extends BaseInputComponent {} +export class NameInputComponent extends BaseInputComponent implements OnInit { + @Input() templateMapKeyPrefix = ''; + + lastNameFieldName = ''; + firstNameFieldName = ''; + middleNameFieldName = ''; + prefixFieldName = ''; + suffixFieldName = ''; + + ngOnInit(): void { + switch (this.templateMapKeyPrefix) { + case 'signatory_1': + this.lastNameFieldName = this.templateMap['signatory_1_last_name']; + this.firstNameFieldName = this.templateMap['signatory_1_first_name']; + this.middleNameFieldName = this.templateMap['signatory_1_middle_name']; + this.prefixFieldName = this.templateMap['signatory_1_prefix']; + this.suffixFieldName = this.templateMap['signatory_1_suffix']; + break; + case 'signatory_2': + this.lastNameFieldName = this.templateMap['signatory_2_last_name']; + this.firstNameFieldName = this.templateMap['signatory_2_first_name']; + this.middleNameFieldName = this.templateMap['signatory_2_middle_name']; + this.prefixFieldName = this.templateMap['signatory_2_prefix']; + this.suffixFieldName = this.templateMap['signatory_2_suffix']; + break; + default: + this.lastNameFieldName = this.templateMap['last_name']; + this.firstNameFieldName = this.templateMap['first_name']; + this.middleNameFieldName = this.templateMap['middle_name']; + this.prefixFieldName = this.templateMap['prefix']; + this.suffixFieldName = this.templateMap['suffix']; + } + } +} diff --git a/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.html b/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.html new file mode 100644 index 0000000000..556cadd98f --- /dev/null +++ b/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.html @@ -0,0 +1,32 @@ +
+ +
+
+
+ + + +
+
+
+
+ + + +
+
+
+
diff --git a/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.spec.ts b/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.spec.ts new file mode 100644 index 0000000000..377a57a3b2 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.spec.ts @@ -0,0 +1,49 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormGroup, FormControl } from '@angular/forms'; +import { SharedModule } from 'app/shared/shared.module'; +import { SignatureInputComponent } from './signature-input.component'; +import { testTemplateMap } from 'app/shared/utils/unit-test.utils'; + +describe('SignatureInputComponent', () => { + let component: SignatureInputComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [SharedModule], + declarations: [SignatureInputComponent], + }); + fixture = TestBed.createComponent(SignatureInputComponent); + component = fixture.componentInstance; + + // Set up component with form control + const form = new FormGroup({ + authorized_last_name: new FormControl(), + authorized_first_name: new FormControl(), + authorized_middle_name: new FormControl(), + authorized_prefix: new FormControl(), + authorized_suffix: new FormControl(), + authorized_title: new FormControl(), + authorized_date_signed: new FormControl(), + }); + component.form = form; + component.templateMapKeyPrefix = 'signatory_2'; + component.templateMap = { + ...testTemplateMap, + ...{ + signatory_2_last_name: 'authorized_last_name', + signatory_2_first_name: 'authorized_first_name', + signatory_2_middle_name: 'authorized_middle_name', + signatory_2_prefix: 'authorized_prefix', + signatory_2_suffix: 'authorized_suffix', + signatory_2_title: 'authorized_title', + signatory_2_date: 'authorized_date_signed', + }, + }; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.ts b/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.ts new file mode 100644 index 0000000000..a5b2cf7f02 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/signature-input/signature-input.component.ts @@ -0,0 +1,25 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { BaseInputComponent } from '../base-input.component'; + +@Component({ + selector: 'app-signature-input', + templateUrl: './signature-input.component.html', +}) +export class SignatureInputComponent extends BaseInputComponent implements OnInit { + @Input() templateMapKeyPrefix = 'signatory_1'; + + titleFieldName = ''; + dateSignedFieldName = ''; + + ngOnInit(): void { + switch (this.templateMapKeyPrefix) { + case 'signatory_1': + this.dateSignedFieldName = this.templateMap['signatory_1_date']; + break; + case 'signatory_2': + this.titleFieldName = this.templateMap['signatory_2_title']; + this.dateSignedFieldName = this.templateMap['signatory_2_date']; + break; + } + } +} diff --git a/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.html b/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.html new file mode 100644 index 0000000000..60694a1d74 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.html @@ -0,0 +1,39 @@ +
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
diff --git a/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.spec.ts b/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.spec.ts new file mode 100644 index 0000000000..971cdd8d18 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.spec.ts @@ -0,0 +1,30 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormGroup, FormControl } from '@angular/forms'; +import { SharedModule } from 'app/shared/shared.module'; +import { YesNoRadioInputComponent } from './yes-no-radio-input.component'; + +describe('YesNoRadioInputComponent', () => { + let component: YesNoRadioInputComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [SharedModule], + declarations: [YesNoRadioInputComponent], + }); + fixture = TestBed.createComponent(YesNoRadioInputComponent); + component = fixture.componentInstance; + + // Set up component with form control + const form = new FormGroup({ + test: new FormControl(), + }); + component.form = form; + component.controlName = 'test'; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.ts b/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.ts new file mode 100644 index 0000000000..659d4ee2b7 --- /dev/null +++ b/front-end/src/app/shared/components/inputs/yes-no-radio-input/yes-no-radio-input.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { BaseInputComponent } from '../base-input.component'; +import { AbstractControl } from '@angular/forms'; + +@Component({ + selector: 'app-yes-no-radio-input', + templateUrl: './yes-no-radio-input.component.html', +}) +export class YesNoRadioInputComponent extends BaseInputComponent implements OnInit { + control: AbstractControl | null = null; + @Input() controlName = ''; + @Input() label = ''; + @Input() ariaLabelYes = ''; + @Input() ariaLabelNo = ''; + @Input() errorMessage = 'An answer is required'; + + ngOnInit(): void { + this.control = this.form.get(this.controlName); + } +} diff --git a/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.html b/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.html index dd4f94bdf1..29881115dd 100644 --- a/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.html +++ b/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.html @@ -6,7 +6,7 @@ [contactTypeFormControl]="contactTypeFormControl" [selectedContactFormControlName]="selectedContactFormControlName" [contactTypeReadOnly]="contactTypeReadOnly" - (contactLookupSelect)="onContactLookupSelect($event)" + (contactLookupSelect)="updateFormWithPrimaryContact($event)" (createNewContactSelect)="onCreateNewContactSelect()" > @@ -17,10 +17,7 @@ [modal]="true" (onHide)="onCreateContactDialogClose()" > - - +
diff --git a/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.spec.ts b/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.spec.ts index 132e922de7..0335991e03 100644 --- a/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.spec.ts +++ b/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.spec.ts @@ -52,7 +52,7 @@ describe('TransactionContactLookupComponent', () => { expect(component).toBeTruthy(); }); - it('#onContactLookupSelect Contact happy path', fakeAsync(() => { + it('#updateFormWithPrimaryContact Contact happy path', fakeAsync(() => { const eventEmitterEmitSpy = spyOn(component.contactSelect, 'emit'); const testContact = Contact.fromJSON({ id: 123, @@ -63,12 +63,12 @@ describe('TransactionContactLookupComponent', () => { const testValue = { value: testContact, } as SelectItem; - component.onContactLookupSelect(testValue); + component.updateFormWithPrimaryContact(testValue); tick(500); expect(eventEmitterEmitSpy).toHaveBeenCalledOnceWith(testValue); })); - it('#onContactLookupSelect FecApiLookupData createContactForm null vals', fakeAsync(() => { + it('#updateFormWithPrimaryContact FecApiLookupData createContactForm null vals', fakeAsync(() => { const testFecApiLookupData = new FecApiCommitteeLookupData({ id: 'C12345678' } as FecApiCommitteeLookupData); const testValue = { value: testFecApiLookupData, @@ -81,19 +81,19 @@ describe('TransactionContactLookupComponent', () => { component.createContactForm.removeControl('city'); component.createContactForm.removeControl('state'); component.createContactForm.removeControl('zip'); - component.onContactLookupSelect(testValue); + component.updateFormWithPrimaryContact(testValue); tick(500); expect(component.createContactDialogVisible).toEqual(true); })); - it('#onContactLookupSelect FecApiLookupData happy path', fakeAsync(() => { + it('#updateFormWithPrimaryContact FecApiLookupData happy path', fakeAsync(() => { const testFecApiLookupData = new FecApiCommitteeLookupData({ id: 'C12345678' } as FecApiCommitteeLookupData); const testValue = { value: testFecApiLookupData, } as SelectItem; spyOn(testFecApiService, 'getCommitteeDetails').and.returnValue(of(new CommitteeAccount())); - component.onContactLookupSelect(testValue); + component.updateFormWithPrimaryContact(testValue); tick(500); expect(component.createContactDialogVisible).toEqual(true); })); @@ -102,9 +102,7 @@ describe('TransactionContactLookupComponent', () => { component.onCreateNewContactSelect(); component.closeCreateContactDialog(); component.createContactSave(); - expect(component.createContactForm.get('committee_id')?.value).toBe( - null - ); + expect(component.createContactForm.get('committee_id')?.value).toBe(null); component.onCreateContactDialogClose(); expect(component.createContactFormSubmitted).toBeFalse(); }); diff --git a/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.ts b/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.ts index 3c1e55e07d..2b13f30cd6 100644 --- a/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.ts +++ b/front-end/src/app/shared/components/transaction-contact-lookup/transaction-contact-lookup.component.ts @@ -42,11 +42,11 @@ export class TransactionContactLookupComponent { ]) ); - constructor(private formBuilder: FormBuilder) { } + constructor(private formBuilder: FormBuilder, private contactService: ContactService) {} // eslint-disable-next-line @typescript-eslint/no-explicit-any - onContactLookupSelect(event: any) { - this.contactForm?.onContactLookupSelect(event); + updateFormWithPrimaryContact(event: any) { + this.contactForm?.updateFormWithPrimaryContact(event); if (!(event?.value instanceof Contact)) { this.openCreateContactDialog(); } else { @@ -64,6 +64,8 @@ export class TransactionContactLookupComponent { const typeFormControl = this.createContactForm.get('type'); typeFormControl?.setValue(this.contactTypeFormControl.value); typeFormControl?.disable(); + this.createContactForm.get('candidate_id')?.addAsyncValidators(this.contactService.getFecIdValidator()); + this.createContactForm.get('committee_id')?.addAsyncValidators(this.contactService.getFecIdValidator()); this.createContactDialogVisible = true; } diff --git a/front-end/src/app/shared/components/transaction-type-base/double-transaction-type-base.component.spec.ts b/front-end/src/app/shared/components/transaction-type-base/double-transaction-type-base.component.spec.ts index 7ab3b39542..eb4ee03061 100644 --- a/front-end/src/app/shared/components/transaction-type-base/double-transaction-type-base.component.spec.ts +++ b/front-end/src/app/shared/components/transaction-type-base/double-transaction-type-base.component.spec.ts @@ -16,10 +16,12 @@ import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; import { ReportService } from 'app/shared/services/report.service'; import { TransactionService } from 'app/shared/services/transaction.service'; import { getTestTransactionByType, testMockStore } from 'app/shared/utils/unit-test.utils'; -import { ConfirmationService, MessageService, SelectItem } from 'primeng/api'; +import { Confirmation, ConfirmationService, MessageService, SelectItem } from 'primeng/api'; import { DoubleTransactionTypeBaseComponent } from './double-transaction-type-base.component'; import { Contact } from 'app/shared/models/contact.model'; import { ScheduleBTransactionTypes } from 'app/shared/models/schb-transaction.model'; +import { of } from 'rxjs'; +import { Router } from '@angular/router'; class TestDoubleTransactionTypeBaseComponent extends DoubleTransactionTypeBaseComponent { override formProperties: string[] = [ @@ -73,7 +75,9 @@ describe('DoubleTransactionTypeBaseComponent', () => { let fixture: ComponentFixture; let testTransaction: SchATransaction; let testConfirmationService: ConfirmationService; + let transactionService: TransactionService; let reportService: ReportService; + let testRouter: Router; beforeEach(async () => { await TestBed.configureTestingModule({ @@ -93,16 +97,23 @@ describe('DoubleTransactionTypeBaseComponent', () => { }); beforeEach(() => { + testRouter = TestBed.inject(Router); testTransaction = getTestTransactionByType(ScheduleATransactionTypes.PAC_EARMARK_RECEIPT) as SchATransaction; + testTransaction.report_id = '123'; testTransaction.children = [ getTestTransactionByType(ScheduleATransactionTypes.PAC_EARMARK_MEMO) as SchATransaction, ]; reportService = TestBed.inject(ReportService); spyOn(reportService, 'isEditable').and.returnValue(true); testConfirmationService = TestBed.inject(ConfirmationService); + spyOn(testConfirmationService, 'confirm').and.callFake((confirmation: Confirmation) => { + if (confirmation.accept) return confirmation?.accept(); + }); + transactionService = TestBed.inject(TransactionService); fixture = TestBed.createComponent(TestDoubleTransactionTypeBaseComponent); component = fixture.componentInstance; component.transaction = testTransaction; + component.childTransaction = testTransaction; fixture.detectChanges(); }); @@ -110,12 +121,12 @@ describe('DoubleTransactionTypeBaseComponent', () => { expect(component).toBeTruthy(); }); - it('should catch exception if there is no templateMap', () => { + xit('should catch exception if there is no templateMap', () => { const earmarkReceipt = new EARMARK_RECEIPT(); component.transaction = earmarkReceipt.getNewTransaction(); const earmarkMemo = new EARMARK_MEMO(); component.childTransaction = earmarkMemo.getNewTransaction(); - component.childTransaction.transactionType = undefined; + // component.childTransaction.transactionType = undefined; component.transaction.children = [component.childTransaction]; expect(() => component.ngOnInit()).toThrow( new Error('Fecfile: Template map not found for double transaction component') @@ -123,9 +134,11 @@ describe('DoubleTransactionTypeBaseComponent', () => { }); it("should set the child transaction's contact when its shared with the parent", () => { - component.useParentContact = true; component.transaction = testTransaction; component.childTransaction = testTransaction.children?.[0] as SchATransaction; + if (component.childTransaction.transactionType) { + component.childTransaction.transactionType.useParentContact = true; + } const contact = new Contact(); contact.name = 'Name'; @@ -135,21 +148,10 @@ describe('DoubleTransactionTypeBaseComponent', () => { value: contact, }; - component.onContactLookupSelect(selectContact); + component.updateFormWithPrimaryContact(selectContact); expect(component.childTransaction.contact_1?.name).toEqual('Name'); }); - it('positive contribution_amount values should be overriden when the schema requires a negative value', () => { - component.transaction = getTestTransactionByType(ScheduleATransactionTypes.CONDUIT_EARMARK_RECEIPT_DEPOSITED); - const childTransaction = getTestTransactionByType(ScheduleATransactionTypes.RETURNED_BOUNCED_RECEIPT_INDIVIDUAL); - childTransaction.parent_transaction = component.transaction; - component.transaction.children = [childTransaction]; - component.ngOnInit(); - - component.childForm.patchValue({ contribution_amount: 2 }); - expect(component.childForm.get('contribution_amount')?.value).toBe(-2); - }); - it("should auto-generate the child transaction's purpose description", () => { component.transaction = getTestTransactionByType(ScheduleATransactionTypes.CONDUIT_EARMARK_RECEIPT_DEPOSITED); const childTransaction = getTestTransactionByType(ScheduleBTransactionTypes.CONDUIT_EARMARK_OUT_DEPOSITED); @@ -176,16 +178,15 @@ describe('DoubleTransactionTypeBaseComponent', () => { }); it('should save a parent and child transaction', () => { - const componentNavigateToSpy = spyOn(testConfirmationService, 'confirm'); + const apiPostSpy = spyOn(transactionService, 'create').and.returnValue(of(testTransaction)); + spyOn(testRouter, 'navigateByUrl').and.callFake(() => Promise.resolve(true)); if (testTransaction.children) { component.childTransaction = testTransaction.children[0]; component.childTransaction.parent_transaction = component.transaction; } - // Save invalid form values const navEvent = new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, component.transaction); - component.save(navEvent); // Save valid form values component.form.patchValue({ @@ -232,7 +233,7 @@ describe('DoubleTransactionTypeBaseComponent', () => { memo_code: true, text4000: '', }); - component.save(navEvent); - expect(componentNavigateToSpy).toHaveBeenCalledTimes(1); + component.handleNavigate(navEvent); + expect(apiPostSpy).toHaveBeenCalledTimes(1); }); }); diff --git a/front-end/src/app/shared/components/transaction-type-base/double-transaction-type-base.component.ts b/front-end/src/app/shared/components/transaction-type-base/double-transaction-type-base.component.ts index 83db78abdc..31a3800a64 100644 --- a/front-end/src/app/shared/components/transaction-type-base/double-transaction-type-base.component.ts +++ b/front-end/src/app/shared/components/transaction-type-base/double-transaction-type-base.component.ts @@ -1,21 +1,22 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { NavigationEvent } from 'app/shared/models/transaction-navigation-controls.model'; +import { NavigationAction, NavigationEvent } from 'app/shared/models/transaction-navigation-controls.model'; import { TemplateMapKeyType, TransactionTemplateMapType, TransactionType, } from 'app/shared/models/transaction-type.model'; -import { ScheduleTransaction, Transaction } from 'app/shared/models/transaction.model'; +import { Transaction } from 'app/shared/models/transaction.model'; import { LabelUtils, PrimeOptions } from 'app/shared/utils/label.utils'; import { getContactTypeOptions } from 'app/shared/utils/transaction-type-properties'; import { ValidateUtils } from 'app/shared/utils/validate.utils'; import { SelectItem } from 'primeng/api'; -import { BehaviorSubject, Subject, of, takeUntil } from 'rxjs'; +import { concat, of, reduce } from 'rxjs'; import { Contact, ContactTypeLabels } from '../../models/contact.model'; -import { TransactionContactUtils } from './transaction-contact.utils'; +import { ContactIdMapType, TransactionContactUtils } from './transaction-contact.utils'; import { TransactionFormUtils } from './transaction-form.utils'; import { TransactionTypeBaseComponent } from './transaction-type-base.component'; +import { TransactionChildFormUtils } from './transaction-child-form.utils'; /** * This component is to help manage a form that contains 2 transactions that the @@ -23,10 +24,7 @@ import { TransactionTypeBaseComponent } from './transaction-type-base.component' * * The primany transaction code is inherited from the TransactionTypeBaseComponent. This * abstract component class adds a child transaction that is defined in the parent - * transaction's TransactionType class. (e.g. TransactionType.childTransactionType) - * - * See the transaction-group-ag component for an example of how to implement a - * two-transaction input form. + * transaction's TransactionType class. */ @Component({ template: '', @@ -40,10 +38,8 @@ export abstract class DoubleTransactionTypeBaseComponent childTransaction?: Transaction; childContactTypeOptions: PrimeOptions = LabelUtils.getPrimeOptions(ContactTypeLabels); childForm: FormGroup = this.fb.group({}); - childContactId$: Subject = new BehaviorSubject(''); - childPurposeDescriptionLabel = ''; + childContactIdMap: ContactIdMapType = {}; childTemplateMap: TransactionTemplateMapType = {} as TransactionTemplateMapType; - useParentContact = false; childMemoCodeCheckboxLabel$ = of(''); override ngOnInit(): void { @@ -51,139 +47,75 @@ export abstract class DoubleTransactionTypeBaseComponent super.ngOnInit(); // Initialize child form. - this.childTransaction = (this.transaction?.children ?? [])[0]; + if (this.transaction) { + this.childTransaction = this.getChildTransaction(this.transaction, 0); + } else { + throw new Error('Fecfile: Transaction not found for double-entry transaction form'); + } + if (!this.childTransaction) { + throw new Error('Fecfile: Child transaction not found for double-entry transaction form'); + } this.childTransactionType = this.childTransaction?.transactionType; if (!this.childTransactionType?.templateMap) { - throw new Error('Fecfile: Template map not found for double transaction component'); + throw new Error('Fecfile: Template map not found for double transaction double-entry transaction form'); } this.childTemplateMap = this.childTransactionType.templateMap; this.childContactTypeOptions = getContactTypeOptions(this.childTransactionType.contactTypeOptions ?? []); - this.childFormProperties = this.childTransactionType.getFormControlNames(this.childTemplateMap); + this.childFormProperties = this.childTransactionType.getFormControlNames(); this.childForm = this.fb.group(ValidateUtils.getFormGroupFields(this.childFormProperties)); if ( - this.childTransactionType?.inheritedFields?.includes( - 'memo_code' as TemplateMapKeyType) && this.transactionType) { + this.childTransactionType?.inheritedFields?.includes('memo_code' as TemplateMapKeyType) && + this.transactionType + ) { this.childMemoCodeCheckboxLabel$ = this.memoCodeCheckboxLabel$; } else { this.childMemoCodeCheckboxLabel$ = this.getMemoCodeCheckboxLabel$(this.childForm, this.childTransactionType); } - TransactionFormUtils.onInit(this, this.childForm, this.childTransaction, this.childContactId$); - this.childOnInit(); - } - - childOnInit() { - // Determine if amount should always be negative and then force it to be so if needed - if (this.childTransactionType?.negativeAmountValueOnly && this.childTemplateMap?.amount) { - this.childForm - .get(this.childTemplateMap.amount) - ?.valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe((amount) => { - if (+amount > 0) { - this.childForm.get(this.childTemplateMap.amount)?.setValue(-1 * amount); - } - }); - } - - if (this.childTransactionType?.generatePurposeDescriptionLabel) { - this.childPurposeDescriptionLabel = this.childTransactionType?.generatePurposeDescriptionLabel(); - } - - // Parent contribution purpose description updates with configured child fields update. - this.transaction?.transactionType?.childTriggerFields?.forEach((triggerField) => { - this.childForm - .get(this.childTemplateMap[triggerField]) - ?.valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe((value) => { - /** Before updating the parent description, manually update the child - * fields because they will not be updated by the time this hook is called - **/ - const key = this.childTemplateMap[triggerField] as keyof ScheduleTransaction; - ((this.childTransaction as ScheduleTransaction)[key] as string) = value; - (this.childTransaction as ScheduleTransaction).entity_type = this.childForm.get('entity_type')?.value; - this.updateParentPurposeDescription(); - }); - }); - - // Child contribution purpose description updates with configured parent fields update. - this.childTransactionType?.parentTriggerFields?.forEach((triggerField) => { - this.form - .get(this.templateMap[triggerField]) - ?.valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe((value) => { - /** Before updating the parent description, manually update the child - * fields because they will not be updated by the time this hook is called - **/ - const key = this.templateMap[triggerField] as keyof ScheduleTransaction; - ((this.transaction as ScheduleTransaction)[key] as string) = value; - (this.transaction as ScheduleTransaction).entity_type = this.form.get('entity_type')?.value; - this.updateChildPurposeDescription(); - }); - }); - - this.useParentContact = !!this.childTransactionType?.useParentContact; - - // Inheritted fields must match parent values - this.childTransactionType?.inheritedFields?.forEach((inherittedField) => { - this.form - .get(this.templateMap[inherittedField]) - ?.valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe((value) => { - this.childForm.get(this.childTemplateMap[inherittedField])?.setValue(value); - }); - this.childForm.get(this.childTemplateMap[inherittedField])?.disable(); - }); - } - - override onContactLookupSelect(selectItem: SelectItem): void { - super.onContactLookupSelect(selectItem); - if (this.useParentContact && this.childTransaction && this.transaction?.contact_1) { - this.childTransaction.contact_1 = this.transaction.contact_1; - this.childForm.get('entity_type')?.setValue(selectItem.value.type); - } + TransactionFormUtils.onInit( + this, + this.childForm, + this.childTransaction, + this.childContactIdMap, + this.contactService + ); + TransactionChildFormUtils.childOnInit(this, this.childForm, this.childTransaction); } override ngOnDestroy(): void { super.ngOnDestroy(); - this.childContactId$.complete(); + Object.values(this.childContactIdMap).forEach((id$) => id$.complete()); } - private updateParentPurposeDescription() { - if (this.transaction?.transactionType?.generatePurposeDescription) { - this.form.patchValue({ - [this.templateMap.purpose_description]: this.transaction.transactionType.generatePurposeDescriptionWrapper( - this.transaction - ), - }); - } - } - - private updateChildPurposeDescription() { - if (this.childTransaction?.transactionType?.generatePurposeDescription) { - this.childForm.patchValue({ - [this.childTemplateMap.purpose_description]: this.childTransactionType?.generatePurposeDescriptionWrapper( - this.childTransaction - ), - }); - } + /** + * For certain transactions, like CONDUIT_EARMARK_OUT, the transaction_type_identifier + * will not match the transaction type model name because it is assigned DEPOSITED + * and UNDEPOSITED variations of the model name for its TTI. We account for that here + * when comparing the child to the transaction types dependent on the parent + * @param transaction + * @param index + * @returns + */ + getChildTransaction(transaction: Transaction, index: number): Transaction | undefined { + return transaction?.children?.filter((child) => { + const transactionTypeId = transaction?.transactionType?.dependentChildTransactionTypes?.[index]; + const transactionTypeIdVariations = [ + transactionTypeId, + `${transactionTypeId}_DEPOSITED`, + `${transactionTypeId}_UNDEPOSITED`, + ]; + return transactionTypeIdVariations.includes(child.transaction_type_identifier); + })[0]; } override save(navigationEvent: NavigationEvent) { - this.formSubmitted = true; - - if (this.form.invalid || this.childForm.invalid) { - return; - } - - // Remove parent transaction links within the parent-child hierarchy in the - // transaction objects to avoid a recursion overflow from the class-transformer - // plainToClass() converter. - if (this.transaction?.children) { - this.transaction.children[0].parent_transaction = undefined; - } - if (this.childTransaction?.parent_transaction) { - this.childTransaction.parent_transaction = undefined; + // update all contacts with changes from form. + if (this.transaction && this.childTransaction) { + TransactionContactUtils.updateContactsWithForm(this.transaction, this.templateMap, this.form); + TransactionContactUtils.updateContactsWithForm(this.childTransaction, this.childTemplateMap, this.childForm); + } else { + throw new Error('Fecfile: No transactions submitted for double-entry transaction form.'); } const payload: Transaction = TransactionFormUtils.getPayloadTransaction( @@ -191,55 +123,107 @@ export abstract class DoubleTransactionTypeBaseComponent this.form, this.formProperties ); + payload.children = [ TransactionFormUtils.getPayloadTransaction(this.childTransaction, this.childForm, this.childFormProperties), ]; payload.children[0].report_id = payload.report_id; - // Confirm save for parent transaction - // No need to confirm child contact changes if it uses the parent contact info - const saveCallback = this.childTransactionType?.useParentContact ? this.doSave : this.childConfirmSave; - this.confirmSave(payload, this.form, saveCallback, navigationEvent, payload); + if (payload.transaction_type_identifier) { + const responseFromApi = this.writeToApi(payload); + responseFromApi.subscribe((transaction) => { + navigationEvent.transaction = this.transactionType?.updateParentOnSave ? payload : transaction; + this.navigateTo(navigationEvent); + }); + } } - private childConfirmSave(navigationEvent: NavigationEvent, payload: Transaction) { - if (payload.children?.length === 1) { - this.confirmSave(payload.children[0], this.childForm, this.doSave, navigationEvent, payload, 'childDialog'); + override handleNavigate(navigationEvent: NavigationEvent): void { + this.formSubmitted = true; + + if (navigationEvent.action === NavigationAction.SAVE) { + if (this.childForm.invalid || this.form.invalid || !this.transaction || !this.childTransaction) { + return; + } + let confirmation$ = this.confirmWithUser(this.transaction, this.form); + confirmation$ = concat( + confirmation$, + this.confirmWithUser(this.childTransaction, this.childForm, 'childDialog') + ).pipe(reduce((accumulator, confirmed) => accumulator && confirmed)); + + confirmation$.subscribe((confirmed: boolean) => { + // if every confirmation was accepted + if (confirmed) this.save(navigationEvent); + }); } else { - throw new Error('Fecfile: Parent transaction missing child transaction when trying to confirm save.'); + this.navigateTo(navigationEvent); } } override resetForm() { - this.formSubmitted = false; - TransactionFormUtils.resetForm(this.form, this.transaction, this.contactTypeOptions); + super.resetForm(); TransactionFormUtils.resetForm(this.childForm, this.childTransaction, this.childContactTypeOptions); } - childOnContactLookupSelect(selectItem: SelectItem) { - TransactionContactUtils.onContactLookupSelect( + override updateFormWithPrimaryContact(selectItem: SelectItem): void { + super.updateFormWithPrimaryContact(selectItem); + if (this.childTransaction?.transactionType?.useParentContact && this.transaction?.contact_1) { + this.childTransaction.contact_1 = this.transaction.contact_1; + this.childForm.get('entity_type')?.setValue(selectItem.value.type); + } + } + + childUpdateFormWithPrimaryContact(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithPrimaryContact( selectItem, this.childForm, this.childTransaction, - this.childContactId$ + this.childContactIdMap['contact_1'] ); + if (this.childTransaction) { + this.updateInheritedFields(this.childForm, this.childTransaction); + } else { + throw new Error('Fecfile: Missing child transaction.'); + } + } + + protected updateInheritedFields(childForm: FormGroup, childTransaction: Transaction): void { // Some inheritted fields (such as memo_code) cannot be set before the components are initialized. // This happens most reliably when the user selects a contact for the child transaction. // Afterwards, inheritted fields are updated to match parent values. - this.childTransactionType?.inheritedFields?.forEach((inherittedField) => { - const childFieldControl = this.childForm.get(this.childTemplateMap[inherittedField]); - childFieldControl?.enable(); - const value = this.form.get(this.templateMap[inherittedField])?.value; - if (value !== undefined) { - childFieldControl?.setValue(value); - childFieldControl?.updateValueAndValidity(); + + childTransaction.transactionType?.inheritedFields?.forEach((inherittedField) => { + if (childTransaction.transactionType) { + const childFieldControl = childForm.get(childTransaction.transactionType.templateMap[inherittedField]); + childFieldControl?.enable(); + const value = this.form.get(this.templateMap[inherittedField])?.value; + if (value !== undefined) { + childFieldControl?.setValue(value); + childFieldControl?.updateValueAndValidity(); + } + childFieldControl?.disable(); + } else { + throw new Error('Fecfile: Transaction missing transactionType.'); } - childFieldControl?.disable(); }); } - childOnSecondaryContactLookupSelect(selectItem: SelectItem) { - TransactionContactUtils.onSecondaryContactLookupSelect(selectItem, this.childForm, this.childTransaction); + childUpdateFormWithCandidateContact(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithCandidateContact( + selectItem, + this.childForm, + this.childTransaction, + this.childContactIdMap['contact_2'] + ); + } + + childUpdateFormWithSecondaryContact(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithSecondaryContact( + selectItem, + this.childForm, + this.childTransaction, + this.childContactIdMap['contact_2'] + ); } } diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-child-form.utils.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-child-form.utils.ts new file mode 100644 index 0000000000..5f5a009fee --- /dev/null +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-child-form.utils.ts @@ -0,0 +1,92 @@ +import { FormGroup } from '@angular/forms'; +import { ScheduleTransaction, Transaction } from 'app/shared/models/transaction.model'; +import { takeUntil } from 'rxjs'; +import { DoubleTransactionTypeBaseComponent } from './double-transaction-type-base.component'; +import { TripleTransactionTypeBaseComponent } from './triple-transaction-type-base.component'; + +function updatePurposeDescription(form: FormGroup, transaction: Transaction) { + if (transaction?.transactionType?.generatePurposeDescription) { + form.patchValue({ + [transaction.transactionType.templateMap.purpose_description]: + transaction.transactionType.generatePurposeDescriptionWrapper(transaction), + }); + } +} + +export class TransactionChildFormUtils { + static childOnInit( + component: DoubleTransactionTypeBaseComponent | TripleTransactionTypeBaseComponent, + childForm: FormGroup, + childTransaction: Transaction + ) { + // Determine if amount should always be negative and then force it to be so if needed + if ( + childTransaction.transactionType?.negativeAmountValueOnly && + childTransaction.transactionType.templateMap?.amount + ) { + childForm + .get(childTransaction.transactionType.templateMap.amount) + ?.valueChanges.pipe(takeUntil(component.destroy$)) + .subscribe((amount) => { + if (+amount > 0 && childTransaction.transactionType) { + childForm.get(childTransaction.transactionType.templateMap.amount)?.setValue(-1 * amount); + } + }); + } + + // Parent contribution purpose description updates with configured child fields update. + component.transaction?.transactionType?.childTriggerFields?.forEach((triggerField) => { + if (childTransaction.transactionType) { + childForm + .get(childTransaction.transactionType.templateMap[triggerField]) + ?.valueChanges.pipe(takeUntil(component.destroy$)) + .subscribe((value) => { + /** Before updating the parent description, manually update the child + * fields because they will not be updated by the time this hook is called + **/ + const key = childTransaction.transactionType?.templateMap[triggerField] as keyof ScheduleTransaction; + ((childTransaction as ScheduleTransaction)[key] as string) = value; + (childTransaction as ScheduleTransaction).entity_type = childForm.get('entity_type')?.value; + if (component.transaction) { + updatePurposeDescription(component.form, component.transaction); + } else { + throw new Error('Fecfile: Parent transaction not found for component'); + } + }); + } + }); + + // Child contribution purpose description updates with configured parent fields update. + childTransaction.transactionType?.parentTriggerFields?.forEach((triggerField) => { + component.form + .get(component.templateMap[triggerField]) + ?.valueChanges.pipe(takeUntil(component.destroy$)) + .subscribe((value) => { + /** Before updating the parent description, manually update the child + * fields because they will not be updated by the time this hook is called + **/ + const key = component.templateMap[triggerField] as keyof ScheduleTransaction; + ((component.transaction as ScheduleTransaction)[key] as string) = value; + (component.transaction as ScheduleTransaction).entity_type = component.form.get('entity_type')?.value; + updatePurposeDescription(childForm, childTransaction); + }); + }); + + // Inheritted fields must match parent values + childTransaction.transactionType?.inheritedFields?.forEach((inherittedField) => { + if (childTransaction.transactionType) { + component.form + .get(component.templateMap[inherittedField]) + ?.valueChanges.pipe(takeUntil(component.destroy$)) + .subscribe((value) => { + if (childTransaction.transactionType) { + childForm.get(childTransaction.transactionType.templateMap[inherittedField])?.setValue(value); + } + }); + childForm.get(childTransaction.transactionType.templateMap[inherittedField])?.disable(); + } else { + throw new Error('Fecfile: Template map not found for transaction component'); + } + }); + } +} diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-contact.utils.spec.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-contact.utils.spec.ts new file mode 100644 index 0000000000..196c768f3d --- /dev/null +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-contact.utils.spec.ts @@ -0,0 +1,163 @@ +import { FormControl, FormGroup } from '@angular/forms'; +import { Contact, ContactTypes } from 'app/shared/models/contact.model'; +import { + testTemplateMap, + testContact, + testScheduleATransaction, + getTestTransactionByType, +} from 'app/shared/utils/unit-test.utils'; +import { TransactionContactUtils } from './transaction-contact.utils'; +import { Subject } from 'rxjs'; +import { SelectItem } from 'primeng/api'; +import { SchC1Transaction, ScheduleC1TransactionTypes } from 'app/shared/models/schc1-transaction.model'; + +describe('ContactUtils', () => { + let form: FormGroup; + let selectItem: SelectItem; + let contactId$: Subject; + + beforeEach(() => { + form = new FormGroup({ + contributor_last_name: new FormControl('test_ln'), + contributor_first_name: new FormControl('test_fn'), + contributor_middle_name: new FormControl(''), + contributor_prefix: new FormControl(''), + contributor_suffix: new FormControl(''), + contributor_street_1: new FormControl(''), + contributor_street_2: new FormControl(''), + contributor_city: new FormControl(''), + contributor_state: new FormControl(''), + contributor_zip: new FormControl(''), + contributor_employer: new FormControl(''), + contributor_occupation: new FormControl(''), + contributor_organization_name: new FormControl('test_org_name'), + donor_candidate_last_name: new FormControl('test_candidate_ln'), + donor_candidate_first_name: new FormControl('test_candidate_fn'), + donor_committee_fec_id: new FormControl(''), + donor_committee_name: new FormControl(''), + donor_candidate_fec_id: new FormControl(''), + donor_candidate_middle_name: new FormControl(''), + donor_candidate_prefix: new FormControl(''), + donor_candidate_suffix: new FormControl(''), + donor_candidate_office: new FormControl(''), + donor_candidate_state: new FormControl(''), + donor_candidate_district: new FormControl(''), + ind_name_account_location: new FormControl(''), + account_street_1: new FormControl(''), + account_street_2: new FormControl(''), + account_city: new FormControl(''), + account_state: new FormControl(''), + account_zip: new FormControl(''), + }); + + selectItem = { + label: '', + value: testContact, + styleClass: '', + icon: '', + title: '', + disabled: false, + }; + + contactId$ = new Subject(); + }); + + it('test getCreateTransactionContactConfirmationMessage', () => { + let output = TransactionContactUtils.getCreateTransactionContactConfirmationMessage( + ContactTypes.INDIVIDUAL, + form, + testTemplateMap, + 'contact_1' + ); + expect(output).toBe( + "By saving this transaction, you're also creating a new individual contact for test_ln, test_fn." + ); + + output = TransactionContactUtils.getCreateTransactionContactConfirmationMessage( + ContactTypes.COMMITTEE, + form, + testTemplateMap, + 'contact_1' + ); + expect(output).toBe( + "By saving this transaction, you're also creating a new committee contact for test_org_name." + ); + + output = TransactionContactUtils.getCreateTransactionContactConfirmationMessage( + ContactTypes.ORGANIZATION, + form, + testTemplateMap, + 'contact_1' + ); + expect(output).toBe( + "By saving this transaction, you're also creating a new organization contact for test_org_name." + ); + + output = TransactionContactUtils.getCreateTransactionContactConfirmationMessage( + ContactTypes.CANDIDATE, + form, + testTemplateMap, + 'contact_2' + ); + expect(output).toBe( + "By saving this transaction, you're also creating a new candidate contact for test_candidate_ln, test_candidate_fn." + ); + }); + + it('test updateFormWithPrimaryContact', () => { + TransactionContactUtils.updateFormWithPrimaryContact(selectItem, form, testScheduleATransaction, contactId$); + expect(form.get('contributor_last_name')?.value).toBe('Smith'); + expect(form.get('contributor_first_name')?.value).toBe('Joe'); + expect(form.get('contributor_middle_name')?.value).toBe('James'); + expect(form.get('contributor_prefix')?.value).toBe('Mr'); + expect(form.get('contributor_suffix')?.value).toBe('Jr'); + expect(form.get('contributor_employer')?.value).toBe('Plumbing, Inc.'); + expect(form.get('contributor_occupation')?.value).toBe('plumber'); + expect(form.get('contributor_street_1')?.value).toBe('123 Main St'); + expect(form.get('contributor_street_2')?.value).toBe('Apt B'); + expect(form.get('contributor_city')?.value).toBe('Anytown'); + expect(form.get('contributor_state')?.value).toBe('VA'); + expect(form.get('contributor_zip')?.value).toBe('22201'); + + selectItem.value.type = ContactTypes.COMMITTEE; + TransactionContactUtils.updateFormWithPrimaryContact(selectItem, form, testScheduleATransaction, contactId$); + expect(form.get('contributor_organization_name')?.value).toBe('Organization LLC'); + expect(form.get('donor_committee_fec_id')?.value).toBe('888'); + expect(form.get('donor_committee_name')?.value).toBe('Organization LLC'); + + selectItem.value.type = ContactTypes.ORGANIZATION; + TransactionContactUtils.updateFormWithPrimaryContact(selectItem, form, testScheduleATransaction, contactId$); + expect(form.get('contributor_organization_name')?.value).toBe('Organization LLC'); + }); + + it('test updateFormWithCandidateContact', () => { + TransactionContactUtils.updateFormWithCandidateContact( + selectItem, + form, + testScheduleATransaction, + new Subject() + ); + expect(form.get('donor_candidate_fec_id')?.value).toBe('999'); + expect(form.get('donor_candidate_last_name')?.value).toBe('Smith'); + expect(form.get('donor_candidate_first_name')?.value).toBe('Joe'); + expect(form.get('donor_candidate_middle_name')?.value).toBe('James'); + expect(form.get('donor_candidate_prefix')?.value).toBe('Mr'); + expect(form.get('donor_candidate_suffix')?.value).toBe('Jr'); + expect(form.get('donor_candidate_office')?.value).toBe('H'); + expect(form.get('donor_candidate_state')?.value).toBe('VA'); + expect(form.get('donor_candidate_district')?.value).toBe('1'); + expect(testScheduleATransaction.contact_2).toBeTruthy(); + }); + + it('test updateFormWithSecondaryContact', () => { + const transaction = getTestTransactionByType(ScheduleC1TransactionTypes.C1_LOAN_AGREEMENT) as SchC1Transaction; + TransactionContactUtils.updateFormWithSecondaryContact(selectItem, form, transaction, new Subject()); + expect(form.get('ind_name_account_location')?.value).toBe('Organization LLC'); + expect(form.get('account_street_1')?.value).toBe('123 Main St'); + expect(form.get('account_street_2')?.value).toBe('Apt B'); + expect(form.get('account_city')?.value).toBe('Anytown'); + expect(form.get('account_state')?.value).toBe('VA'); + expect(form.get('account_zip')?.value).toBe('22201'); + expect(transaction.contact_2).toBeTruthy(); + }); +}); diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-contact.utils.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-contact.utils.ts index 6f45a35b1c..a2e081507d 100644 --- a/front-end/src/app/shared/components/transaction-type-base/transaction-contact.utils.ts +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-contact.utils.ts @@ -1,111 +1,136 @@ -import { AbstractControl, FormGroup } from '@angular/forms'; +import { FormGroup } from '@angular/forms'; import { TransactionTemplateMapType } from 'app/shared/models/transaction-type.model'; import { Transaction } from 'app/shared/models/transaction.model'; -import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; import { SelectItem } from 'primeng/api'; import { Subject } from 'rxjs'; import { Contact, ContactFields, ContactTypes } from '../../models/contact.model'; export class TransactionContactUtils { - static getEditTransactionContactConfirmationMessage( - contactChanges: string[], - contact: Contact | undefined, - form: FormGroup, - fecDatePipe: FecDatePipe, - templateMap: TransactionTemplateMapType - ): string | undefined { - if (contact) { - const changesMessage = 'Change(s):
    '.concat( - ...contactChanges.map((change) => `
  • ${change}
  • `, '
') - ); - let contactName = contact.name; - if (contact.type === ContactTypes.INDIVIDUAL) { - contactName = `${contact.last_name}, ${contact.first_name}`; - contactName += contact.middle_name ? ' ' + contact.middle_name : ''; - } - const dateReceived = fecDatePipe.transform(form.get(templateMap.date)?.value); - return ( - `By saving this transaction, you are also updating the contact for ` + - `${contactName}. This change will only affect transactions with ` + - `receipt date on or after ${dateReceived}.

${changesMessage}` - ); - } - return undefined; - } - + /** + * Generate a message string that alerts the user that a new contact will be created + * when the transaction is saved. + * @param contactType + * @param form + * @param templateMap + * @returns {string} + */ static getCreateTransactionContactConfirmationMessage( contactType: ContactTypes, form: FormGroup, - templateMap: TransactionTemplateMapType + templateMap: TransactionTemplateMapType, + contactKey: string ): string { let confirmationContactTitle = ''; switch (contactType) { case ContactTypes.INDIVIDUAL: - confirmationContactTitle = - `individual contact for ` + - `${form.get(templateMap.last_name)?.value}, ` + - `${form.get(templateMap.first_name)?.value}`; + confirmationContactTitle = `individual contact for ${form.get(templateMap.last_name)?.value}, ${ + form.get(templateMap.first_name)?.value + }`; break; case ContactTypes.COMMITTEE: - confirmationContactTitle = - `committee contact for ` + `${form.get(templateMap.organization_name)?.value}`; + confirmationContactTitle = `committee contact for ${form.get(templateMap.organization_name)?.value}`; break; case ContactTypes.ORGANIZATION: - confirmationContactTitle = - `organization contact for ` + `${form.get(templateMap.organization_name)?.value}`; + confirmationContactTitle = `organization contact for ${ + contactKey === 'contact_2' + ? form.get(templateMap.secondary_name)?.value + : form.get(templateMap.organization_name)?.value + }`; + break; + case ContactTypes.CANDIDATE: + confirmationContactTitle = `candidate contact for ${form.get(templateMap.candidate_last_name)?.value}, ${ + form.get(templateMap.candidate_first_name)?.value + }`; break; } return `By saving this transaction, you're also creating a new ${confirmationContactTitle}.`; } /** - * This method returns the differences between the transaction - * form's contact section and its database contact in prose - * for the UI as a string[] (one entry for each change) after - * first setting these values on the Contact object. - * @returns string[] containing the changes in prose for the UI. + * Given a FormGroup and a Contact object, the method returns an array of data pairs (pairs in an array) + * containing the contact property and the new contact property value from the form. + * @param form + * @param contact + * @param templateMap + * @param contactConfig + * @returns */ - static setTransactionContactFormChanges( + static getContactChanges( form: FormGroup, - contact: Contact | undefined, - templateMap: TransactionTemplateMapType - ): string[] { - function getFormField( - form: FormGroup, - field: string, - templateMap: TransactionTemplateMapType - ): AbstractControl | null { - if (field == 'committee_id') { - return form.get(templateMap.committee_fec_id); - } - if (field == 'name') { - return form.get(templateMap.organization_name); - } - return form.get(templateMap[field as keyof TransactionTemplateMapType]); - } + contact: Contact, + templateMap: TransactionTemplateMapType, + contactConfig: { [formField: string]: string } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ): any[] { + return Object.entries(contactConfig) + .map(([field, property]: string[]) => { + const contactValue = contact[property as keyof Contact]; + const formField = form.get(templateMap[field as keyof TransactionTemplateMapType]); + if (formField && formField?.value !== contactValue) { + return [property, formField.value]; + } + return undefined; + }) + .filter((change) => !!change); + } - if (contact) { - return Object.entries(ContactFields) - .map(([field, label]: string[]) => { - const contactValue = contact[field as keyof typeof contact]; - const value = contactValue === '' ? null : contactValue; // Convert '' to null to match form field values. - const formField = getFormField(form, field, templateMap); + /** + * Build and return the message string to display to the user in the pop-up when + * being alerted that a contact will be updated in the database. + * @param contact + * @param dateString + * @param contactChanges + * @returns + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + static getContactChangesMessage(contact: Contact, dateString: string, contactChanges: [string, any][]) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const changeMessages = contactChanges.map(([property, value]: [string, any]) => { + if (!value) { + return `
  • Removed ${ContactFields[property as keyof typeof ContactFields].toLowerCase()}
  • `; + } + return `
  • Updated ${ContactFields[property as keyof typeof ContactFields].toLowerCase()} to ${value}
  • `; + }); + const changesMessage = 'Change(s):
      '.concat(...changeMessages.join(''), '
    '); + return ( + `By saving this transaction, you are also updating the contact for ` + + `${contact.getNameString()}. This change will only affect transactions with ` + + `receipt date on or after ${dateString}.

    ${changesMessage}` + ); + } - if (formField && formField?.value !== value) { - contact[field as keyof typeof contact] = (formField.value || null) as never; - if (!formField.value) { - return `Removed ${label.toLowerCase()}`; - } - return `Updated ${label.toLowerCase()} to ${formField.value}`; - } - return ''; - }) - .filter((change) => change); - } - return []; + /** + * Loop though the contact records attached to a transaction object (i.e. 'contact_1', 'contact_2', etc) + * and update the contact objects in place with the values entered into the transaction form for that contact. + * @param transaction + * @param templateMap + * @param form + */ + static updateContactsWithForm(transaction: Transaction, templateMap: TransactionTemplateMapType, form: FormGroup) { + Object.entries(transaction.transactionType?.contactConfig ?? {}).forEach( + ([contactKey, config]: [string, { [formField: string]: string }]) => { + if (transaction[contactKey as keyof Transaction]) { + const contact = transaction[contactKey as keyof Transaction] as Contact; + const contactChanges = TransactionContactUtils.getContactChanges(form, contact, templateMap, config); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + contactChanges.forEach(([property, value]: [keyof Contact, any]) => { + contact[property] = value as never; + }); + } + } + ); } - static onContactLookupSelect( + /** + * Update the transaction form values for the first contact form fields (i.e. 'contact_1') + * when a user has selected a contact from the lookup. + * @param selectItem + * @param form + * @param transaction + * @param contactId$ + * @returns + */ + static updateFormWithPrimaryContact( selectItem: SelectItem, form: FormGroup, transaction: Transaction | undefined, @@ -141,13 +166,22 @@ export class TransactionContactUtils { if (transaction) { transaction.contact_1 = contact; } - contactId$.next(contact.id || ''); + contactId$.next(contact.id ?? ''); } - static onSecondaryContactLookupSelect( + /** + * Update the transaction form values for the second CANDIDATE contact form fields (i.e. 'contact_2') + * when a user has selected a contact from a contact lookup on the form. + * @param selectItem + * @param form + * @param transaction + * @returns + */ + static updateFormWithCandidateContact( selectItem: SelectItem, form: FormGroup, - transaction: Transaction | undefined + transaction: Transaction | undefined, + contactId$: Subject ) { const contact: Contact = selectItem?.value; const templateMap = transaction?.transactionType?.templateMap; @@ -164,5 +198,37 @@ export class TransactionContactUtils { if (transaction) { transaction.contact_2 = contact; } + contactId$.next(contact.id ?? ''); + } + + /** + * Update the transaction form values for the SECONDARY contact form fields (i.e. 'contact_2') + * when a user has selected a contact from a contact lookup on the form. + * @param selectItem + * @param form + * @param transaction + * @returns + */ + static updateFormWithSecondaryContact( + selectItem: SelectItem, + form: FormGroup, + transaction: Transaction | undefined, + contactId$: Subject + ) { + const contact: Contact = selectItem?.value; + const templateMap = transaction?.transactionType?.templateMap; + if (!(contact && templateMap)) return; + form.get(templateMap.secondary_name)?.setValue(contact.name); + form.get(templateMap.secondary_street_1)?.setValue(contact.street_1); + form.get(templateMap.secondary_street_2)?.setValue(contact.street_2); + form.get(templateMap.secondary_city)?.setValue(contact.city); + form.get(templateMap.secondary_state)?.setValue(contact.state); + form.get(templateMap.secondary_zip)?.setValue(contact.zip); + if (transaction) { + transaction.contact_2 = contact; + } + contactId$.next(contact.id ?? ''); } } + +export type ContactIdMapType = { [contact: string]: Subject }; diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-form.utils.spec.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-form.utils.spec.ts index 3341c34cf7..06a95634ea 100644 --- a/front-end/src/app/shared/components/transaction-type-base/transaction-form.utils.spec.ts +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-form.utils.spec.ts @@ -1,79 +1,77 @@ import { FormControl, FormGroup } from '@angular/forms'; import { SchATransaction, ScheduleATransactionTypes } from 'app/shared/models/scha-transaction.model'; import { SchBTransaction, ScheduleBTransactionTypes } from 'app/shared/models/schb-transaction.model'; -import { TransactionTemplateMapType } from 'app/shared/models/transaction-type.model'; import { AggregationGroups } from 'app/shared/models/transaction.model'; import { TransactionFormUtils } from './transaction-form.utils'; describe('FormUtils', () => { const t = new TransactionFormUtils(); - describe('FormType', () => { - it('should be truthy', () => { - expect(t).toBeTruthy(); - }); - - it('should add the amount for not-refunds', () => { - const form = new FormGroup({ - contribution_amount: new FormControl(), - contribution_aggregate: new FormControl(), - expenditure_amount: new FormControl(), - }); - const transaction = SchATransaction.fromJSON({ - transaction_type_identifier: ScheduleATransactionTypes.TRIBAL_NATIONAL_PARTY_CONVENTION_ACCOUNT, - aggregation_group: AggregationGroups.NATIONAL_PARTY_CONVENTION_ACCOUNT, - contribution_amount: 50, - }); + it('should be truthy', () => { + expect(t).toBeTruthy(); + }); - const previous_transaction = SchATransaction.fromJSON({ - transaction_type_identifier: ScheduleATransactionTypes.TRIBAL_NATIONAL_PARTY_CONVENTION_ACCOUNT, - aggregation_group: AggregationGroups.NATIONAL_PARTY_CONVENTION_ACCOUNT, - contribution_amount: 100, - contribution_aggregate: 100, - }); + it('should add the amount for not-refunds', () => { + const form = new FormGroup({ + contribution_amount: new FormControl(), + contribution_aggregate: new FormControl(), + expenditure_amount: new FormControl(), + }); - TransactionFormUtils.updateAggregate( - form, - transaction.transactionType?.templateMap as TransactionTemplateMapType, - transaction, - previous_transaction, - transaction.contribution_amount as number - ); + const transaction = SchATransaction.fromJSON({ + transaction_type_identifier: ScheduleATransactionTypes.TRIBAL_NATIONAL_PARTY_CONVENTION_ACCOUNT, + aggregation_group: AggregationGroups.NATIONAL_PARTY_CONVENTION_ACCOUNT, + contribution_amount: 50, + }); - const aggregateFormControl = form.get('contribution_aggregate') as FormControl; - expect(aggregateFormControl.value).toEqual(150); + const previous_transaction = SchATransaction.fromJSON({ + transaction_type_identifier: ScheduleATransactionTypes.TRIBAL_NATIONAL_PARTY_CONVENTION_ACCOUNT, + aggregation_group: AggregationGroups.NATIONAL_PARTY_CONVENTION_ACCOUNT, + contribution_amount: 100, + contribution_aggregate: 100, }); - it('should add the amount for refunds', () => { - const form = new FormGroup({ - contribution_amount: new FormControl(), - aggregate_amount: new FormControl(), - expenditure_amount: new FormControl(), - }); + TransactionFormUtils.updateAggregate( + form, + transaction.transactionType.templateMap, + transaction, + previous_transaction, + transaction.contribution_amount as number + ); - const transaction = SchBTransaction.fromJSON({ - transaction_type_identifier: ScheduleBTransactionTypes.TRIBAL_REFUND_NP_CONVENTION_ACCOUNT, - aggregation_group: AggregationGroups.NATIONAL_PARTY_CONVENTION_ACCOUNT, - expenditure_amount: 50, - }); + const aggregateFormControl = form.get('contribution_aggregate') as FormControl; + expect(aggregateFormControl.value).toEqual(150); + }); - const previous_transaction = SchATransaction.fromJSON({ - transaction_type_identifier: ScheduleATransactionTypes.TRIBAL_NATIONAL_PARTY_CONVENTION_ACCOUNT, - aggregation_group: AggregationGroups.NATIONAL_PARTY_CONVENTION_ACCOUNT, - contribution_amount: 100, - contribution_aggregate: 100, - }); + it('should add the amount for refunds', () => { + const form = new FormGroup({ + contribution_amount: new FormControl(), + aggregate_amount: new FormControl(), + expenditure_amount: new FormControl(), + }); - TransactionFormUtils.updateAggregate( - form, - transaction.transactionType?.templateMap as TransactionTemplateMapType, - transaction, - previous_transaction, - transaction.expenditure_amount as number - ); + const transaction = SchBTransaction.fromJSON({ + transaction_type_identifier: ScheduleBTransactionTypes.TRIBAL_REFUND_NP_CONVENTION_ACCOUNT, + aggregation_group: AggregationGroups.NATIONAL_PARTY_CONVENTION_ACCOUNT, + expenditure_amount: 50, + }); - const aggregateFormControl = form.get('aggregate_amount') as FormControl; - expect(aggregateFormControl.value).toEqual(50); + const previous_transaction = SchATransaction.fromJSON({ + transaction_type_identifier: ScheduleATransactionTypes.TRIBAL_NATIONAL_PARTY_CONVENTION_ACCOUNT, + aggregation_group: AggregationGroups.NATIONAL_PARTY_CONVENTION_ACCOUNT, + contribution_amount: 100, + contribution_aggregate: 100, }); + + TransactionFormUtils.updateAggregate( + form, + transaction.transactionType.templateMap, + transaction, + previous_transaction, + transaction.expenditure_amount as number + ); + + const aggregateFormControl = form.get('aggregate_amount') as FormControl; + expect(aggregateFormControl.value).toEqual(50); }); }); diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-form.utils.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-form.utils.ts index ebfc625978..d92284000d 100644 --- a/front-end/src/app/shared/components/transaction-type-base/transaction-form.utils.ts +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-form.utils.ts @@ -1,4 +1,4 @@ -import { FormGroup } from '@angular/forms'; +import { FormGroup, FormControl } from '@angular/forms'; import { SchATransaction } from 'app/shared/models/scha-transaction.model'; import { TransactionTemplateMapType, TransactionType } from 'app/shared/models/transaction-type.model'; import { ScheduleTransaction, Transaction } from 'app/shared/models/transaction.model'; @@ -6,11 +6,13 @@ import { PrimeOptions } from 'app/shared/utils/label.utils'; import { getFromJSON } from 'app/shared/utils/transaction-type.utils'; import { ValidateUtils } from 'app/shared/utils/validate.utils'; import { combineLatestWith, Observable, of, startWith, Subject, switchMap, takeUntil } from 'rxjs'; -import { ContactTypes } from '../../models/contact.model'; +import { Contact, ContactTypes } from '../../models/contact.model'; import { DoubleTransactionTypeBaseComponent } from './double-transaction-type-base.component'; -import { TransactionContactUtils } from './transaction-contact.utils'; +import { TripleTransactionTypeBaseComponent } from './triple-transaction-type-base.component'; import { TransactionMemoUtils } from './transaction-memo.utils'; import { TransactionTypeBaseComponent } from './transaction-type-base.component'; +import { ContactIdMapType } from './transaction-contact.utils'; +import { ContactService } from 'app/shared/services/contact.service'; export class TransactionFormUtils { /** @@ -21,32 +23,36 @@ export class TransactionFormUtils { * @param component * @param form - parent or child (i.e. form or childForm) * @param transaction - parent or child - * @param contactId$ - parent or child (i.e. contactId$ or childContactId$) + * @param contactIdMap - parent or child */ static onInit( - component: TransactionTypeBaseComponent | DoubleTransactionTypeBaseComponent, + component: TransactionTypeBaseComponent | DoubleTransactionTypeBaseComponent | TripleTransactionTypeBaseComponent, form: FormGroup, transaction: Transaction | undefined, - contactId$: Subject + contactIdMap: ContactIdMapType, + contactService: ContactService ): void { if (transaction && transaction.id) { form.patchValue({ ...transaction }); TransactionMemoUtils.patchMemoText(transaction, form); - form.get('entity_type')?.disable(); - contactId$.next(transaction.contact_1_id || ''); } else { component.resetForm(); form.get('entity_type')?.enable(); - contactId$.next(''); } - const templateMap = transaction?.transactionType?.templateMap; - if (!templateMap) { + const transactionType = transaction?.transactionType; + const templateMap = transactionType?.templateMap; + if (!transactionType || !templateMap) { throw new Error('Fecfile: Cannot find template map when initializing transaction form'); } + Object.keys(transactionType.contactConfig ?? {}).forEach((contact) => { + contactIdMap[contact] = new Subject(); + contactIdMap[contact].next((transaction[contact as keyof Transaction] as Contact)?.id ?? ''); + }); + form .get('entity_type') ?.valueChanges.pipe(takeUntil(component.destroy$)) @@ -83,11 +89,11 @@ export class TransactionFormUtils { }); } - if (transaction.transactionType?.showAggregate) { + if (transactionType.showAggregate) { const previous_transaction$: Observable = form.get(templateMap.date)?.valueChanges.pipe( startWith(form.get(templateMap.date)?.value), - combineLatestWith(contactId$), + combineLatestWith(contactIdMap['contact_1']), switchMap(([contribution_date, contactId]) => { return component.transactionService.getPreviousTransaction(transaction, contactId, contribution_date); }) @@ -104,10 +110,36 @@ export class TransactionFormUtils { }); } + // Add form controls to bubble up validate error messages from the Contact Lookup component + form.addControl('contact_1', new FormControl()); + form.addControl( + 'contact_2', + new FormControl(null, () => { + if (!transaction?.contact_2 && transaction.transactionType?.contact2IsRequired) { + return { required: true }; + } + return null; + }) + ); + const schema = transaction.transactionType?.schema; if (schema) { ValidateUtils.addJsonSchemaValidators(form, schema, false, transaction); } + + Object.entries(contactIdMap).forEach(([contact, id$]) => { + const contactConfig = transactionType.contactConfig[contact]; + id$.pipe(takeUntil(component.destroy$)).subscribe((id) => { + for (const field of ['committee_fec_id', 'candidate_fec_id']) { + if (contactConfig[field]) { + form.get(templateMap[field as keyof TransactionTemplateMapType])?.clearAsyncValidators(); + form + .get(templateMap[field as keyof TransactionTemplateMapType]) + ?.addAsyncValidators(contactService.getFecIdValidator(id)); + } + } + }); + }); } static updateAggregate( @@ -135,29 +167,53 @@ export class TransactionFormUtils { throw new Error('Fecfile: Payload transaction not found'); } + // Remove parent transaction links within the parent-child hierarchy in the + // transaction objects to avoid a recursion overflow from the class-transformer + // plainToClass() converter + if (transaction?.children) { + transaction.children.forEach((child) => { + child.parent_transaction = undefined; + }); + } + let formValues = ValidateUtils.getFormValues(form, transaction.transactionType?.schema, formProperties); formValues = TransactionMemoUtils.retrieveMemoText(transaction, form, formValues); - if (transaction.transactionType?.templateMap) { - // Update contact object in transaction with new form values - TransactionContactUtils.setTransactionContactFormChanges( - form, - transaction.contact_1, - transaction.transactionType.templateMap - ); - } + formValues = TransactionFormUtils.addExtraFormFields(transaction, form, formValues); - const payload: ScheduleTransaction = getFromJSON({ + let payload: ScheduleTransaction = getFromJSON({ ...transaction, ...formValues, }); - if (payload.children) { payload.children = payload.updateChildren(); } - + // Reorganize the payload if this transaction type can update its parent transaction + // This will break the scenario where the user creates a grandparent, then child, then tries + // to create a grandchild transaction because we won't know which child transaction of the grandparent + // was the original transaction it's id was generated on the api. the middle child's + // id is necessary to generate the url for creating the grandchild. + if (transaction.transactionType?.updateParentOnSave) { + payload = payload.getUpdatedParent() as ScheduleTransaction; + } return payload; } + /** + * Some form fields are not part of the FEC spec but internal state variables for the front-end. Add them to the payload. + * @param form + * @param transaction + * @param contactTypeOptions + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + static addExtraFormFields(transaction: Transaction, form: FormGroup, formValues: any) { + transaction.transactionType?.formFields.forEach((field) => { + if (!(field in formValues)) { + formValues[field] = form.get(field)?.value ?? null; + } + }); + return formValues; + } + static resetForm(form: FormGroup, transaction: Transaction | undefined, contactTypeOptions: PrimeOptions) { form.reset(); form.markAsPristine(); @@ -188,5 +244,4 @@ export class TransactionFormUtils { // Memo Code is read-only if there is a constant value in the schema. Otherwise, it's mutable return TransactionFormUtils.getMemoCodeConstant(transactionType) !== undefined; } - } diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.spec.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.spec.ts index 18b55e84ab..5d5a16e4b6 100644 --- a/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.spec.ts +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.spec.ts @@ -1,794 +1,93 @@ import { DatePipe } from '@angular/common'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { Router } from '@angular/router'; +import { FormBuilder } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; import { provideMockStore } from '@ngrx/store/testing'; -import { CandidateOfficeTypes, Contact, ContactTypes } from 'app/shared/models/contact.model'; -import { MemoText } from 'app/shared/models/memo-text.model'; import { NavigationAction, NavigationDestination, NavigationEvent, } from 'app/shared/models/transaction-navigation-controls.model'; -import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; -import { ApiService } from 'app/shared/services/api.service'; import { TransactionService } from 'app/shared/services/transaction.service'; -import { - getTestTransactionByType, - testIndividualReceipt, - testMockStore, - testScheduleATransaction, -} from 'app/shared/utils/unit-test.utils'; -import { Confirmation, ConfirmationService, Message, MessageService, SelectItem } from 'primeng/api'; +import { testIndividualReceipt, testMockStore, getTestTransactionByType } from 'app/shared/utils/unit-test.utils'; +import { Confirmation, ConfirmationService, MessageService } from 'primeng/api'; import { of } from 'rxjs'; import { SchATransaction, ScheduleATransactionTypes } from '../../models/scha-transaction.model'; -import { TransactionContactUtils } from './transaction-contact.utils'; -import { TransactionMemoUtils } from './transaction-memo.utils'; import { TransactionTypeBaseComponent } from './transaction-type-base.component'; - -class TestTransactionTypeBaseComponent extends TransactionTypeBaseComponent { - override formProperties: string[] = [ - 'entity_type', - 'contributor_organization_name', - 'contributor_last_name', - 'contributor_first_name', - 'contributor_middle_name', - 'contributor_prefix', - 'contributor_suffix', - 'contributor_street_1', - 'contributor_street_2', - 'contributor_city', - 'contributor_state', - 'contributor_zip', - 'contributor_employer', - 'contributor_occupation', - 'donor_committee_fec_id', - 'donor_committee_name', - 'donor_candidate_fec_id', - 'donor_candidate_last_name', - 'donor_candidate_first_name', - 'donor_candidate_middle_name', - 'donor_candidate_prefix', - 'donor_candidate_suffix', - 'donor_candidate_office', - 'donor_candidate_state', - 'donor_candidate_district', - 'contribution_date', - 'contribution_amount', - 'contribution_aggregate', - 'contribution_purpose_descrip', - 'memo_code', - 'text4000', - ]; -} - -const initTransactionData = { - id: undefined, - report_id: undefined, - contact: undefined, - contact_1_id: undefined, - form_type: undefined, - transaction_id: null, - transaction_type_identifier: ScheduleATransactionTypes.INDIVIDUAL_RECEIPT, - contribution_purpose_descrip: undefined, - parent_transaction_id: undefined, - children: undefined, - parent_transaction: undefined, - fields_to_validate: undefined, - itemized: false, - memo_text: MemoText.fromJSON({ text4000: 'Memo!' }), - memo_text_id: 'ID Goes Here', -}; +import { TransactionDetailComponent } from 'app/reports/transactions/transaction-detail/transaction-detail.component'; +import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; let testTransaction: SchATransaction; describe('TransactionTypeBaseComponent', () => { - let component: TestTransactionTypeBaseComponent; - let fixture: ComponentFixture; - let testMessageService: MessageService; - let testRouter: Router; - let testTransactionService: TransactionService; - let testApiService: ApiService; + let component: TransactionTypeBaseComponent; + let fixture: ComponentFixture; let testConfirmationService: ConfirmationService; - let fecDatePipe: FecDatePipe; + + //spys + let navigateToSpy: jasmine.Spy; + let transactionServiceSpy: jasmine.SpyObj; + let confirmSpy: jasmine.Spy; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [TestTransactionTypeBaseComponent], + declarations: [TransactionDetailComponent], imports: [RouterTestingModule, HttpClientTestingModule], providers: [ DatePipe, MessageService, FormBuilder, - TransactionService, + { + provide: TransactionService, + useValue: jasmine.createSpyObj('TransactionService', { + update: of(undefined), + create: of(undefined), + getPreviousTransaction: of(undefined), + }), + }, ConfirmationService, provideMockStore(testMockStore), FecDatePipe, ], }).compileComponents(); - testMessageService = TestBed.inject(MessageService); - testRouter = TestBed.inject(Router); - testTransactionService = TestBed.inject(TransactionService); - testApiService = TestBed.inject(ApiService); + transactionServiceSpy = TestBed.inject(TransactionService) as jasmine.SpyObj; testConfirmationService = TestBed.inject(ConfirmationService); - fecDatePipe = TestBed.inject(FecDatePipe); - }); - beforeEach(() => { testTransaction = testIndividualReceipt; - fixture = TestBed.createComponent(TestTransactionTypeBaseComponent); + fixture = TestBed.createComponent(TransactionDetailComponent); component = fixture.componentInstance; component.transaction = testTransaction; fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('#retrieveMemoText should work', () => { - if (!component.transaction) throw new Error('Fecfile: transaction does not exist'); - component.form = new FormGroup({ - text4000: new FormControl('memo'), - }); - const formValues = TransactionMemoUtils.retrieveMemoText(component.transaction, component.form, {}); - expect(formValues['memo_text']['text4000']).toBe('memo'); - }); - - function addContact(component: TestTransactionTypeBaseComponent, contact: Contact) { - if (component.transaction) { - component.transaction.contact_1 = contact; - TransactionContactUtils.onContactLookupSelect( - { value: contact }, - component.form, - component.transaction, - component.contactId$ - ); - } - } - - it('#save should update IND contact', () => { - const testTransaction1: SchATransaction = SchATransaction.fromJSON(initTransactionData); - const testContact: Contact = new Contact(); - testContact.id = 'testId'; - testContact.type = ContactTypes.INDIVIDUAL; - testContact.last_name = 'testLn1'; - testContact.first_name = 'testFn1'; - testContact.middle_name = 'testMn1'; - testContact.prefix = 'testPrefix1'; - testContact.suffix = 'testSuffix1'; - testContact.employer = 'testEmployer1'; - testContact.occupation = 'testOccupation1'; - testContact.street_1 = 'testStreet1'; - testContact.street_2 = 'testStreet2'; - testContact.city = 'testCity1'; - testContact.state = 'VA'; - testContact.zip = '12345'; - spyOn(testApiService, 'post').and.returnValue(of(testContact)); - spyOn(testTransactionService, 'update').and.returnValue(of(testTransaction1)); - const confirmSpy = spyOn(testConfirmationService, 'confirm'); - // test reject - confirmSpy.and.callFake((confirmation: Confirmation) => { - if (confirmation.reject) { - return confirmation.reject(); - } - }); - - const componentNavigateToSpy = spyOn(component, 'navigateTo'); - component.transaction = testTransaction; - - addContact(component, testContact); - const listSaveEvent = new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, testTransaction1); - component.save(listSaveEvent); - confirmSpy.and.callFake((confirmation: Confirmation) => { - if (confirmation.accept) { - return confirmation.accept(); - } - }); - component.form = new FormGroup([]); - component.save(listSaveEvent); - const testContact2 = new Contact(); - testContact2.type = ContactTypes.INDIVIDUAL; - testContact2.id = 'testId'; - if (component.transaction) { - component.transaction.contact_1 = testContact2; - } - component.save(listSaveEvent); - if (component.transaction) { - component.transaction.contact_1 = undefined; - } - if (testTransaction.transactionType) { - TransactionContactUtils.getEditTransactionContactConfirmationMessage( - [], - testContact, - component.form, - fecDatePipe, - testTransaction.transactionType?.templateMap - ); - } - expect(componentNavigateToSpy).toHaveBeenCalledTimes(3); - }); - - function spyOnServices(contact: Contact, transaction: SchATransaction) { - spyOn(testApiService, 'post').and.returnValue(of(contact)); - spyOn(testTransactionService, 'update').and.returnValue(of(transaction)); - spyOn(testConfirmationService, 'confirm').and.callFake((confirmation: Confirmation) => { - if (confirmation.accept) { - return confirmation.accept(); - } - }); - } - - it('#save should update COM contact', () => { - const testTransaction1: SchATransaction = SchATransaction.fromJSON(initTransactionData); - const testContact: Contact = new Contact(); - testContact.id = 'testId'; - testContact.type = ContactTypes.COMMITTEE; - testContact.committee_id = 'C12345679'; - testContact.name = 'testName1'; - - spyOnServices(testContact, testTransaction1); - - const componentNavigateToSpy = spyOn(component, 'navigateTo'); - component.transaction = testTransaction; - - addContact(component, testContact); - const listSaveEvent = new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, testTransaction1); - component.save(listSaveEvent); - component.form = new FormGroup([]); - component.form.addControl('donor_committee_fec_id', new FormControl('test')); - component.save(listSaveEvent); - const testContact2 = new Contact(); - testContact2.type = ContactTypes.COMMITTEE; - testContact2.id = 'testId'; - if (component.transaction) { - component.transaction.contact_1 = testContact2; - } - component.save(listSaveEvent); - expect(componentNavigateToSpy).toHaveBeenCalledTimes(3); + navigateToSpy = spyOn(component, 'navigateTo'); + confirmSpy = spyOn(testConfirmationService, 'confirm'); }); - it('#save should update ORG contact', () => { - const testTransaction1: SchATransaction = SchATransaction.fromJSON(initTransactionData); - const orgContact: Contact = new Contact(); - orgContact.id = 'testId'; - orgContact.type = ContactTypes.ORGANIZATION; - orgContact.name = 'testName1'; - - spyOnServices(orgContact, testTransaction1); - - const componentNavigateToSpy = spyOn(component, 'navigateTo'); - component.transaction = testTransaction; - - addContact(component, orgContact); - const listSaveEvent = new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, testTransaction1); - component.save(listSaveEvent); - component.form = new FormGroup([]); - component.save(listSaveEvent); - const orgContact2 = new Contact(); - orgContact2.type = ContactTypes.ORGANIZATION; - orgContact2.id = 'testId'; - if (component.transaction) { - component.transaction.contact_1 = orgContact2; - } - component.save(listSaveEvent); - expect(componentNavigateToSpy).toHaveBeenCalledTimes(3); + it('should initialize Individual Receipt', () => { + expect(component).toBeTruthy(); + expect(component.transactionType?.title).toBe('Individual Receipt'); }); - it('#save should update CAN contact', () => { - const testTransaction1: SchATransaction = SchATransaction.fromJSON(initTransactionData); - const testContact: Contact = new Contact(); - testContact.id = 'testId'; - testContact.type = ContactTypes.CANDIDATE; - testContact.last_name = 'testLn1'; - testContact.first_name = 'testFn1'; - testContact.middle_name = 'testMn1'; - testContact.prefix = 'testPrefix1'; - testContact.suffix = 'testSuffix1'; - testContact.employer = 'testEmployer1'; - testContact.occupation = 'testOccupation1'; - testContact.street_1 = 'testStreet1'; - testContact.street_2 = 'testStreet2'; - testContact.city = 'testCity1'; - testContact.state = 'VA'; - testContact.zip = '12345'; - - spyOn(testApiService, 'post').and.returnValue(of(testContact)); - spyOn(testTransactionService, 'update').and.returnValue(of(testTransaction1)); - const confirmSpy = spyOn(testConfirmationService, 'confirm'); - // test reject - confirmSpy.and.callFake((confirmation: Confirmation) => { - if (confirmation.reject) { - return confirmation.reject(); - } - }); - - const componentNavigateToSpy = spyOn(component, 'navigateTo'); - component.transaction = testTransaction; - - addContact(component, testContact); - const listSaveEvent = new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, testTransaction1); - component.save(listSaveEvent); + it('should save on save event', fakeAsync(() => { + if (component.transaction) transactionServiceSpy.update.and.returnValue(of(component.transaction)); confirmSpy.and.callFake((confirmation: Confirmation) => { - if (confirmation.accept) { - return confirmation.accept(); - } - }); - component.save(listSaveEvent); - component.form = new FormGroup([]); - component.save(listSaveEvent); - const testContact2 = new Contact(); - testContact2.type = ContactTypes.CANDIDATE; - testContact2.id = 'testId'; - if (component.transaction) { - component.transaction.contact_1 = testContact2; - } - component.save(listSaveEvent); - if (component.transaction) { - component.transaction.contact_1 = undefined; - } - if (testTransaction.transactionType) { - TransactionContactUtils.getEditTransactionContactConfirmationMessage( - [], - testContact, - component.form, - fecDatePipe, - testTransaction.transactionType?.templateMap - ); - } - expect(componentNavigateToSpy).toHaveBeenCalledTimes(3); - }); - - it('#save should navigate for create', () => { - const testTransaction1: SchATransaction = SchATransaction.fromJSON(initTransactionData); - const testContact: Contact = new Contact(); - testContact.id = 'testId'; - - spyOnServices(testContact, testTransaction1); - - const componentNavigateToSpy = spyOn(component, 'navigateTo'); - component.transaction = testTransaction; - - component.save(new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, testTransaction1)); - expect(componentNavigateToSpy).toHaveBeenCalledTimes(1); - }); - - it('#save should navigate for update', fakeAsync(() => { - const testTransaction2: SchATransaction = SchATransaction.fromJSON(initTransactionData); - testTransaction2.id = '123'; - const testContact: Contact = new Contact(); - testContact.id = 'testId'; - spyOn(testApiService, 'post').and.returnValue(of(testContact)); - const updateSpy = spyOn(testTransactionService, 'update'); - updateSpy.and.returnValue(of(testTransaction2)); - spyOn(testConfirmationService, 'confirm').and.callFake((confirmation: Confirmation) => { - if (confirmation.accept) { - return confirmation.accept(); - } + if (confirmation.accept) return confirmation?.accept(); }); - - const componentNavigateToSpy = spyOn(component, 'navigateTo'); - component.transaction = testTransaction; - - component.save(new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, testTransaction2)); - tick(1000); - expect(componentNavigateToSpy).toHaveBeenCalledTimes(1); - expect(updateSpy).toHaveBeenCalled(); + expect(component.form.invalid).toBeFalse(); + const listSaveEvent = new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, component.transaction); + component.handleNavigate(listSaveEvent); + tick(500); + expect(transactionServiceSpy.update).toHaveBeenCalled(); + expect(navigateToSpy).toHaveBeenCalled(); })); - it('#navigateTo NavigationDestination.ANOTHER should show popup', () => { - const expectedMessage: Message = { - severity: 'success', - summary: 'Successful', - detail: 'Transaction Saved', - life: 3000, - }; - const messageServiceAddSpy = spyOn(testMessageService, 'add'); - spyOn(testRouter, 'navigateByUrl').and.callFake(() => Promise.resolve(true)); - component.navigateTo( - new NavigationEvent( - NavigationAction.SAVE, - NavigationDestination.ANOTHER, - testTransaction, - ScheduleATransactionTypes.INDIVIDUAL_RECEIPT - ) - ); - expect(messageServiceAddSpy).toHaveBeenCalledOnceWith(expectedMessage); - }); - - it('#navigateTo NavigationDestination.ANOTHER_CHILD should show popup', () => { - const testTransaction1: SchATransaction = SchATransaction.fromJSON(initTransactionData); - testTransaction1.parent_transaction_id = '123'; - component.transaction = testTransaction1; - const expectedMessage: Message = { - severity: 'success', - summary: 'Successful', - detail: 'Transaction Saved', - life: 3000, - }; - const messageServiceAddSpy = spyOn(testMessageService, 'add'); - spyOn(testRouter, 'navigateByUrl').and.callFake(() => Promise.resolve(true)); - component.navigateTo( - new NavigationEvent( - NavigationAction.SAVE, - NavigationDestination.ANOTHER_CHILD, - testTransaction1, - ScheduleATransactionTypes.INDIVIDUAL_RECEIPT - ) - ); - expect(messageServiceAddSpy).toHaveBeenCalledOnceWith(expectedMessage); - }); - - it('#navigateTo NavigationDestination.CHILD should show popup + navigate', () => { - const testTransactionId = '123'; - const testTransactionTypeToAdd = ScheduleATransactionTypes.INDIVIDUAL_RECEIPT; - component.transaction = testTransaction; - component.transaction.report_id = '999'; - - const expectedMessage: Message = { - severity: 'success', - summary: 'Successful', - detail: 'Parent Transaction Saved', - life: 3000, - }; - const expectedRoute = `/reports/transactions/report/999/list/${testTransactionId}/create-sub-transaction/${testTransactionTypeToAdd}`; - - const messageServiceAddSpy = spyOn(testMessageService, 'add'); - const routerNavigateByUrlSpy = spyOn(testRouter, 'navigateByUrl'); - - component.navigateTo( - new NavigationEvent(NavigationAction.SAVE, NavigationDestination.CHILD, testTransaction, testTransactionTypeToAdd) - ); - expect(messageServiceAddSpy).toHaveBeenCalledOnceWith(expectedMessage); - expect(routerNavigateByUrlSpy).toHaveBeenCalledOnceWith(expectedRoute); - }); - - it('#navigateTo NavigationDestination.LIST should navigate', () => { - const testTransaction3: SchATransaction = SchATransaction.fromJSON(initTransactionData); - testTransaction3.id = '123'; - testTransaction3.report_id = '99'; - testTransaction3.contact_1_id = '33'; - const expectedRoute = `/reports/transactions/report/${testTransaction3.report_id}/list`; - const routerNavigateByUrlSpy = spyOn(testRouter, 'navigateByUrl'); - component.navigateTo(new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, testTransaction3)); - expect(routerNavigateByUrlSpy).toHaveBeenCalledOnceWith(expectedRoute); - }); - - it('#navigateTo NavigationDestination.CHILD should navigate', () => { - component.transaction = testTransaction; - const expectedRoute = '/reports/transactions/report/999/list/123/create-sub-transaction/INDIVIDUAL_RECEIPT'; - const routerNavigateByUrlSpy = spyOn(testRouter, 'navigateByUrl'); - component.navigateTo( - new NavigationEvent( - NavigationAction.SAVE, - NavigationDestination.CHILD, - testTransaction, - ScheduleATransactionTypes.INDIVIDUAL_RECEIPT - ) - ); - expect(routerNavigateByUrlSpy).toHaveBeenCalledOnceWith(expectedRoute); - }); - - it('#navigateTo NavigationDestination.PARENT should navigate', () => { - const transaction = { ...testTransaction } as SchATransaction; - transaction.parent_transaction_id = '333'; - const expectedRoute = '/reports/transactions/report/999/list/333'; - const routerNavigateByUrlSpy = spyOn(testRouter, 'navigateByUrl'); - component.navigateTo(new NavigationEvent(NavigationAction.SAVE, NavigationDestination.PARENT, transaction)); - expect(routerNavigateByUrlSpy).toHaveBeenCalledOnceWith(expectedRoute); - }); - - it('#navigateTo default should navigate', () => { - component.transaction = testTransaction; - const expectedRoute = '/reports/transactions/report/999/list'; - const routerNavigateByUrlSpy = spyOn(testRouter, 'navigateByUrl'); - component.navigateTo(new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, testTransaction)); - expect(routerNavigateByUrlSpy).toHaveBeenCalledOnceWith(expectedRoute); - }); - - it('#onContactLookupSelect IND should handle null form', () => { - const testContact = new Contact(); - testContact.id = '123'; - testContact.type = ContactTypes.INDIVIDUAL; - const testContactSelectItem: SelectItem = { - value: testContact, - }; - component.form.setControl('entity_type', null); - component.onContactLookupSelect(testContactSelectItem); - expect(component.form.get('contributor_last_name')?.value).toBeFalsy(); - - component.form.setControl('entity_type', new FormControl(ContactTypes.INDIVIDUAL)); - component.form.setControl('contributor_last_name', null); - component.form.setControl('contributor_first_name', null); - component.form.setControl('contributor_middle_name', null); - component.form.setControl('contributor_prefix', null); - component.form.setControl('contributor_suffix', null); - component.form.setControl('contributor_employer', null); - component.form.setControl('contributor_occupation', null); - component.form.setControl('contributor_street_1', null); - component.form.setControl('contributor_street_2', null); - component.form.setControl('contributor_city', null); - component.form.setControl('contributor_state', null); - component.form.setControl('contributor_zip', null); - - component.onContactLookupSelect(testContactSelectItem); - expect(component.form.get('contributor_last_name')?.value).toBeFalsy(); - }); - - it('#onContactLookupSelect INDIVIDUAL should set fields', () => { - const testEntityType = ContactTypes.INDIVIDUAL; - const testLastName = 'testLastName'; - const testFirstName = 'testFirstName'; - const testMiddleName = 'testMiddleName'; - const testPrefix = 'testPrefix'; - const testSuffix = 'testSuffix'; - const testEmployer = 'testEmployer'; - const testOccupation = 'testOccupation'; - const testStreet1 = 'testStreet1'; - const testStreet2 = 'testStreet2'; - const testCity = 'testCity'; - const testState = 'testState'; - const testZip = 'testZip'; - - const testContact = new Contact(); - testContact.id = '123'; - testContact.type = ContactTypes.INDIVIDUAL; - testContact.last_name = testLastName; - testContact.first_name = testFirstName; - testContact.middle_name = testMiddleName; - testContact.prefix = testPrefix; - testContact.suffix = testSuffix; - testContact.employer = testEmployer; - testContact.occupation = testOccupation; - testContact.street_1 = testStreet1; - testContact.street_2 = testStreet2; - testContact.city = testCity; - testContact.state = testState; - testContact.zip = testZip; - - const testContactSelectItem: SelectItem = { - value: testContact, - }; - - component.form.addControl('entity_type', { value: testEntityType }); - component.onContactLookupSelect(testContactSelectItem); - const lastNameFormControlValue = component.form.get('contributor_last_name')?.value; - const firstNameFormControlValue = component.form.get('contributor_first_name')?.value; - const middleNameFormControlValue = component.form.get('contributor_middle_name')?.value; - const prefixFormControlValue = component.form.get('contributor_prefix')?.value; - const suffixFormControlValue = component.form.get('contributor_suffix')?.value; - const employerFormControlValue = component.form.get('contributor_employer')?.value; - const occupationFormControlValue = component.form.get('contributor_occupation')?.value; - const street1FormControlValue = component.form.get('contributor_street_1')?.value; - const street2FormControlValue = component.form.get('contributor_street_2')?.value; - const cityFormControlValue = component.form.get('contributor_city')?.value; - const stateFormControlValue = component.form.get('contributor_state')?.value; - const zipFormControlValue = component.form.get('contributor_zip')?.value; - - expect(lastNameFormControlValue === testLastName).toBeTrue(); - expect(firstNameFormControlValue === testFirstName).toBeTrue(); - expect(middleNameFormControlValue === testMiddleName).toBeTrue(); - expect(prefixFormControlValue === testPrefix).toBeTrue(); - expect(suffixFormControlValue === testSuffix).toBeTrue(); - expect(employerFormControlValue === testEmployer).toBeTrue(); - expect(occupationFormControlValue === testOccupation).toBeTrue(); - expect(street1FormControlValue === testStreet1).toBeTrue(); - expect(street2FormControlValue === testStreet2).toBeTrue(); - expect(cityFormControlValue === testCity).toBeTrue(); - expect(stateFormControlValue === testState).toBeTrue(); - expect(zipFormControlValue === testZip).toBeTrue(); - }); - - it('#onContactLookupSelect INDIVIDUAL should set fields', () => { - const testEntityType = ContactTypes.INDIVIDUAL; - - const testContact = new Contact(); - testContact.id = '123'; - testContact.type = ContactTypes.INDIVIDUAL; - testContact.last_name = 'testLastName'; - testContact.first_name = 'testFirstName'; - testContact.middle_name = 'testMiddleName'; - testContact.prefix = 'testPrefix'; - testContact.suffix = 'testSuffix'; - testContact.employer = 'testEmployer'; - testContact.occupation = 'testOccupation'; - testContact.street_1 = 'testStreet1'; - testContact.street_2 = 'testStreet2'; - testContact.city = 'testCity'; - testContact.state = 'testState'; - testContact.zip = 'testZip'; - - const testContactSelectItem: SelectItem = { - value: testContact, - }; - - component.form.addControl('entity_type', { value: testEntityType }); - component.onContactLookupSelect(testContactSelectItem); - const lastNameFormControlValue = component.form.get('contributor_last_name')?.value; - const firstNameFormControlValue = component.form.get('contributor_first_name')?.value; - const middleNameFormControlValue = component.form.get('contributor_middle_name')?.value; - const prefixFormControlValue = component.form.get('contributor_prefix')?.value; - const suffixFormControlValue = component.form.get('contributor_suffix')?.value; - const employerFormControlValue = component.form.get('contributor_employer')?.value; - const occupationFormControlValue = component.form.get('contributor_occupation')?.value; - const street1FormControlValue = component.form.get('contributor_street_1')?.value; - const street2FormControlValue = component.form.get('contributor_street_2')?.value; - const cityFormControlValue = component.form.get('contributor_city')?.value; - const stateFormControlValue = component.form.get('contributor_state')?.value; - const zipFormControlValue = component.form.get('contributor_zip')?.value; - - expect(lastNameFormControlValue === testContact.last_name).toBeTrue(); - expect(firstNameFormControlValue === testContact.first_name).toBeTrue(); - expect(middleNameFormControlValue === testContact.middle_name).toBeTrue(); - expect(prefixFormControlValue === testContact.prefix).toBeTrue(); - expect(suffixFormControlValue === testContact.suffix).toBeTrue(); - expect(employerFormControlValue === testContact.employer).toBeTrue(); - expect(occupationFormControlValue === testContact.occupation).toBeTrue(); - expect(street1FormControlValue === testContact.street_1).toBeTrue(); - expect(street2FormControlValue === testContact.street_2).toBeTrue(); - expect(cityFormControlValue === testContact.city).toBeTrue(); - expect(stateFormControlValue === testContact.state).toBeTrue(); - expect(zipFormControlValue === testContact.zip).toBeTrue(); - }); - - it('#onContactLookupSelect INDIVIDUAL should calculate aggregate', () => { - component.transaction = testTransaction; - const testEntityType = ContactTypes.INDIVIDUAL; - - const testContact = new Contact(); - testContact.id = '123'; - testContact.type = ContactTypes.INDIVIDUAL; - testContact.last_name = 'testLastName'; - testContact.first_name = 'testFirstName'; - testContact.middle_name = 'testMiddleName'; - testContact.prefix = 'testPrefix'; - testContact.suffix = 'testSuffix'; - testContact.employer = 'testEmployer'; - testContact.occupation = 'testOccupation'; - testContact.street_1 = 'testStreet1'; - testContact.street_2 = 'testStreet2'; - testContact.city = 'testCity'; - testContact.state = 'testState'; - testContact.zip = 'testZip'; - - const testContactSelectItem: SelectItem = { - value: testContact, - }; - - component.form.addControl('entity_type', { value: testEntityType }); - component.form.get('contribution_amount')?.setValue(1111); - component.form.get('contribution_date')?.setValue('2022-03-02'); - fixture.detectChanges(); - - const getPreviousTransactionSpy = spyOn(testTransactionService, 'getPreviousTransaction').and.returnValue( - of(testTransaction) - ); - expect(getPreviousTransactionSpy).toHaveBeenCalledTimes(0); - component.form.get('contribution_date')?.valueChanges.subscribe((date) => console.log(`date: ${date}`)); - component.onContactLookupSelect(testContactSelectItem); - expect(getPreviousTransactionSpy).toHaveBeenCalledTimes(1); - }); - - it('#onContactLookupSelect ORG should handle null form', () => { - const testContact = new Contact(); - testContact.id = '123'; - testContact.type = ContactTypes.ORGANIZATION; - const testContactSelectItem: SelectItem = { - value: testContact, - }; - - component.form.setControl('entity_type', new FormControl(ContactTypes.ORGANIZATION)); - component.form.setControl('contributor_organization_name', null); - component.onContactLookupSelect(testContactSelectItem); - expect(component.form.get('contributor_organization_name')?.value).toBeFalsy(); - }); - - it('#onContactLookupSelect ORGANIZATION should set fields', () => { - const testEntityType = ContactTypes.ORGANIZATION; - const testOrganizationName = 'testOrganizationName'; - const testContact = new Contact(); - testContact.id = '123'; - testContact.type = ContactTypes.ORGANIZATION; - testContact.name = testOrganizationName; - component.transaction = Object.assign({}, testScheduleATransaction); - component.ngOnInit(); - fixture.detectChanges(); - - const testContactSelectItem: SelectItem = { - value: testContact, - }; - - component.form.addControl('entity_type', { value: testEntityType }); - component.onContactLookupSelect(testContactSelectItem); - const organizationNameFormControlValue = component.form.get('contributor_organization_name')?.value; - - expect(organizationNameFormControlValue).toEqual(testOrganizationName); - }); - - it('#onContactLookupSelect COMMITTEE should set fields', () => { - const testEntityType = ContactTypes.COMMITTEE; - const testCommitteeName = 'testCommitteeName'; - const testContact = new Contact(); - testContact.id = '123'; - testContact.type = ContactTypes.COMMITTEE; - testContact.name = testCommitteeName; - - component.transaction = testScheduleATransaction; - component.ngOnInit(); - fixture.detectChanges(); - - const testContactSelectItem: SelectItem = { - value: testContact, - }; - - component.form.get('entity_type')?.setValue(testEntityType); - component.onContactLookupSelect(testContactSelectItem); - - const committeeNameFormControlValue = component.form.get('contributor_organization_name')?.value; - - expect(committeeNameFormControlValue).toEqual(testCommitteeName); - }); - - it('#onContactLookupSelect CANDIDATE should set fields', () => { - const testEntityType = ContactTypes.CANDIDATE; - - const testContact = new Contact(); - testContact.id = '123'; - testContact.type = ContactTypes.CANDIDATE; - testContact.candidate_id = 'testCandidateId'; - testContact.last_name = 'testLastName'; - testContact.first_name = 'testFirstName'; - testContact.middle_name = 'testMiddleName'; - testContact.prefix = 'testPrefix'; - testContact.suffix = 'testSuffix'; - testContact.candidate_office = CandidateOfficeTypes.HOUSE; - testContact.candidate_state = 'MD'; - testContact.candidate_district = '01'; - testContact.street_1 = 'testStreet1'; - testContact.street_2 = 'testStreet2'; - testContact.city = 'testCity'; - testContact.state = 'testState'; - testContact.zip = 'testZip'; - - component.transaction = getTestTransactionByType(ScheduleATransactionTypes.REFUND_TO_FEDERAL_CANDIDATE); - component.ngOnInit(); - fixture.detectChanges(); - - const testContactSelectItem: SelectItem = { - value: testContact, - }; - - component.form.get('entity_type')?.setValue(testEntityType); - component.onSecondaryContactLookupSelect(testContactSelectItem); - const candidateIdFormControlValue = component.form.get('donor_candidate_fec_id')?.value; - const lastNameFormControlValue = component.form.get('donor_candidate_last_name')?.value; - const firstNameFormControlValue = component.form.get('donor_candidate_first_name')?.value; - const middleNameFormControlValue = component.form.get('donor_candidate_middle_name')?.value; - const prefixFormControlValue = component.form.get('donor_candidate_prefix')?.value; - const suffixFormControlValue = component.form.get('donor_candidate_suffix')?.value; - const candidateOfficeFormControlValue = component.form.get('donor_candidate_office')?.value; - const candidateStateFormControlValue = component.form.get('donor_candidate_state')?.value; - const candidateDistrictFormControlValue = component.form.get('donor_candidate_district')?.value; - - expect(candidateIdFormControlValue).toEqual(testContact.candidate_id); - expect(lastNameFormControlValue).toEqual(testContact.last_name); - expect(firstNameFormControlValue).toEqual(testContact.first_name); - expect(middleNameFormControlValue).toEqual(testContact.middle_name); - expect(prefixFormControlValue).toEqual(testContact.prefix); - expect(suffixFormControlValue).toEqual(testContact.suffix); - expect(candidateOfficeFormControlValue).toEqual(testContact.candidate_office); - expect(candidateStateFormControlValue).toEqual(testContact.candidate_state); - expect(candidateDistrictFormControlValue).toEqual(testContact.candidate_district); - }); - it('positive contribution_amount values should be overriden when the schema requires a negative value', () => { component.transaction = getTestTransactionByType(ScheduleATransactionTypes.RETURNED_BOUNCED_RECEIPT_INDIVIDUAL); component.ngOnInit(); + component.form.patchValue({ contribution_amount: 2 }); - expect(component.form.value.contribution_amount).toBe(-2); + expect(component.form.get('contribution_amount')?.value).toBe(-2); }); }); diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts index a2a08e4c7a..51328b3366 100644 --- a/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts @@ -1,17 +1,14 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; import { - GO_BACK_CONTROL, NavigationAction, - NavigationControl, NavigationDestination, NavigationEvent, - TransactionNavigationControls, } from 'app/shared/models/transaction-navigation-controls.model'; import { TransactionTemplateMapType, TransactionType } from 'app/shared/models/transaction-type.model'; -import { ScheduleTransaction, Transaction } from 'app/shared/models/transaction.model'; +import { Transaction } from 'app/shared/models/transaction.model'; import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; import { ContactService } from 'app/shared/services/contact.service'; import { ReportService } from 'app/shared/services/report.service'; @@ -21,9 +18,9 @@ import { getContactTypeOptions } from 'app/shared/utils/transaction-type-propert import { ValidateUtils } from 'app/shared/utils/validate.utils'; import { selectActiveReport } from 'app/store/active-report.selectors'; import { ConfirmationService, MessageService, SelectItem } from 'primeng/api'; -import { BehaviorSubject, map, of, Subject, takeUntil, startWith } from 'rxjs'; -import { Contact, ContactTypeLabels, ContactTypes } from '../../models/contact.model'; -import { TransactionContactUtils } from './transaction-contact.utils'; +import { map, of, Subject, takeUntil, startWith, Observable, delay, from, concatAll, reduce } from 'rxjs'; +import { Contact, ContactTypeLabels } from '../../models/contact.model'; +import { ContactIdMapType, TransactionContactUtils } from './transaction-contact.utils'; import { TransactionFormUtils } from './transaction-form.utils'; @Component({ @@ -34,16 +31,10 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy formProperties: string[] = []; transactionType?: TransactionType; - ContactTypes = ContactTypes; contactTypeOptions: PrimeOptions = LabelUtils.getPrimeOptions(ContactTypeLabels); - entityTypeControl?: FormControl; - candidateContactTypeFormControl: FormControl = new FormControl(ContactTypes.CANDIDATE); // eslint-disable-next-line @typescript-eslint/no-unused-vars - candidateContactTypeOption: PrimeOptions = LabelUtils.getPrimeOptions(ContactTypeLabels, [ContactTypes.CANDIDATE]); - stateOptions: PrimeOptions = LabelUtils.getPrimeOptions(LabelUtils.getStateCodeLabelsWithoutMilitary()); destroy$: Subject = new Subject(); - contactId$: Subject = new BehaviorSubject(''); + contactIdMap: ContactIdMapType = {}; formSubmitted = false; - purposeDescriptionLabel = ''; templateMap: TransactionTemplateMapType = {} as TransactionTemplateMapType; form: FormGroup = this.fb.group({}); isEditable = true; @@ -67,40 +58,17 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy } this.transactionType = this.transaction.transactionType; this.templateMap = this.transactionType.templateMap; - this.formProperties = this.transactionType.getFormControlNames(this.templateMap); + this.formProperties = this.transactionType.getFormControlNames(); this.contactTypeOptions = getContactTypeOptions(this.transactionType.contactTypeOptions ?? []); this.form = this.fb.group(ValidateUtils.getFormGroupFields(this.formProperties)); - this.form.addControl('contact_1', new FormControl()); - this.form.addControl( - 'contact_2', - new FormControl(null, () => { - if (!this.transaction?.contact_2 && this.transactionType?.contact2IsRequired) { - return { required: true }; - } - return null; - }) - ); - this.memoCodeCheckboxLabel$ = this.getMemoCodeCheckboxLabel$(this.form, this.transactionType); - TransactionFormUtils.onInit(this, this.form, this.transaction, this.contactId$); - this.entityTypeControl = this.form.get('entity_type') as FormControl; - this.parentOnInit(); - this.store - .select(selectActiveReport) - .pipe(takeUntil(this.destroy$)) - .subscribe((report) => { - this.isEditable = this.reportService.isEditable(report); - if (!this.isEditable) this.form.disable(); - }); - } + TransactionFormUtils.onInit(this, this.form, this.transaction, this.contactIdMap, this.contactService); - parentOnInit() { - const transactionType = this.transactionType; // Determine if amount should always be negative and then force it to be so if needed - if (transactionType?.negativeAmountValueOnly && this.templateMap?.amount) { + if (this.transactionType?.negativeAmountValueOnly && this.templateMap?.amount) { this.form .get(this.templateMap.amount) ?.valueChanges.pipe(takeUntil(this.destroy$)) @@ -111,22 +79,35 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy }); } - if (transactionType?.generatePurposeDescriptionLabel) { - this.purposeDescriptionLabel = transactionType.generatePurposeDescriptionLabel(); - } + this.store + .select(selectActiveReport) + .pipe(takeUntil(this.destroy$)) + .subscribe((report) => { + this.isEditable = this.reportService.isEditable(report); + if (!this.isEditable) this.form.disable(); + }); } ngOnDestroy(): void { this.destroy$.next(true); this.destroy$.complete(); - this.contactId$.complete(); + Object.values(this.contactIdMap).forEach((id$) => id$.complete()); } - save(navigationEvent: NavigationEvent) { - this.formSubmitted = true; + writeToApi(payload: Transaction): Observable { + if (payload.id) { + return this.transactionService.update(payload); + } else { + return this.transactionService.create(payload); + } + } - if (this.form.invalid) { - return; + save(navigationEvent: NavigationEvent) { + // update all contacts with changes from form. + if (this.transaction) { + TransactionContactUtils.updateContactsWithForm(this.transaction, this.templateMap, this.form); + } else { + throw new Error('Fecfile: No transactions submitted for double-entry transaction form.'); } const payload: Transaction = TransactionFormUtils.getPayloadTransaction( @@ -134,122 +115,86 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy this.form, this.formProperties ); - - this.confirmSave(payload, this.form, this.doSave, navigationEvent, payload); + if (payload.transaction_type_identifier) { + const responseFromApi = this.writeToApi(payload); + responseFromApi.subscribe((transaction) => { + navigationEvent.transaction = this.transactionType?.updateParentOnSave ? payload : transaction; + this.navigateTo(navigationEvent); + }); + } } - protected confirmSave( - confirmTransaction: Transaction, + confirmWithUser( + transaction: Transaction, form: FormGroup, - acceptCallback: (navigationEvent: NavigationEvent, payload: Transaction) => void, - navigationEvent: NavigationEvent, - payload: Transaction, - targetDialog: 'dialog' | 'childDialog' = 'dialog' + targetDialog: 'dialog' | 'childDialog' | 'childDialog_2' = 'dialog' ) { - if ( - confirmTransaction.contact_1_id && - confirmTransaction.contact_1 && - confirmTransaction?.transactionType?.templateMap - ) { - const transactionContactChanges = TransactionContactUtils.setTransactionContactFormChanges( - form, - confirmTransaction.contact_1, - confirmTransaction.transactionType.templateMap - ); - if (transactionContactChanges?.length) { - const confirmationMessage = TransactionContactUtils.getEditTransactionContactConfirmationMessage( - transactionContactChanges, - confirmTransaction.contact_1, - form, - this.fecDatePipe, - confirmTransaction.transactionType.templateMap - ); - this.confirmationService.confirm({ - key: targetDialog, - header: 'Confirm', - icon: 'pi pi-info-circle', - message: confirmationMessage, - acceptLabel: 'Continue', - rejectLabel: 'Cancel', - accept: () => { - acceptCallback.call(this, navigationEvent, payload); - }, - reject: () => { - return; - }, - }); - } else { - acceptCallback.call(this, navigationEvent, payload); - } - } else { - if (confirmTransaction?.transactionType?.templateMap) { - const confirmationMessage = TransactionContactUtils.getCreateTransactionContactConfirmationMessage( - (confirmTransaction as ScheduleTransaction).entity_type as ContactTypes, - form, - confirmTransaction.transactionType.templateMap - ); - this.confirmationService.confirm({ - key: targetDialog, - header: 'Confirm', - icon: 'pi pi-info-circle', - message: confirmationMessage, - acceptLabel: 'Continue', - rejectLabel: 'Cancel', - accept: () => { - acceptCallback.call(this, navigationEvent, payload); - }, - reject: () => { - return; - }, - }); - } else { - throw new Error('Fecfile: Cannot find template map when confirming transaction'); - } + const templateMap = transaction.transactionType?.templateMap; + if (!templateMap) { + throw new Error('Fecfile: Cannot find template map when confirming transaction'); } - } - - protected doSave(navigationEvent: NavigationEvent, payload: Transaction) { - if (payload.transaction_type_identifier) { - const originalTransaction = payload; - // Reorganize the payload if this transaction type can update its parent transaction - // This will break the scenario where the user creates a grandparent, then child, then tries - // to create a grandchild transaction because we won't know which child transaction of the grandparent - // was the original transaction it's id was generated on the api. the middle child's - // id is necessary to generate the url for creating the grandchild. - if (payload.transactionType?.updateParentOnSave) { - payload = payload.getUpdatedParent(); - } - - if (payload.id) { - this.transactionService.update(payload).subscribe((transaction) => { - navigationEvent.transaction = originalTransaction.transactionType?.updateParentOnSave - ? originalTransaction - : transaction; - this.navigateTo(navigationEvent); - }); - } else { - this.transactionService.create(payload).subscribe((transaction) => { - navigationEvent.transaction = originalTransaction.transactionType?.updateParentOnSave - ? originalTransaction - : transaction; - this.navigateTo(navigationEvent); - }); - } - } - } - - getNavigationControls(): TransactionNavigationControls { - if (!this.isEditable) return new TransactionNavigationControls([], [GO_BACK_CONTROL], []); - return this.transactionType?.navigationControls ?? new TransactionNavigationControls([], [], []); - } + const confirmations$ = Object.entries(transaction.transactionType?.contactConfig ?? {}) + .map(([contactKey, config]: [string, { [formField: string]: string }]) => { + if (transaction[contactKey as keyof Transaction]) { + if (transaction.transactionType?.useParentContact && contactKey === 'contact_1') { + return ''; + } + const contact = transaction[contactKey as keyof Transaction] as Contact; + if (!contact.id) { + return TransactionContactUtils.getCreateTransactionContactConfirmationMessage( + contact.type, + form, + templateMap, + contactKey + ); + } + const changes = TransactionContactUtils.getContactChanges(form, contact, templateMap, config); + const dateString = this.fecDatePipe.transform(form.get(templateMap.date)?.value); + if (changes.length > 0) { + return TransactionContactUtils.getContactChangesMessage(contact, dateString, changes); + } + } + return ''; + }) + .filter((message) => !!message) + .map((message: string) => { + return new Observable((subscriber) => { + this.confirmationService.confirm({ + key: targetDialog, + header: 'Confirm', + icon: 'pi pi-info-circle', + message: message, + acceptLabel: 'Continue', + rejectLabel: 'Cancel', + accept: () => { + subscriber.next(true); + subscriber.complete(); + }, + reject: () => { + subscriber.next(false); + subscriber.complete(); + }, + }); + }).pipe(delay(500)); + }); - getInlineControls(): NavigationControl[] { - return this.getNavigationControls().getNavigationControls('inline', this.transaction); + return from([of(true), ...confirmations$]).pipe( + concatAll(), + reduce((accumulator, confirmed) => accumulator && confirmed) + ); } handleNavigate(navigationEvent: NavigationEvent): void { + this.formSubmitted = true; + if (navigationEvent.action === NavigationAction.SAVE) { - this.save(navigationEvent); + if (this.form.invalid || !this.transaction) { + return; + } + this.confirmWithUser(this.transaction, this.form).subscribe((confirmed: boolean) => { + // if every confirmation was accepted + if (confirmed) this.save(navigationEvent); + }); } else { this.navigateTo(navigationEvent); } @@ -271,10 +216,8 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy this.router.navigateByUrl( `${reportPath}/list/${event.transaction?.parent_transaction_id}/create-sub-transaction/${event.destinationTransactionType}` ); - this.resetForm(); } else { this.router.navigateByUrl(`${reportPath}/create/${event.destinationTransactionType}`); - this.resetForm(); } } else if (event.destination === NavigationDestination.CHILD) { this.messageService.add({ @@ -298,20 +241,31 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy TransactionFormUtils.resetForm(this.form, this.transaction, this.contactTypeOptions); } - isDescriptionSystemGenerated(transactionType?: TransactionType): boolean { - // Description is system generated if there is a defined function. Otherwise, it's mutable - return transactionType?.generatePurposeDescription !== undefined; + updateFormWithPrimaryContact(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithPrimaryContact( + selectItem, + this.form, + this.transaction, + this.contactIdMap['contact_1'] + ); } - onContactLookupSelect(selectItem: SelectItem) { - TransactionContactUtils.onContactLookupSelect(selectItem, this.form, this.transaction, this.contactId$); - } - onSecondaryContactLookupSelect(selectItem: SelectItem) { - TransactionContactUtils.onSecondaryContactLookupSelect(selectItem, this.form, this.transaction); + updateFormWithCandidateContact(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithCandidateContact( + selectItem, + this.form, + this.transaction, + this.contactIdMap['contact_2'] + ); } - getEntityType(): string { - return this.form.get('entity_type')?.value || ''; + updateFormWithSecondaryContact(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithSecondaryContact( + selectItem, + this.form, + this.transaction, + this.contactIdMap['contact_2'] + ); } getMemoCodeCheckboxLabel$(form: FormGroup, transactionType: TransactionType) { diff --git a/front-end/src/app/shared/components/transaction-type-base/triple-transaction-type-base.component.spec.ts b/front-end/src/app/shared/components/transaction-type-base/triple-transaction-type-base.component.spec.ts new file mode 100644 index 0000000000..fa7a9c7316 --- /dev/null +++ b/front-end/src/app/shared/components/transaction-type-base/triple-transaction-type-base.component.spec.ts @@ -0,0 +1,95 @@ +import { DatePipe } from '@angular/common'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { FormBuilder } from '@angular/forms'; +import { RouterTestingModule } from '@angular/router/testing'; +import { provideMockStore } from '@ngrx/store/testing'; +import { SchATransaction, ScheduleATransactionTypes } from 'app/shared/models/scha-transaction.model'; +import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; +import { + NavigationAction, + NavigationDestination, + NavigationEvent, +} from 'app/shared/models/transaction-navigation-controls.model'; +import { TransactionService } from 'app/shared/services/transaction.service'; +import { getTestTransactionByType, testMockStore } from 'app/shared/utils/unit-test.utils'; +import { Confirmation, ConfirmationService, MessageService } from 'primeng/api'; +import { SchCTransaction, ScheduleCTransactionTypes } from 'app/shared/models/schc-transaction.model'; +import { SchC1Transaction, ScheduleC1TransactionTypes } from 'app/shared/models/schc1-transaction.model'; +import { TripleTransactionDetailComponent } from 'app/reports/transactions/triple-transaction-detail/triple-transaction-detail.component'; +import { TripleTransactionTypeBaseComponent } from './triple-transaction-type-base.component'; +import { of } from 'rxjs'; + +let testTransaction: SchCTransaction; + +describe('TripleTransactionTypeBaseComponent', () => { + let component: TripleTransactionTypeBaseComponent; + let fixture: ComponentFixture; + let testConfirmationService: ConfirmationService; + + //spys + let navigateToSpy: jasmine.Spy; + let transactionServiceSpy: jasmine.SpyObj; + let confirmSpy: jasmine.Spy; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TripleTransactionDetailComponent], + imports: [RouterTestingModule, HttpClientTestingModule], + providers: [ + DatePipe, + MessageService, + FormBuilder, + { + provide: TransactionService, + useValue: jasmine.createSpyObj('TransactionService', { + update: of(undefined), + create: of(undefined), + getPreviousTransaction: of(undefined), + }), + }, + ConfirmationService, + provideMockStore(testMockStore), + FecDatePipe, + ], + }).compileComponents(); + + transactionServiceSpy = TestBed.inject(TransactionService) as jasmine.SpyObj; + testConfirmationService = TestBed.inject(ConfirmationService); + + testTransaction = getTestTransactionByType(ScheduleCTransactionTypes.LOAN_RECEIVED_FROM_BANK) as SchCTransaction; + const child1 = getTestTransactionByType(ScheduleC1TransactionTypes.C1_LOAN_AGREEMENT) as SchC1Transaction; + child1.treasurer_first_name = 'treas_fname'; + child1.treasurer_last_name = 'treas_lname'; + const child2 = getTestTransactionByType( + ScheduleATransactionTypes.LOAN_RECEIVED_FROM_BANK_RECEIPT + ) as SchATransaction; + testTransaction.report_id = '123'; + testTransaction.children = [child1, child2]; + fixture = TestBed.createComponent(TripleTransactionDetailComponent); + component = fixture.componentInstance; + component.transaction = testTransaction; + fixture.detectChanges(); + + navigateToSpy = spyOn(component, 'navigateTo'); + confirmSpy = spyOn(testConfirmationService, 'confirm'); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + expect(component.transactionType?.title).toBe('Loan Received from Bank'); + }); + + xit('should save on save event', fakeAsync(() => { + if (component.transaction) transactionServiceSpy.create.and.returnValue(of(component.transaction)); + confirmSpy.and.callFake((confirmation: Confirmation) => { + if (confirmation.accept) return confirmation?.accept(); + }); + expect(component.form.invalid).toBeFalse(); + const listSaveEvent = new NavigationEvent(NavigationAction.SAVE, NavigationDestination.LIST, component.transaction); + component.handleNavigate(listSaveEvent); + tick(500); + expect(transactionServiceSpy.create).toHaveBeenCalled(); + expect(navigateToSpy).toHaveBeenCalled(); + })); +}); diff --git a/front-end/src/app/shared/components/transaction-type-base/triple-transaction-type-base.component.ts b/front-end/src/app/shared/components/transaction-type-base/triple-transaction-type-base.component.ts new file mode 100644 index 0000000000..1a210e3af3 --- /dev/null +++ b/front-end/src/app/shared/components/transaction-type-base/triple-transaction-type-base.component.ts @@ -0,0 +1,210 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { NavigationAction, NavigationEvent } from 'app/shared/models/transaction-navigation-controls.model'; +import { + TemplateMapKeyType, + TransactionTemplateMapType, + TransactionType, +} from 'app/shared/models/transaction-type.model'; +import { Transaction } from 'app/shared/models/transaction.model'; +import { LabelUtils, PrimeOptions } from 'app/shared/utils/label.utils'; +import { getContactTypeOptions } from 'app/shared/utils/transaction-type-properties'; +import { ValidateUtils } from 'app/shared/utils/validate.utils'; +import { SelectItem } from 'primeng/api'; +import { concat, of, reduce } from 'rxjs'; +import { Contact, ContactTypeLabels } from '../../models/contact.model'; +import { ContactIdMapType, TransactionContactUtils } from './transaction-contact.utils'; +import { TransactionFormUtils } from './transaction-form.utils'; +import { DoubleTransactionTypeBaseComponent } from './double-transaction-type-base.component'; +import { TransactionChildFormUtils } from './transaction-child-form.utils'; + +/** + * This component is to help manage a form that contains 3 transactions that the + * user needs to fill out and submit to the back end. + * + * The primany transaction code is inherited from the TransactionTypeBaseComponent and + * the secondary transaction code is inherited from the DoubleTransactionTypeBaseComponent + * in turn. This abstract component class adds a child_2 transaction that is defined in the parent + * transaction's TransactionType class. + */ +@Component({ + template: '', +}) +export abstract class TripleTransactionTypeBaseComponent + extends DoubleTransactionTypeBaseComponent + implements OnInit, OnDestroy +{ + childFormProperties_2: string[] = []; + childTransactionType_2?: TransactionType; + childTransaction_2?: Transaction; + childContactTypeOptions_2: PrimeOptions = LabelUtils.getPrimeOptions(ContactTypeLabels); + childForm_2: FormGroup = this.fb.group({}); + childContactIdMap_2: ContactIdMapType = {}; + childTemplateMap_2: TransactionTemplateMapType = {} as TransactionTemplateMapType; + childMemoCodeCheckboxLabel_2$ = of(''); + + override ngOnInit(): void { + // Initialize primary and secondary forms. + super.ngOnInit(); + + // Initialize child form. + if (this.transaction) { + this.childTransaction_2 = this.getChildTransaction(this.transaction, 1); + } else { + throw new Error('Fecfile: Transaction not found for triple-entry transaction form'); + } + if (!this.childTransaction_2) { + throw new Error('Fecfile: Child 2 transaction not found for triple-entry transaction form'); + } + this.childTransactionType_2 = this.childTransaction_2?.transactionType; + if (!this.childTransactionType_2?.templateMap) { + throw new Error('Fecfile: Template map not found for triple transaction triple-entry transaction form'); + } + this.childTemplateMap_2 = this.childTransactionType_2.templateMap; + this.childContactTypeOptions_2 = getContactTypeOptions(this.childTransactionType_2.contactTypeOptions ?? []); + this.childFormProperties_2 = this.childTransactionType_2.getFormControlNames(); + this.childForm_2 = this.fb.group(ValidateUtils.getFormGroupFields(this.childFormProperties_2)); + + if ( + this.childTransactionType_2?.inheritedFields?.includes('memo_code' as TemplateMapKeyType) && + this.transactionType + ) { + this.childMemoCodeCheckboxLabel_2$ = this.memoCodeCheckboxLabel$; + } else { + this.childMemoCodeCheckboxLabel_2$ = this.getMemoCodeCheckboxLabel$( + this.childForm_2, + this.childTransactionType_2 + ); + } + + TransactionFormUtils.onInit( + this, + this.childForm_2, + this.childTransaction_2, + this.childContactIdMap_2, + this.contactService + ); + TransactionChildFormUtils.childOnInit(this, this.childForm_2, this.childTransaction_2); + } + + override ngOnDestroy(): void { + super.ngOnDestroy(); + Object.values(this.childContactIdMap_2).forEach((id$) => id$.complete()); + } + + override save(navigationEvent: NavigationEvent) { + // update all contacts with changes from form. + if (this.transaction && this.childTransaction && this.childTransaction_2) { + TransactionContactUtils.updateContactsWithForm(this.transaction, this.templateMap, this.form); + TransactionContactUtils.updateContactsWithForm(this.childTransaction, this.childTemplateMap, this.childForm); + TransactionContactUtils.updateContactsWithForm( + this.childTransaction_2, + this.childTemplateMap_2, + this.childForm_2 + ); + } else { + throw new Error('Fecfile: No transactions submitted for triple-entry transaction form.'); + } + + const payload: Transaction = TransactionFormUtils.getPayloadTransaction( + this.transaction, + this.form, + this.formProperties + ); + + payload.children = [ + TransactionFormUtils.getPayloadTransaction(this.childTransaction, this.childForm, this.childFormProperties), + TransactionFormUtils.getPayloadTransaction(this.childTransaction_2, this.childForm_2, this.childFormProperties_2), + ]; + payload.children[0].report_id = payload.report_id; + payload.children[1].report_id = payload.report_id; + + if (payload.transaction_type_identifier) { + const responseFromApi = this.writeToApi(payload); + responseFromApi.subscribe((transaction) => { + navigationEvent.transaction = this.transactionType?.updateParentOnSave ? payload : transaction; + this.navigateTo(navigationEvent); + }); + } + } + + override handleNavigate(navigationEvent: NavigationEvent): void { + this.formSubmitted = true; + + if (navigationEvent.action === NavigationAction.SAVE) { + if ( + this.form.invalid || + this.childForm.invalid || + this.childForm_2.invalid || + !this.transaction || + !this.childTransaction || + !this.childTransaction_2 + ) { + return; + } + + let confirmation$ = this.confirmWithUser(this.transaction, this.form); + confirmation$ = concat( + confirmation$, + this.confirmWithUser(this.childTransaction, this.childForm, 'childDialog') + ).pipe(reduce((accumulator, confirmed) => accumulator && confirmed)); + confirmation$ = concat( + confirmation$, + this.confirmWithUser(this.childTransaction_2, this.childForm_2, 'childDialog_2') + ).pipe(reduce((accumulator, confirmed) => accumulator && confirmed)); + + confirmation$.subscribe((confirmed: boolean) => { + // if every confirmation was accepted + if (confirmed) this.save(navigationEvent); + }); + } else { + this.navigateTo(navigationEvent); + } + } + + override resetForm() { + super.resetForm(); + TransactionFormUtils.resetForm(this.childForm_2, this.childTransaction_2, this.childContactTypeOptions_2); + } + + override updateFormWithPrimaryContact(selectItem: SelectItem): void { + super.updateFormWithPrimaryContact(selectItem); + if (this.childTransaction_2?.transactionType?.useParentContact && this.transaction?.contact_1) { + this.childTransaction_2.contact_1 = this.transaction.contact_1; + this.childForm_2.get('entity_type')?.setValue(selectItem.value.type); + } + } + + childUpdateFormWithPrimaryContact_2(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithPrimaryContact( + selectItem, + this.childForm_2, + this.childTransaction_2, + this.childContactIdMap_2['contact_1'] + ); + + if (this.childTransaction_2) { + this.updateInheritedFields(this.childForm_2, this.childTransaction_2); + } else { + throw new Error('Fecfile: Missing child transaction.'); + } + } + + childUpdateFormWithCandidateContact_2(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithCandidateContact( + selectItem, + this.childForm_2, + this.childTransaction_2, + this.childContactIdMap_2['contact_2'] + ); + } + + childUpdateFormWithSecondaryContact_2(selectItem: SelectItem) { + TransactionContactUtils.updateFormWithSecondaryContact( + selectItem, + this.childForm_2, + this.childTransaction_2, + this.childContactIdMap_2['contact_2'] + ); + } +} diff --git a/front-end/src/app/shared/models/contact.model.ts b/front-end/src/app/shared/models/contact.model.ts index 8cc8c9f24c..317d9b19c0 100644 --- a/front-end/src/app/shared/models/contact.model.ts +++ b/front-end/src/app/shared/models/contact.model.ts @@ -96,8 +96,94 @@ export class Contact extends BaseModel { static fromJSON(json: any): Contact { // eslint-disable-line @typescript-eslint/no-explicit-any return plainToClass(Contact, json); } + + getNameString(): string { + return this.name ? this.name : `${this.last_name}, ${this.first_name} ${this.middle_name ?? ''}`; + } } +/** + * The following maps have: + * KEY = the key to a templateMap entry for the transaction forms + * VALUE = the key to the contact field + */ +export const STANDARD_SINGLE_CONTACT = { + contact_1: { + organization_name: 'name', + committee_name: 'name', + committee_fec_id: 'committee_id', + last_name: 'last_name', + first_name: 'first_name', + middle_name: 'middle_name', + prefix: 'prefix', + suffix: 'suffix', + street_1: 'street_1', + street_2: 'street_2', + city: 'city', + state: 'state', + zip: 'zip', + employer: 'employer', + occupation: 'occupation', + }, +}; +export const STANDARD_AND_CANDIDATE = { + contact_1: { + organization_name: 'name', + committee_name: 'name', + committee_fec_id: 'committee_id', + last_name: 'last_name', + first_name: 'first_name', + middle_name: 'middle_name', + prefix: 'prefix', + suffix: 'suffix', + street_1: 'street_1', + street_2: 'street_2', + city: 'city', + state: 'state', + zip: 'zip', + employer: 'employer', + occupation: 'occupation', + }, + contact_2: { + candidate_fec_id: 'candidate_id', + candidate_last_name: 'last_name', + candidate_first_name: 'first_name', + candidate_middle_name: 'middle_name', + candidate_prefix: 'prefix', + candidate_suffix: 'suffix', + candidate_office: 'candidate_office', + candidate_state: 'candidate_state', + candidate_district: 'candidate_district', + }, +}; +export const STANDARD_AND_SECONDARY = { + contact_1: { + organization_name: 'name', + committee_name: 'name', + committee_fec_id: 'committee_id', + last_name: 'last_name', + first_name: 'first_name', + middle_name: 'middle_name', + prefix: 'prefix', + suffix: 'suffix', + street_1: 'street_1', + street_2: 'street_2', + city: 'city', + state: 'state', + zip: 'zip', + employer: 'employer', + occupation: 'occupation', + }, + contact_2: { + secondary_name: 'name', + secondary_street_1: 'street_1', + secondary_street_2: 'street_2', + secondary_city: 'city', + secondary_state: 'state', + secondary_zip: 'zip', + }, +}; + export class FecApiLookupData {} export class FecApiCandidateLookupData extends FecApiLookupData { diff --git a/front-end/src/app/shared/models/scha-transaction-type.model.ts b/front-end/src/app/shared/models/scha-transaction-type.model.ts index 000d4f8655..a377a52fac 100644 --- a/front-end/src/app/shared/models/scha-transaction-type.model.ts +++ b/front-end/src/app/shared/models/scha-transaction-type.model.ts @@ -50,5 +50,24 @@ export abstract class SchATransactionType extends TransactionType { category_code: '', election_code: 'election_code', election_other_description: 'election_other_description', + secondary_name: '', + secondary_street_1: '', + secondary_street_2: '', + secondary_city: '', + secondary_state: '', + secondary_zip: '', + signatory_1_last_name: '', + signatory_1_first_name: '', + signatory_1_middle_name: '', + signatory_1_prefix: '', + signatory_1_suffix: '', + signatory_1_date: '', + signatory_2_last_name: '', + signatory_2_first_name: '', + signatory_2_middle_name: '', + signatory_2_prefix: '', + signatory_2_suffix: '', + signatory_2_title: '', + signatory_2_date: '', }; } diff --git a/front-end/src/app/shared/models/scha-transaction.model.ts b/front-end/src/app/shared/models/scha-transaction.model.ts index a35a7e5000..fa0a0a3eae 100644 --- a/front-end/src/app/shared/models/scha-transaction.model.ts +++ b/front-end/src/app/shared/models/scha-transaction.model.ts @@ -183,6 +183,7 @@ export enum ScheduleATransactionTypes { PARTNERSHIP_ATTRIBUTION_NATIONAL_PARTY_RECOUNT_JF_TRANSFER_MEMO = 'PARTNERSHIP_ATTRIBUTION_NATIONAL_PARTY_RECOUNT_JF_TRANSFER_MEMO', PARTNERSHIP_ATTRIBUTION_NATIONAL_PARTY_HEADQUARTERS_JF_TRANSFER_MEMO = 'PARTNERSHIP_ATTRIBUTION_NATIONAL_PARTY_HEADQUARTERS_JF_TRANSFER_MEMO', LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT = 'LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT', + LOAN_RECEIVED_FROM_BANK_RECEIPT = 'LOAN_RECEIVED_FROM_BANK_RECEIPT', } export const ScheduleATransactionTypeLabels: LabelList = [ @@ -436,6 +437,7 @@ export const ScheduleATransactionTypeLabels: LabelList = [ 'Partnership Attribution Headquarters Buildings Account JF Transfer Memo', ], [ScheduleATransactionTypes.LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT, 'Loan Received from Individual'], + [ScheduleATransactionTypes.LOAN_RECEIVED_FROM_BANK_RECEIPT, 'Loan Received from Bank'], ]; export const UnimplementedTypeEntityCategories: LabelList = [ diff --git a/front-end/src/app/shared/models/schb-transaction-type.model.ts b/front-end/src/app/shared/models/schb-transaction-type.model.ts index b0b0f3ca9a..e0bea9d49f 100644 --- a/front-end/src/app/shared/models/schb-transaction-type.model.ts +++ b/front-end/src/app/shared/models/schb-transaction-type.model.ts @@ -49,5 +49,24 @@ export abstract class SchBTransactionType extends TransactionType { category_code: 'category_code', election_code: 'election_code', election_other_description: 'election_other_description', + secondary_name: '', + secondary_street_1: '', + secondary_street_2: '', + secondary_city: '', + secondary_state: '', + secondary_zip: '', + signatory_1_last_name: '', + signatory_1_first_name: '', + signatory_1_middle_name: '', + signatory_1_prefix: '', + signatory_1_suffix: '', + signatory_1_date: '', + signatory_2_last_name: '', + signatory_2_first_name: '', + signatory_2_middle_name: '', + signatory_2_prefix: '', + signatory_2_suffix: '', + signatory_2_title: '', + signatory_2_date: '', }; } diff --git a/front-end/src/app/shared/models/schc-transaction-type.model.ts b/front-end/src/app/shared/models/schc-transaction-type.model.ts index 0b46a211fd..b17906d212 100644 --- a/front-end/src/app/shared/models/schc-transaction-type.model.ts +++ b/front-end/src/app/shared/models/schc-transaction-type.model.ts @@ -48,5 +48,24 @@ export abstract class SchCTransactionType extends TransactionType { category_code: '', election_code: 'election_code', election_other_description: 'election_other_description', + secondary_name: '', + secondary_street_1: '', + secondary_street_2: '', + secondary_city: '', + secondary_state: '', + secondary_zip: '', + signatory_1_last_name: '', + signatory_1_first_name: '', + signatory_1_middle_name: '', + signatory_1_prefix: '', + signatory_1_suffix: '', + signatory_1_date: '', + signatory_2_last_name: '', + signatory_2_first_name: '', + signatory_2_middle_name: '', + signatory_2_prefix: '', + signatory_2_suffix: '', + signatory_2_title: '', + signatory_2_date: '', }; } diff --git a/front-end/src/app/shared/models/schc1-transaction-type.model.ts b/front-end/src/app/shared/models/schc1-transaction-type.model.ts index 09a84b21e1..af1d535c86 100644 --- a/front-end/src/app/shared/models/schc1-transaction-type.model.ts +++ b/front-end/src/app/shared/models/schc1-transaction-type.model.ts @@ -39,14 +39,33 @@ export abstract class SchC1TransactionType extends TransactionType { amount: 'loan_amount', balance: 'total_balance', payment_to_date: '', - interest_rate: '', - due_date: '', - secured: '', + interest_rate: 'loan_interest_rate', + due_date: 'loan_due_date', + secured: 'collateral', aggregate: '', purpose_description: '', - text4000: 'text4000', + text4000: '', category_code: '', election_code: '', election_other_description: '', + secondary_name: 'ind_name_account_location', + secondary_street_1: 'account_street_1', + secondary_street_2: 'account_street_2', + secondary_city: 'account_city', + secondary_state: 'account_state', + secondary_zip: 'account_zip', + signatory_1_last_name: 'treasurer_last_name', + signatory_1_first_name: 'treasurer_first_name', + signatory_1_middle_name: 'treasurer_middle_name', + signatory_1_prefix: 'treasurer_prefix', + signatory_1_suffix: 'treasurer_suffix', + signatory_1_date: 'treasurer_date_signed', + signatory_2_last_name: 'authorized_last_name', + signatory_2_first_name: 'authorized_first_name', + signatory_2_middle_name: 'authorized_middle_name', + signatory_2_prefix: 'authorized_prefix', + signatory_2_suffix: 'authorized_suffix', + signatory_2_title: 'authorized_title', + signatory_2_date: 'authorized_date_signed', }; } diff --git a/front-end/src/app/shared/models/schc1-transaction.model.ts b/front-end/src/app/shared/models/schc1-transaction.model.ts index 72cb5e6ff1..6207eaba09 100644 --- a/front-end/src/app/shared/models/schc1-transaction.model.ts +++ b/front-end/src/app/shared/models/schc1-transaction.model.ts @@ -12,9 +12,9 @@ export class SchC1Transaction extends Transaction { lender_state: string | undefined; lender_zip: string | undefined; loan_amount: number | undefined; - loan_interest_rate: number | undefined; + loan_interest_rate: string | undefined; @Transform(BaseModel.dateTransform) loan_incurred_date: Date | undefined; - @Transform(BaseModel.dateTransform) loan_due_date: Date | undefined; + loan_due_date: string | undefined; loan_restructured: boolean | undefined; @Transform(BaseModel.dateTransform) loan_originally_incurred_date: Date | undefined; credit_amount_this_draw: number | undefined; @@ -53,6 +53,10 @@ export class SchC1Transaction extends Transaction { entity_type: string | undefined; aggregation_group: AggregationGroups | undefined; + // The line_of_credit field is strictly to save front-end UI state and is not + // part of the SchC1 spec + line_of_credit: boolean | undefined; + // eslint-disable-next-line @typescript-eslint/no-explicit-any static fromJSON(json: any, depth = 2): SchC1Transaction { const transaction = plainToClass(SchC1Transaction, json); @@ -79,9 +83,9 @@ export enum ScheduleC1TransactionGroups { export type ScheduleC1TransactionGroupsType = ScheduleC1TransactionGroups.SCHEDULE_C1; export enum ScheduleC1TransactionTypes { - LOAN_AGREEMENT = 'LOAN_AGREEMENT', + C1_LOAN_AGREEMENT = 'C1_LOAN_AGREEMENT', } export const ScheduleC1TransactionTypeLabels: LabelList = [ - [ScheduleC1TransactionTypes.LOAN_AGREEMENT, 'Loan Agreement'], + [ScheduleC1TransactionTypes.C1_LOAN_AGREEMENT, 'Loan Agreement'], ]; diff --git a/front-end/src/app/shared/models/schc2-transaction-type.model.ts b/front-end/src/app/shared/models/schc2-transaction-type.model.ts index f13c1f4d66..15ecfa25b4 100644 --- a/front-end/src/app/shared/models/schc2-transaction-type.model.ts +++ b/front-end/src/app/shared/models/schc2-transaction-type.model.ts @@ -1,7 +1,7 @@ import { TransactionType, TransactionTemplateMapType } from './transaction-type.model'; export abstract class SchC2TransactionType extends TransactionType { - scheduleId = 'C1'; + scheduleId = 'C2'; apiEndpoint = '/transactions/schedule-c2'; override amountInputHeader = 'Loan information'; @@ -46,5 +46,24 @@ export abstract class SchC2TransactionType extends TransactionType { category_code: '', election_code: '', election_other_description: '', + secondary_name: '', + secondary_street_1: '', + secondary_street_2: '', + secondary_city: '', + secondary_state: '', + secondary_zip: '', + signatory_1_last_name: '', + signatory_1_first_name: '', + signatory_1_middle_name: '', + signatory_1_prefix: '', + signatory_1_suffix: '', + signatory_1_date: '', + signatory_2_last_name: '', + signatory_2_first_name: '', + signatory_2_middle_name: '', + signatory_2_prefix: '', + signatory_2_suffix: '', + signatory_2_title: '', + signatory_2_date: '', }; } diff --git a/front-end/src/app/shared/models/schd-transaction.model.spec.ts b/front-end/src/app/shared/models/schd-transaction.model.spec.ts new file mode 100644 index 0000000000..6c0c764a9c --- /dev/null +++ b/front-end/src/app/shared/models/schd-transaction.model.spec.ts @@ -0,0 +1,28 @@ +import { SchDTransaction } from './schd-transaction.model'; + +describe('SchDTransaction', () => { + it('should create an instance', () => { + expect(new SchDTransaction()).toBeTruthy(); + }); + + it('#fromJSON() should return a populated SchDTransaction instance', () => { + const data = { + id: '999', + form_type: 'SD10', + creditor_organization_name: 'foo', + }; + const transaction: SchDTransaction = SchDTransaction.fromJSON(data); + expect(transaction).toBeInstanceOf(SchDTransaction); + expect(transaction.id).toBe('999'); + expect(transaction.form_type).toBe('SD10'); + expect(transaction.creditor_organization_name).toBe('foo'); + }); + + xit('Creates a transaction object from JSON', () => { + const json = { + transaction_type_identifier: 'DEBT_OWED_BY_COMMITTEE', + }; + const transaction: SchDTransaction = SchDTransaction.fromJSON(json); + expect(transaction.constructor.name).toBe('SchDTransaction'); + }); +}); diff --git a/front-end/src/app/shared/models/schd-transaction.model.ts b/front-end/src/app/shared/models/schd-transaction.model.ts new file mode 100644 index 0000000000..1fad784331 --- /dev/null +++ b/front-end/src/app/shared/models/schd-transaction.model.ts @@ -0,0 +1,61 @@ +import { plainToClass } from 'class-transformer'; +import { AggregationGroups, Transaction } from './transaction.model'; +import { LabelList } from '../utils/label.utils'; +import { getFromJSON, TransactionTypeUtils } from '../utils/transaction-type.utils'; + +export class SchDTransaction extends Transaction { + entity_type: string | undefined; + receipt_line_number: string | undefined; + aggregation_group: AggregationGroups | undefined; + + creditor_organization_name: string | undefined; + creditor_last_name: string | undefined; + creditor_first_name: string | undefined; + creditor_middle_name: string | undefined; + creditor_prefix: string | undefined; + creditor_suffix: string | undefined; + creditor_street__1: string | undefined; + creditor_street__2: string | undefined; + creditor_city: string | undefined; + creditor_state: string | undefined; + creditor_zip: string | undefined; + purpose_of_debt_or_obligation: string | undefined; + beginning_balance: number | undefined; + incurred_amount: number | undefined; + payment_amount: number | undefined; + balance_at_close: number | undefined; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + static fromJSON(json: any, depth = 2): SchDTransaction { + const transaction = plainToClass(SchDTransaction, json); + if (transaction.transaction_type_identifier) { + const transactionType = TransactionTypeUtils.factory(transaction.transaction_type_identifier); + transaction.setMetaProperties(transactionType); + } + if (depth > 0 && transaction.parent_transaction) { + transaction.parent_transaction = getFromJSON(transaction.parent_transaction, depth - 1); + } + if (depth > 0 && transaction.children) { + transaction.children = transaction.children.map(function (child) { + return getFromJSON(child, depth - 1); + }); + } + return transaction; + } +} + +export enum ScheduleDTransactionGroups { + DEBTS = 'DEBTS', +} + +export type ScheduleDTransactionGroupsType = ScheduleDTransactionGroups.DEBTS; + +export enum ScheduleDTransactionTypes { + DEBT_OWED_BY_COMMITTEE = 'DEBT_OWED_BY_COMMITTEE', + DEBT_OWED_TO_COMMITTEE = 'DEBT_OWED_TO_COMMITTEE', +} + +export const ScheduleDTransactionTypeLabels: LabelList = [ + [ScheduleDTransactionTypes.DEBT_OWED_BY_COMMITTEE, 'Debt Owed By Committee'], + [ScheduleDTransactionTypes.DEBT_OWED_TO_COMMITTEE, 'Debt Owed To Committee'], +]; diff --git a/front-end/src/app/shared/models/sche-transaction.model.spec.ts b/front-end/src/app/shared/models/sche-transaction.model.spec.ts new file mode 100644 index 0000000000..f91aa0d91d --- /dev/null +++ b/front-end/src/app/shared/models/sche-transaction.model.spec.ts @@ -0,0 +1,36 @@ +import { SchETransaction } from './sche-transaction.model'; + +describe('SchETransaction', () => { + it('should create an instance', () => { + expect(new SchETransaction()).toBeTruthy(); + }); + + it('#fromJSON() should return a populated SchETransaction instance', () => { + const data = { + id: '999', + form_type: 'SE', + payee_organization_name: 'foo', + }; + const transaction: SchETransaction = SchETransaction.fromJSON(data); + expect(transaction).toBeInstanceOf(SchETransaction); + expect(transaction.id).toBe('999'); + expect(transaction.form_type).toBe('SE'); + expect(transaction.payee_organization_name).toBe('foo'); + }); + + xit('Creates a transaction object from JSON', () => { + const json = { + transaction_type_identifier: 'INDEPENDENT_EXPENDITURE', + parent_transaction: { + transaction_type_identifier: 'INDEPENDENT_EXPENDITURE', + }, + children: [ + { + transaction_type_identifier: 'INDEPENDENT_EXPENDITURE', + }, + ], + }; + const transaction: SchETransaction = SchETransaction.fromJSON(json); + expect(transaction.constructor.name).toBe('SchETransaction'); + }); +}); diff --git a/front-end/src/app/shared/models/sche-transaction.model.ts b/front-end/src/app/shared/models/sche-transaction.model.ts new file mode 100644 index 0000000000..cc5794fa0a --- /dev/null +++ b/front-end/src/app/shared/models/sche-transaction.model.ts @@ -0,0 +1,129 @@ +import { plainToClass, Transform } from 'class-transformer'; +import { AggregationGroups, Transaction } from './transaction.model'; +import { LabelList } from '../utils/label.utils'; +import { BaseModel } from './base.model'; +import { getFromJSON, TransactionTypeUtils } from '../utils/transaction-type.utils'; + +export class SchETransaction extends Transaction { + receipt_line_number: string | undefined; + aggregation_group: AggregationGroups | undefined; + + entity_type: string | undefined; + filer_committee_id_number: string | undefined; + transaction_id_number: string | undefined; + back_reference_tran_id_number: string | undefined; + back_reference_sched_name: string | undefined; + payee_organization_name: string | undefined; + payee_last_name: string | undefined; + payee_first_name: string | undefined; + payee_middle_name: string | undefined; + payee_prefix: string | undefined; + payee_suffix: string | undefined; + + payee_street_1: string | undefined; + payee_street_2: string | undefined; + payee_city: string | undefined; + payee_state: string | undefined; + payee_zip: string | undefined; + + election_code: string | undefined; + election_other_description: string | undefined; + @Transform(BaseModel.dateTransform) dissemination_date: Date | undefined; + expenditure_amount: number | undefined; + @Transform(BaseModel.dateTransform) disbursement_date: Date | undefined; + calendar_ytd_per_election_office: number | undefined; + + expenditure_purpose_descrip: string | undefined; + category_code: string | undefined; + + payee_cmtte_fec_id_number: string | undefined; + + support_oppose_code: string | undefined; + so_candidate_id_number: string | undefined; + so_candidate_last_name: string | undefined; + so_candidate_first_name: string | undefined; + so_candinate_middle_name: string | undefined; + so_candidate_prefix: string | undefined; + so_candidate_suffix: string | undefined; + so_candidate_office: string | undefined; + so_candidate_district: string | undefined; + so_candidate_state: string | undefined; + + completing_last_name: string | undefined; + completing_first_name: string | undefined; + completing_middle_name: string | undefined; + completing_prefix: string | undefined; + completing_suffix: string | undefined; + @Transform(BaseModel.dateTransform) date_signed: Date | undefined; + + memo_code: boolean | undefined; + memo_text_description: string | undefined; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + static fromJSON(json: any, depth = 2): SchETransaction { + const transaction = plainToClass(SchETransaction, json); + if (transaction.transaction_type_identifier) { + const transactionType = TransactionTypeUtils.factory(transaction.transaction_type_identifier); + transaction.setMetaProperties(transactionType); + } + if (depth > 0 && transaction.parent_transaction) { + transaction.parent_transaction = getFromJSON(transaction.parent_transaction, depth - 1); + } + if (depth > 0 && transaction.children) { + transaction.children = transaction.children.map(function (child) { + return getFromJSON(child, depth - 1); + }); + } + return transaction; + } +} + +export enum ScheduleETransactionGroups { + INDEPENDENT_EXPENDITURES = 'INDEPENDENT_EXPENDITURES', +} + +export type ScheduleETransactionGroupsType = ScheduleETransactionGroups.INDEPENDENT_EXPENDITURES; + +export enum ScheduleETransactionTypes { + INDEPENDENT_EXPENDITURE = 'INDEPENDENT_EXPENDITURE', + MULTISTATE_INDEPENDENT_EXPENDITURE = 'MULTISTATE_INDEPENDENT_EXPENDITURE', + INDEPENDENT_EXPENDITURE_DEBT = 'INDEPENDENT_EXPENDITURE_DEBT', + INDEPENDENT_EXPENDITURE_CREDIT_CARD_PAYMENT = 'INDEPENDENT_EXPENDITURE_CREDIT_CARD_PAYMENT', + INDEPENDENT_EXPENDITURE_CREDIT_CARD_PAYMENT_MEMO = 'INDEPENDENT_EXPENDITURE_CREDIT_CARD_PAYMENT_MEMO', + INDEPENDENT_EXPENDITURE_STAFF_REIMBURSEMENT = 'INDEPENDENT_EXPENDITURE_STAFF_REIMBURSEMENT', + INDEPENDENT_EXPENDITURE_STAFF_REIMBURSEMENT_MEMO = 'INDEPENDENT_EXPENDITURE_STAFF_REIMBURSEMENT_MEMO', + INDEPENDENT_EXPENDITURE_PAYMENT_TO_PAYROLL = 'INDEPENDENT_EXPENDITURE_STAFF_REIMBURSEMENT', + INDEPENDENT_EXPENDITURE_PAYMENT_TO_PAYROLL_MEMO = 'INDEPENDENT_EXPENDITURE_STAFF_REIMBURSEMENT_MEMO', + INDEPENDENT_EXPENDITURE_VOID = 'INDEPENDENT_EXPENDITURE_VOID', +} + +export const ScheduleETransactionTypeLabels: LabelList = [ + [ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE, 'Independent Expenditure'], + [ScheduleETransactionTypes.MULTISTATE_INDEPENDENT_EXPENDITURE, 'Multistate Independent Expenditure'], + [ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE_DEBT, 'Debt for Independent Expenditure'], + [ + ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE_CREDIT_CARD_PAYMENT, + 'Credit Card Payment for Independent Expenditure', + ], + [ + ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE_CREDIT_CARD_PAYMENT_MEMO, + 'Credit Card Memo for Independent Expenditure', + ], + [ + ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE_STAFF_REIMBURSEMENT, + 'Staff Reimbursement for Independent Expenditure', + ], + [ + ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE_STAFF_REIMBURSEMENT_MEMO, + 'Staff Reimbursement Memo for Independent Expenditure', + ], + [ + ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE_PAYMENT_TO_PAYROLL, + 'Payment to Payroll for Independent Expenditure', + ], + [ + ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE_PAYMENT_TO_PAYROLL_MEMO, + 'Payment to Payroll Memo for Independent Expenditure', + ], + [ScheduleETransactionTypes.INDEPENDENT_EXPENDITURE_VOID, 'Independent Expenditure Void'], +]; diff --git a/front-end/src/app/shared/models/transaction-navigation-controls.model.ts b/front-end/src/app/shared/models/transaction-navigation-controls.model.ts index a204b08220..92ce6fa910 100644 --- a/front-end/src/app/shared/models/transaction-navigation-controls.model.ts +++ b/front-end/src/app/shared/models/transaction-navigation-controls.model.ts @@ -91,6 +91,14 @@ export const SAVE_DOUBLE_ENTRY_LIST_CONTROL = new NavigationControl( hasNoContact ); +export const SAVE_TRIPLE_ENTRY_LIST_CONTROL = new NavigationControl( + NavigationAction.SAVE, + NavigationDestination.LIST, + 'Save transactions', + 'p-button-primary', + hasNoContact +); + export const SAVE_ANOTHER_CONTROL = new NavigationControl( NavigationAction.SAVE, NavigationDestination.ANOTHER, diff --git a/front-end/src/app/shared/models/transaction-type.model.ts b/front-end/src/app/shared/models/transaction-type.model.ts index 89d867d4a6..6941a9ff88 100644 --- a/front-end/src/app/shared/models/transaction-type.model.ts +++ b/front-end/src/app/shared/models/transaction-type.model.ts @@ -8,7 +8,7 @@ import { LOAN_TERMS_FIELDS, hasFields, } from '../utils/transaction-type-properties'; -import { ContactType } from './contact.model'; +import { ContactType, STANDARD_SINGLE_CONTACT } from './contact.model'; import { TransactionNavigationControls } from './transaction-navigation-controls.model'; import { Transaction, TransactionTypes } from './transaction.model'; @@ -21,6 +21,7 @@ export abstract class TransactionType { abstract apiEndpoint: string; // Root URL to API endpoint for CRUDing transaction abstract formFields: string[]; abstract contactTypeOptions?: ContactType[]; + contactConfig: { [contactKey: string]: { [formField: string]: string } } = STANDARD_SINGLE_CONTACT; abstract title: string; abstract schema: JsonSchema; // FEC validation JSON schema abstract templateMap: TransactionTemplateMapType; // Mapping of values between the schedule (A,B,C...) and the common identifiers in the HTML templates @@ -31,13 +32,11 @@ export abstract class TransactionType { negativeAmountValueOnly = false; // Set to true if the amount for the transaction can only have a negative value isRefund = false; // Boolean flag to identify the transaction type as a refund showAggregate = true; // Boolean flag to show/hide the calculated aggregate input on the transaction forms - showStandardAmount = true; // Boolean flag to show/hide the standard amount control. This is typically hidden if an alternate is used, like in Loans - hasCandidateCommittee = false; //Boolean flag to show/hide committee inputs along side candidate info contact2IsRequired = false; // Boolean flag to cause contact_2 required to be added to the form validation // Double-entry settings isDependentChild = false; // When set to true, the parent transaction of the transaction is used to generate UI form entry page - dependentChildTransactionType?: TransactionTypes; // For double-entry transaction forms, this property defines the transaction type of the dependent child transaction + dependentChildTransactionTypes?: TransactionTypes[]; // For multi-entry transaction forms, this property defines the transaction type of the dependent child transactions inheritedFields?: TemplateMapKeyType[]; // fields that are copied from parent to child useParentContact = false; // True if the primary contact of the child transaction inherits the primary contact of its parent childTriggerFields?: TemplateMapKeyType[]; // fields that when updated in the child, trigger the parent to regenerate its description @@ -63,7 +62,6 @@ export abstract class TransactionType { dateLabel = 'DATE'; amountInputHeader = ''; purposeDescripLabel = ''; - description?: string; // Prose describing transaction and filling out the form accordionTitle?: string; // Title for accordion handle (does not include subtext) accordionSubText?: string; // Text after title in accordion handle @@ -71,6 +69,8 @@ export abstract class TransactionType { footer?: string; // Text at the end of form contactTitle?: string; // Title for primary contact contactLookupLabel?: string; //Label above contact lookup + signatoryOneTitle?: string; // Label for the signatory_1 section in the form + signatoryTwoTitle?: string; // Label for the signatory_2 section in the form getSchemaName(): string { const schema_name = this?.schema?.$id?.split('/').pop()?.split('.')[0]; @@ -102,13 +102,23 @@ export abstract class TransactionType { return ''; } - getFormControlNames(templateMap: TransactionTemplateMapType): string[] { + /** + * Generates a list of fields names for the form controls in a transaction type input component + * @returns string[] - Array of field names. + */ + getFormControlNames(): string[] { const templateFields = this.formFields - .map((name: string) => templateMap[name as TemplateMapKeyType]) + .map((name: string) => { + return name in this.templateMap ? this.templateMap[name as TemplateMapKeyType] : name; + }) .filter((field) => !!field); return ['entity_type', ...templateFields]; } + // The following "has*" methods and properties are boolean switches that show/hide + // a component or section in the transaction type input component + hasAmountInput = true; // Boolean flag to show/hide the standard amount control. This is typically hidden if an alternate is used, like in Loans + hasCandidateCommittee = false; //Boolean flag to show/hide committee inputs along side candidate info hasElectionInformation(): boolean { return hasFields(this.formFields, ELECTION_FIELDS); } @@ -130,6 +140,10 @@ export abstract class TransactionType { hasLoanTermsFields(): boolean { return hasFields(this.formFields, LOAN_TERMS_FIELDS); } + hasAdditionalInfo = true; + hasLoanAgreement = false; + hasSignature1 = false; + hasSignature2 = false; } export enum PurposeDescriptionLabelSuffix { @@ -178,6 +192,25 @@ export type TransactionTemplateMapType = { category_code: string; election_code: string; election_other_description: string; + secondary_name: string; + secondary_street_1: string; + secondary_street_2: string; + secondary_city: string; + secondary_state: string; + secondary_zip: string; + signatory_1_last_name: string; + signatory_1_first_name: string; + signatory_1_middle_name: string; + signatory_1_prefix: string; + signatory_1_suffix: string; + signatory_1_date: string; + signatory_2_last_name: string; + signatory_2_first_name: string; + signatory_2_middle_name: string; + signatory_2_prefix: string; + signatory_2_suffix: string; + signatory_2_title: string; + signatory_2_date: string; }; export type TemplateMapKeyType = keyof TransactionTemplateMapType; diff --git a/front-end/src/app/shared/models/transaction-types/C1_LOAN_AGREEMENT.model.spec.ts b/front-end/src/app/shared/models/transaction-types/C1_LOAN_AGREEMENT.model.spec.ts new file mode 100644 index 0000000000..d7a04c3515 --- /dev/null +++ b/front-end/src/app/shared/models/transaction-types/C1_LOAN_AGREEMENT.model.spec.ts @@ -0,0 +1,26 @@ +import { C1_LOAN_AGREEMENT } from './C1_LOAN_AGREEMENT.model'; +import { SchC1Transaction, ScheduleC1TransactionTypes } from '../schc1-transaction.model'; + +describe('C1_LOAN_AGREEMENT', () => { + let transactionType: C1_LOAN_AGREEMENT; + + beforeEach(() => { + transactionType = new C1_LOAN_AGREEMENT(); + // transaction = getTestTransactionByType(ScheduleCTransactionTypes.LOAN_RECEIVED_FROM_BANK) as SchCTransaction; + }); + + it('should create an instance', () => { + expect(transactionType).toBeTruthy(); + expect(transactionType.scheduleId).toBe('C1'); + }); + + it('#factory() should return a SchATransaction', () => { + const transaction: SchC1Transaction = transactionType.getNewTransaction(); + expect(transaction.form_type).toBe('SC1/10'); + expect(transaction.transaction_type_identifier).toBe(ScheduleC1TransactionTypes.C1_LOAN_AGREEMENT); + }); + + it('#generatePurposeDescription() should generate a string', () => { + expect(transactionType?.generatePurposeDescription).toBeUndefined(); + }); +}); diff --git a/front-end/src/app/shared/models/transaction-types/C1_LOAN_AGREEMENT.model.ts b/front-end/src/app/shared/models/transaction-types/C1_LOAN_AGREEMENT.model.ts new file mode 100644 index 0000000000..8c855d65d0 --- /dev/null +++ b/front-end/src/app/shared/models/transaction-types/C1_LOAN_AGREEMENT.model.ts @@ -0,0 +1,98 @@ +import { schema } from 'fecfile-validate/fecfile_validate_js/dist/C1_LOAN_AGREEMENT'; +import { SchC1Transaction, ScheduleC1TransactionTypes } from '../schc1-transaction.model'; +import { TemplateMapKeyType } from '../transaction-type.model'; +import { SchC1TransactionType } from '../schc1-transaction-type.model'; +import { + ORGANIZATION, + ORG_FIELDS, + SECONDARY_ADDRESS_FIELDS, + LOAN_TERMS_FIELDS, + SIGNATORY_1_FIELDS, + SIGNATORY_2_FIELDS, +} from 'app/shared/utils/transaction-type-properties'; +import { STANDARD_AND_SECONDARY } from '../contact.model'; + +export class C1_LOAN_AGREEMENT extends SchC1TransactionType { + formFields = [ + ...ORG_FIELDS, + ...LOAN_TERMS_FIELDS, + ...SECONDARY_ADDRESS_FIELDS, + ...SIGNATORY_1_FIELDS, + ...SIGNATORY_2_FIELDS, + 'street_1', + 'street_2', + 'city', + 'state', + 'zip', + 'date', + 'amount', + 'balance', + 'secondary_name', + + // C1 only fields not declared in the templateMap. + // They are referenced directly and not via the templateMap + // in the C1 specific form input components. + + 'loan_restructured', + 'loan_originally_incurred_date', + 'credit_amount_this_draw', + 'others_liable', + 'desc_collateral', + 'collateral_value_amount', + 'perfected_interest', + 'future_income', + 'desc_specification_of_the_above', + 'estimated_value', + 'depository_account_established_date', + 'basis_of_loan_description', + + // The line_of_credit field is strictly to save UI state on the front-end + // and is not part of the SchC1 spec + 'line_of_credit', + 'entity_type', // entity_type is not part of the C1_LOAN_AGREEMENT spec but we need to save it to the database + ]; + override contactConfig = STANDARD_AND_SECONDARY; + override contactTypeOptions = ORGANIZATION; + override isDependentChild = true; + override doMemoCodeDateCheck = false; + schema = schema; + override useParentContact = true; + override hasAmountInput = false; + override hasLoanAgreement = true; + override hasSignature1 = true; + override hasSignature2 = true; + override hasAdditionalInfo = false; + override signatoryOneTitle = 'Committee treasurer'; + override signatoryTwoTitle = 'Authorized representative'; + + override inheritedFields = [ + ...ORG_FIELDS, + 'street_1', + 'street_2', + 'city', + 'state', + 'zip', + 'amount', + 'date', + 'due_date', + 'interest_rate', + ] as TemplateMapKeyType[]; + + // override description = + // 'Only the Purpose of Receipt and Note/Memo Text are editable. To update any errors found, return to the previous step to update loan information.'; + override accordionTitle = 'STEP TWO'; + override accordionSubText = + 'Enter contact, loan, terms, collateral, and future income information for the loan agreeement'; + override formTitle = 'Receipt'; + override footer = + 'The information in this loan will automatically create a related receipt. Review the receipt; enter a purpose of receipt or note/memo text; or continue without reviewing and "Save transactions."'; + title = 'Loan Agreement'; + override contactTitle = 'Lender'; + + getNewTransaction() { + return SchC1Transaction.fromJSON({ + form_type: 'SC1/10', + transaction_type_identifier: ScheduleC1TransactionTypes.C1_LOAN_AGREEMENT, + }); + } +} diff --git a/front-end/src/app/shared/models/transaction-types/CONDUIT_EARMARK_OUT.model.ts b/front-end/src/app/shared/models/transaction-types/CONDUIT_EARMARK_OUT.model.ts index 9cac7310f2..0cefcecf68 100644 --- a/front-end/src/app/shared/models/transaction-types/CONDUIT_EARMARK_OUT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/CONDUIT_EARMARK_OUT.model.ts @@ -1,7 +1,7 @@ import { schema } from 'fecfile-validate/fecfile_validate_js/dist/CONDUIT_EARMARK_OUTS'; import { SchBTransaction, ScheduleBTransactionTypes } from '../schb-transaction.model'; import { TemplateMapKeyType } from '../transaction-type.model'; -import { ContactTypes } from '../contact.model'; +import { ContactTypes, STANDARD_AND_CANDIDATE } from '../contact.model'; import { SchATransaction } from '../scha-transaction.model'; import { COMMITTEE, @@ -12,6 +12,7 @@ import { CONDUIT_EARMARK_OUT as CommonConduitEarmarkOut } from './common-types/C export class CONDUIT_EARMARK_OUT extends CommonConduitEarmarkOut { formFields = COMMITTEE_WITH_CANDIDATE_AND_ELECTION_B_FORM_FIELDS; contactTypeOptions = COMMITTEE; + override contactConfig = STANDARD_AND_CANDIDATE; title = 'Conduit Earmark Out'; schema = schema; override parentTriggerFields = ['organization_name', 'last_name', 'first_name'] as TemplateMapKeyType[]; @@ -19,6 +20,7 @@ export class CONDUIT_EARMARK_OUT extends CommonConduitEarmarkOut { true: ScheduleBTransactionTypes.CONDUIT_EARMARK_OUT_UNDEPOSITED, false: ScheduleBTransactionTypes.CONDUIT_EARMARK_OUT_DEPOSITED, }; + override contactLookupLabel = 'ENTITY LOOKUP'; override generatePurposeDescription(transaction: SchBTransaction): string { if (!transaction.parent_transaction) return ''; diff --git a/front-end/src/app/shared/models/transaction-types/CONDUIT_EARMARK_RECEIPT.model.ts b/front-end/src/app/shared/models/transaction-types/CONDUIT_EARMARK_RECEIPT.model.ts index f1f824d019..21f1edb58f 100644 --- a/front-end/src/app/shared/models/transaction-types/CONDUIT_EARMARK_RECEIPT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/CONDUIT_EARMARK_RECEIPT.model.ts @@ -9,7 +9,7 @@ export class CONDUIT_EARMARK_RECEIPT extends CONDUIT_EARMARK { contactTypeOptions = INDIVIDUAL; title = 'Conduit Earmark'; schema = schema; - override dependentChildTransactionType = ScheduleBTransactionTypes.CONDUIT_EARMARK_OUT; + override dependentChildTransactionTypes = [ScheduleBTransactionTypes.CONDUIT_EARMARK_OUT]; override memoCodeTransactionTypes = { true: ScheduleATransactionTypes.CONDUIT_EARMARK_RECEIPT_UNDEPOSITED, false: ScheduleATransactionTypes.CONDUIT_EARMARK_RECEIPT_DEPOSITED, diff --git a/front-end/src/app/shared/models/transaction-types/CONTRIBUTION_TO_CANDIDATE.model.ts b/front-end/src/app/shared/models/transaction-types/CONTRIBUTION_TO_CANDIDATE.model.ts index 2c24dddbd6..95e1fd7d8e 100644 --- a/front-end/src/app/shared/models/transaction-types/CONTRIBUTION_TO_CANDIDATE.model.ts +++ b/front-end/src/app/shared/models/transaction-types/CONTRIBUTION_TO_CANDIDATE.model.ts @@ -7,10 +7,12 @@ import { COMMITTEE, COMMITTEE_WITH_CANDIDATE_AND_ELECTION_B_FORM_FIELDS, } from 'app/shared/utils/transaction-type-properties'; +import { STANDARD_AND_CANDIDATE } from '../contact.model'; export class CONTRIBUTION_TO_CANDIDATE extends SchBTransactionType { formFields = COMMITTEE_WITH_CANDIDATE_AND_ELECTION_B_FORM_FIELDS; contactTypeOptions = COMMITTEE; + override contactConfig = STANDARD_AND_CANDIDATE; title = LabelUtils.get(ScheduleBTransactionTypeLabels, ScheduleBTransactionTypes.CONTRIBUTION_TO_CANDIDATE); schema = schema; override showAggregate = false; diff --git a/front-end/src/app/shared/models/transaction-types/CONTRIBUTION_TO_CANDIDATE_VOID.model.ts b/front-end/src/app/shared/models/transaction-types/CONTRIBUTION_TO_CANDIDATE_VOID.model.ts index c657f30d8b..55ed9a7ee2 100644 --- a/front-end/src/app/shared/models/transaction-types/CONTRIBUTION_TO_CANDIDATE_VOID.model.ts +++ b/front-end/src/app/shared/models/transaction-types/CONTRIBUTION_TO_CANDIDATE_VOID.model.ts @@ -8,10 +8,12 @@ import { COMMITTEE, COMMITTEE_WITH_CANDIDATE_AND_ELECTION_B_FORM_FIELDS, } from 'app/shared/utils/transaction-type-properties'; +import { STANDARD_AND_CANDIDATE } from '../contact.model'; export class CONTRIBUTION_TO_CANDIDATE_VOID extends SchBTransactionType { formFields = COMMITTEE_WITH_CANDIDATE_AND_ELECTION_B_FORM_FIELDS; contactTypeOptions = COMMITTEE; + override contactConfig = STANDARD_AND_CANDIDATE; title = LabelUtils.get(ScheduleBTransactionTypeLabels, ScheduleBTransactionTypes.CONTRIBUTION_TO_CANDIDATE_VOID); schema = schema; override negativeAmountValueOnly = true; diff --git a/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT.model.ts b/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT.model.ts index 622ece57de..e62df5bb68 100644 --- a/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT.model.ts @@ -8,7 +8,7 @@ import { EARMARK } from './common-types/EARMARK.model'; export class EARMARK_RECEIPT extends EARMARK { title = LabelUtils.get(ScheduleATransactionTypeLabels, ScheduleATransactionTypes.EARMARK_RECEIPT); schema = schema; - override dependentChildTransactionType = ScheduleATransactionTypes.EARMARK_MEMO; + override dependentChildTransactionTypes = [ScheduleATransactionTypes.EARMARK_MEMO]; override generatePurposeDescription(transaction: SchATransaction): string { if (!transaction.children) return ''; diff --git a/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_CONVENTION_ACCOUNT.model.ts b/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_CONVENTION_ACCOUNT.model.ts index a9171cf7b4..05c744c272 100644 --- a/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_CONVENTION_ACCOUNT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_CONVENTION_ACCOUNT.model.ts @@ -11,7 +11,7 @@ export class EARMARK_RECEIPT_CONVENTION_ACCOUNT extends EARMARK { ScheduleATransactionTypes.EARMARK_RECEIPT_FOR_CONVENTION_ACCOUNT_CONTRIBUTION ); schema = schema; - override dependentChildTransactionType = ScheduleATransactionTypes.EARMARK_MEMO_CONVENTION_ACCOUNT; + override dependentChildTransactionTypes = [ScheduleATransactionTypes.EARMARK_MEMO_CONVENTION_ACCOUNT]; override generatePurposeDescription(transaction: SchATransaction): string { if (!transaction.children) return ''; diff --git a/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_HEADQUARTERS_ACCOUNT.model.ts b/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_HEADQUARTERS_ACCOUNT.model.ts index 609eece1d2..d41329597f 100644 --- a/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_HEADQUARTERS_ACCOUNT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_HEADQUARTERS_ACCOUNT.model.ts @@ -11,7 +11,7 @@ export class EARMARK_RECEIPT_HEADQUARTERS_ACCOUNT extends EARMARK { ScheduleATransactionTypes.EARMARK_RECEIPT_FOR_HEADQUARTERS_ACCOUNT_CONTRIBUTION ); schema = schema; - override dependentChildTransactionType = ScheduleATransactionTypes.EARMARK_MEMO_HEADQUARTERS_ACCOUNT; + override dependentChildTransactionTypes = [ScheduleATransactionTypes.EARMARK_MEMO_HEADQUARTERS_ACCOUNT]; override generatePurposeDescription(transaction: SchATransaction): string { if (!transaction.children) return ''; diff --git a/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_RECOUNT_ACCOUNT.model.ts b/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_RECOUNT_ACCOUNT.model.ts index e370d4ef50..af76d7fd6b 100644 --- a/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_RECOUNT_ACCOUNT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/EARMARK_RECEIPT_RECOUNT_ACCOUNT.model.ts @@ -11,7 +11,7 @@ export class EARMARK_RECEIPT_RECOUNT_ACCOUNT extends EARMARK { ScheduleATransactionTypes.EARMARK_RECEIPT_FOR_RECOUNT_ACCOUNT_CONTRIBUTION ); schema = schema; - override dependentChildTransactionType = ScheduleATransactionTypes.EARMARK_MEMO_RECOUNT_ACCOUNT; + override dependentChildTransactionTypes = [ScheduleATransactionTypes.EARMARK_MEMO_RECOUNT_ACCOUNT]; override generatePurposeDescription(transaction: SchATransaction): string { if (!transaction.children) return ''; diff --git a/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_100PCT_PAYMENT.model.ts b/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_100PCT_PAYMENT.model.ts index 30cb041fef..baeeaeac5c 100644 --- a/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_100PCT_PAYMENT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_100PCT_PAYMENT.model.ts @@ -8,10 +8,12 @@ import { INDIVIDUAL_ORGANIZATION_CANDIDATE_B_FORM_FIELDS, ORGANIZATION_INDIVIDUAL_COMMITTEE, } from 'app/shared/utils/transaction-type-properties'; +import { STANDARD_AND_CANDIDATE } from '../contact.model'; export class FEDERAL_ELECTION_ACTIVITY_100PCT_PAYMENT extends SchBTransactionType { formFields = INDIVIDUAL_ORGANIZATION_CANDIDATE_B_FORM_FIELDS; contactTypeOptions = ORGANIZATION_INDIVIDUAL_COMMITTEE; + override contactConfig = STANDARD_AND_CANDIDATE; title = LabelUtils.get( ScheduleBTransactionTypeLabels, ScheduleBTransactionTypes.FEDERAL_ELECTION_ACTIVITY_100PCT_PAYMENT diff --git a/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_CREDIT_CARD_PAYMENT_MEMO.model.ts b/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_CREDIT_CARD_PAYMENT_MEMO.model.ts index 442ca5f075..28489c2100 100644 --- a/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_CREDIT_CARD_PAYMENT_MEMO.model.ts +++ b/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_CREDIT_CARD_PAYMENT_MEMO.model.ts @@ -8,10 +8,12 @@ import { INDIVIDUAL_ORGANIZATION_CANDIDATE_B_FORM_FIELDS, ORGANIZATION_INDIVIDUAL_COMMITTEE, } from 'app/shared/utils/transaction-type-properties'; +import { STANDARD_AND_CANDIDATE } from '../contact.model'; export class FEDERAL_ELECTION_ACTIVITY_CREDIT_CARD_PAYMENT_MEMO extends SchBTransactionType { formFields = INDIVIDUAL_ORGANIZATION_CANDIDATE_B_FORM_FIELDS; contactTypeOptions = ORGANIZATION_INDIVIDUAL_COMMITTEE; + override contactConfig = STANDARD_AND_CANDIDATE; title = LabelUtils.get( ScheduleBTransactionTypeLabels, ScheduleBTransactionTypes.FEDERAL_ELECTION_ACTIVITY_CREDIT_CARD_PAYMENT_MEMO diff --git a/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_VOID.model.ts b/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_VOID.model.ts index 8d20139450..c3c8c75fc1 100644 --- a/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_VOID.model.ts +++ b/front-end/src/app/shared/models/transaction-types/FEDERAL_ELECTION_ACTIVITY_VOID.model.ts @@ -9,10 +9,12 @@ import { INDIVIDUAL_ORGANIZATION_CANDIDATE_B_FORM_FIELDS, ORGANIZATION_INDIVIDUAL_COMMITTEE, } from 'app/shared/utils/transaction-type-properties'; +import { STANDARD_AND_CANDIDATE } from '../contact.model'; export class FEDERAL_ELECTION_ACTIVITY_VOID extends SchBTransactionType { formFields = INDIVIDUAL_ORGANIZATION_CANDIDATE_B_FORM_FIELDS; contactTypeOptions = ORGANIZATION_INDIVIDUAL_COMMITTEE; + override contactConfig = STANDARD_AND_CANDIDATE; title = LabelUtils.get(ScheduleBTransactionTypeLabels, ScheduleBTransactionTypes.FEDERAL_ELECTION_ACTIVITY_VOID); schema = schema; override negativeAmountValueOnly = true; diff --git a/front-end/src/app/shared/models/transaction-types/IN_KIND_RECEIPT.model.ts b/front-end/src/app/shared/models/transaction-types/IN_KIND_RECEIPT.model.ts index 211454e756..07f3c0b75d 100644 --- a/front-end/src/app/shared/models/transaction-types/IN_KIND_RECEIPT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/IN_KIND_RECEIPT.model.ts @@ -15,7 +15,7 @@ export class IN_KIND_RECEIPT extends IN_KIND { override contactTypeOptions = INDIVIDUAL; title = LabelUtils.get(ScheduleATransactionTypeLabels, ScheduleATransactionTypes.IN_KIND_RECEIPT); schema = schema; - override dependentChildTransactionType = ScheduleBTransactionTypes.IN_KIND_OUT; + override dependentChildTransactionTypes = [ScheduleBTransactionTypes.IN_KIND_OUT]; override navigationControls: TransactionNavigationControls = STANDARD_DOUBLE_ENTRY_CONTROLS; getNewTransaction() { diff --git a/front-end/src/app/shared/models/transaction-types/IN_KIND_TRANSFER.model.ts b/front-end/src/app/shared/models/transaction-types/IN_KIND_TRANSFER.model.ts index 6006e64889..3116bdcfb9 100644 --- a/front-end/src/app/shared/models/transaction-types/IN_KIND_TRANSFER.model.ts +++ b/front-end/src/app/shared/models/transaction-types/IN_KIND_TRANSFER.model.ts @@ -8,7 +8,7 @@ import { IN_KIND } from './common-types/IN_KIND.model'; export class IN_KIND_TRANSFER extends IN_KIND { title = LabelUtils.get(ScheduleATransactionTypeLabels, ScheduleATransactionTypes.IN_KIND_TRANSFER); schema = schema; - override dependentChildTransactionType = ScheduleBTransactionTypes.IN_KIND_TRANSFER_OUT; + override dependentChildTransactionTypes = [ScheduleBTransactionTypes.IN_KIND_TRANSFER_OUT]; getNewTransaction() { return SchATransaction.fromJSON({ diff --git a/front-end/src/app/shared/models/transaction-types/IN_KIND_TRANSFER_FEDERAL_ELECTION_ACTIVITY.model.ts b/front-end/src/app/shared/models/transaction-types/IN_KIND_TRANSFER_FEDERAL_ELECTION_ACTIVITY.model.ts index edc8646321..e266a5e31e 100644 --- a/front-end/src/app/shared/models/transaction-types/IN_KIND_TRANSFER_FEDERAL_ELECTION_ACTIVITY.model.ts +++ b/front-end/src/app/shared/models/transaction-types/IN_KIND_TRANSFER_FEDERAL_ELECTION_ACTIVITY.model.ts @@ -11,7 +11,7 @@ export class IN_KIND_TRANSFER_FEDERAL_ELECTION_ACTIVITY extends IN_KIND { ScheduleATransactionTypes.IN_KIND_TRANSFER_FEDERAL_ELECTION_ACTIVITY ); schema = schema; - override dependentChildTransactionType = ScheduleBTransactionTypes.IN_KIND_TRANSFER_FEA_OUT; + override dependentChildTransactionTypes = [ScheduleBTransactionTypes.IN_KIND_TRANSFER_FEA_OUT]; getNewTransaction() { return SchATransaction.fromJSON({ diff --git a/front-end/src/app/shared/models/transaction-types/LOAN_BY_COMMITTEE.model.ts b/front-end/src/app/shared/models/transaction-types/LOAN_BY_COMMITTEE.model.ts index 16d1354748..8753e45859 100644 --- a/front-end/src/app/shared/models/transaction-types/LOAN_BY_COMMITTEE.model.ts +++ b/front-end/src/app/shared/models/transaction-types/LOAN_BY_COMMITTEE.model.ts @@ -37,7 +37,7 @@ export class LOAN_BY_COMMITTEE extends SchCTransactionType { 'text4000', ]; contactTypeOptions = COMMITTEE; - override showStandardAmount = false; + override hasAmountInput = false; override doMemoCodeDateCheck = false; title = LabelUtils.get(ScheduleCTransactionTypeLabels, ScheduleCTransactionTypes.LOAN_BY_COMMITTEE); @@ -52,8 +52,8 @@ export class LOAN_BY_COMMITTEE extends SchCTransactionType { override contactLookupLabel = 'LENDEE LOOKUP'; schema = schema; - override apiEndpoint = '/transactions/save-pair'; - override dependentChildTransactionType = ScheduleBTransactionTypes.LOAN_MADE; + override apiEndpoint = '/transactions/save'; + override dependentChildTransactionTypes = [ScheduleBTransactionTypes.LOAN_MADE]; override subTransactionConfig = new SubTransactionGroup('Guarantors', []); override navigationControls: TransactionNavigationControls = new TransactionNavigationControls( [ diff --git a/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK.model.spec.ts b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK.model.spec.ts new file mode 100644 index 0000000000..bd0a3f0069 --- /dev/null +++ b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK.model.spec.ts @@ -0,0 +1,20 @@ +import { SchCTransaction, ScheduleCTransactionTypes } from '../schc-transaction.model'; +import { getTestTransactionByType } from 'app/shared/utils/unit-test.utils'; + +describe('LOAN_RECEIVED_FROM_BANK', () => { + let transaction: SchCTransaction; + + beforeEach(() => { + transaction = getTestTransactionByType(ScheduleCTransactionTypes.LOAN_RECEIVED_FROM_BANK) as SchCTransaction; + }); + + it('should create an instance', () => { + expect(transaction.transactionType).toBeTruthy(); + expect(transaction.transactionType?.scheduleId).toBe('C'); + }); + + it('#factory() should return a SchATransaction', () => { + expect(transaction.form_type).toBe('SC/10'); + expect(transaction.transaction_type_identifier).toBe(ScheduleCTransactionTypes.LOAN_RECEIVED_FROM_BANK); + }); +}); diff --git a/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK.model.ts b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK.model.ts new file mode 100644 index 0000000000..b6f568daad --- /dev/null +++ b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK.model.ts @@ -0,0 +1,72 @@ +import { LabelUtils } from 'app/shared/utils/label.utils'; +import { schema } from 'fecfile-validate/fecfile_validate_js/dist/LOANS'; +import { SchCTransactionType } from '../schc-transaction-type.model'; +import { SchCTransaction, ScheduleCTransactionTypeLabels, ScheduleCTransactionTypes } from '../schc-transaction.model'; +import { + CANCEL_CONTROL, + SAVE_TRIPLE_ENTRY_LIST_CONTROL, + TransactionNavigationControls, + NavigationControl, + NavigationAction, + NavigationDestination, +} from '../transaction-navigation-controls.model'; +import { hasNoContact } from '../transaction.model'; +import { SubTransactionGroup } from '../transaction-type.model'; +import { ScheduleATransactionTypes } from '../scha-transaction.model'; +import { + CORE_FIELDS, + ORG_FIELDS, + ORGANIZATION, + LOAN_FINANCE_FIELDS, + LOAN_TERMS_FIELDS, +} from 'app/shared/utils/transaction-type-properties'; +import { ScheduleC1TransactionTypes } from '../schc1-transaction.model'; + +export class LOAN_RECEIVED_FROM_BANK extends SchCTransactionType { + override formFields = [...CORE_FIELDS, ...ORG_FIELDS, ...LOAN_FINANCE_FIELDS, ...LOAN_TERMS_FIELDS]; + contactTypeOptions = ORGANIZATION; + override hasAmountInput = false; + override doMemoCodeDateCheck = false; + title = LabelUtils.get(ScheduleCTransactionTypeLabels, ScheduleCTransactionTypes.LOAN_RECEIVED_FROM_BANK); + + override description = + 'Follow this multi-step process to create both a loan received from the bank and a loan agreement. This loan type automatically creates an associated transaction. Saving a loan received from bank will autmatically create an associated disbursement.'; + override accordionTitle = 'STEP ONE'; + override accordionSubText = 'Enter lender, loan, and terms information for a loan received for a bank'; + override formTitle = 'Loan'; + override footer = + 'The information in this loan will automatically create a related disbursement. Review the disbursement; enter a purpose of disbursement or note/memo text; or contiue without reviewing and "Save transactions."'; + override contactTitle = 'Lender'; + override contactLookupLabel = 'LENDER LOOKUP'; + + schema = schema; + override apiEndpoint = '/transactions/save'; + override dependentChildTransactionTypes = [ + ScheduleC1TransactionTypes.C1_LOAN_AGREEMENT, + ScheduleATransactionTypes.LOAN_RECEIVED_FROM_BANK_RECEIPT, + ]; + override subTransactionConfig = new SubTransactionGroup('Guarantors', []); + override navigationControls: TransactionNavigationControls = new TransactionNavigationControls( + [ + new NavigationControl( + NavigationAction.SAVE, + NavigationDestination.CHILD, + 'Add loan guarantor', + 'p-button-warning', + hasNoContact, + () => true, + 'pi pi-plus' + ), + ], + [CANCEL_CONTROL], + [SAVE_TRIPLE_ENTRY_LIST_CONTROL] + ); + + getNewTransaction() { + return SchCTransaction.fromJSON({ + form_type: 'SC/10', + transaction_type_identifier: ScheduleCTransactionTypes.LOAN_RECEIVED_FROM_BANK, + receipt_line_number: '13', + }); + } +} diff --git a/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK_RECEIPT.model.spec.ts b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK_RECEIPT.model.spec.ts new file mode 100644 index 0000000000..7b70695f06 --- /dev/null +++ b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK_RECEIPT.model.spec.ts @@ -0,0 +1,27 @@ +import { LOAN_RECEIVED_FROM_BANK_RECEIPT } from './LOAN_RECEIVED_FROM_BANK_RECEIPT.model'; +import { SchATransaction, ScheduleATransactionTypes } from '../scha-transaction.model'; +import { AggregationGroups } from '../transaction.model'; + +describe('LOAN_RECEIVED_FROM_BANK_RECEIPT', () => { + let transactionType: LOAN_RECEIVED_FROM_BANK_RECEIPT; + + beforeEach(() => { + transactionType = new LOAN_RECEIVED_FROM_BANK_RECEIPT(); + }); + + it('should create an instance', () => { + expect(transactionType).toBeTruthy(); + expect(transactionType.scheduleId).toBe('A'); + }); + + it('#factory() should return a SchATransaction', () => { + const transaction: SchATransaction = transactionType.getNewTransaction(); + expect(transaction.form_type).toBe('SA13'); + expect(transaction.aggregation_group).toBe(AggregationGroups.GENERAL); + expect(transaction.transaction_type_identifier).toBe(ScheduleATransactionTypes.LOAN_RECEIVED_FROM_BANK_RECEIPT); + }); + + it('#generatePurposeDescription() should generate a string', () => { + expect(transactionType?.generatePurposeDescription).toBeUndefined(); + }); +}); diff --git a/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK_RECEIPT.model.ts b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK_RECEIPT.model.ts new file mode 100644 index 0000000000..ad48d00b5f --- /dev/null +++ b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_BANK_RECEIPT.model.ts @@ -0,0 +1,42 @@ +import { schema } from 'fecfile-validate/fecfile_validate_js/dist/LOANS_RECEIVED'; +import { AggregationGroups } from '../transaction.model'; +import { SchATransaction, ScheduleATransactionTypes } from '../scha-transaction.model'; +import { TemplateMapKeyType } from '../transaction-type.model'; +import { SchATransactionType } from '../scha-transaction-type.model'; +import { ORGANIZATION_FORM_FIELDS, ORGANIZATION, ORG_FIELDS } from 'app/shared/utils/transaction-type-properties'; + +export class LOAN_RECEIVED_FROM_BANK_RECEIPT extends SchATransactionType { + override formFields = ORGANIZATION_FORM_FIELDS; + override contactTypeOptions = ORGANIZATION; + override isDependentChild = true; + override doMemoCodeDateCheck = false; + schema = schema; + override useParentContact = true; + override inheritedFields = [ + ...ORG_FIELDS, + 'street_1', + 'street_2', + 'city', + 'state', + 'zip', + 'date', + 'amount', + 'memo_code', + ] as TemplateMapKeyType[]; + + override description = + 'Only the Purpose of Receipt and Note/Memo Text are editable. To update any errors found, return to ENTER DATA to update loan information.'; + override accordionTitle = 'AUTO-POPULATED'; + override accordionSubText = 'Review information and enter purpose of description or note/memo text for this receipt'; + override footer = undefined; + title = 'Loan Receipt'; + override contactTitle = 'Lender'; + + getNewTransaction() { + return SchATransaction.fromJSON({ + form_type: 'SA13', + transaction_type_identifier: ScheduleATransactionTypes.LOAN_RECEIVED_FROM_BANK_RECEIPT, + aggregation_group: AggregationGroups.GENERAL, + }); + } +} diff --git a/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL.model.ts b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL.model.ts index 5913170c11..e7a29df43b 100644 --- a/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL.model.ts +++ b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL.model.ts @@ -31,7 +31,7 @@ export class LOAN_RECEIVED_FROM_INDIVIDUAL extends SchCTransactionType { ...LOAN_TERMS_FIELDS, ]; contactTypeOptions = INDIVIDUAL_ORGANIZATION_COMMITTEE; - override showStandardAmount = false; + override hasAmountInput = false; override doMemoCodeDateCheck = false; title = LabelUtils.get(ScheduleCTransactionTypeLabels, ScheduleCTransactionTypes.LOAN_RECEIVED_FROM_INDIVIDUAL); @@ -45,8 +45,8 @@ export class LOAN_RECEIVED_FROM_INDIVIDUAL extends SchCTransactionType { override contactLookupLabel = 'LENDER LOOKUP'; schema = schema; - override apiEndpoint = '/transactions/save-pair'; - override dependentChildTransactionType = ScheduleATransactionTypes.LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT; + override apiEndpoint = '/transactions/save'; + override dependentChildTransactionTypes = [ScheduleATransactionTypes.LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT]; override subTransactionConfig = new SubTransactionGroup('Guarantors', []); override navigationControls: TransactionNavigationControls = new TransactionNavigationControls( [ diff --git a/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT.model.ts b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT.model.ts index 4ed0773080..1161d479f6 100644 --- a/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT.model.ts @@ -8,7 +8,6 @@ import { INDIVIDUAL_ORGANIZATION_COMMITTEE, INDIVIDUAL_FIELDS, ORG_FIELDS, - CORE_FIELDS, } from 'app/shared/utils/transaction-type-properties'; export class LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT extends SchATransactionType { @@ -19,7 +18,18 @@ export class LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT extends SchATransactionType { title = 'Receipt'; schema = schema; override useParentContact = true; - override inheritedFields = [...CORE_FIELDS, ...INDIVIDUAL_FIELDS, ...ORG_FIELDS] as TemplateMapKeyType[]; + override inheritedFields = [ + ...INDIVIDUAL_FIELDS, + ...ORG_FIELDS, + 'street_1', + 'street_2', + 'city', + 'state', + 'zip', + 'date', + 'amount', + 'memo_code' + ] as TemplateMapKeyType[]; override description = 'Only the Purpose of Receipt and Note/Memo Text are editable. To update any errors found, return to the previous step to update loan information.'; @@ -29,6 +39,7 @@ export class LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT extends SchATransactionType { override footer = undefined; override contactTitle = 'Contact'; override contactLookupLabel = 'CONTACT LOOKUP'; + override dateLabel = 'DATE'; getNewTransaction() { return SchATransaction.fromJSON({ diff --git a/front-end/src/app/shared/models/transaction-types/PAC_CONDUIT_EARMARK.model.ts b/front-end/src/app/shared/models/transaction-types/PAC_CONDUIT_EARMARK.model.ts index b0222bb6a5..641638c43e 100644 --- a/front-end/src/app/shared/models/transaction-types/PAC_CONDUIT_EARMARK.model.ts +++ b/front-end/src/app/shared/models/transaction-types/PAC_CONDUIT_EARMARK.model.ts @@ -9,7 +9,7 @@ export class PAC_CONDUIT_EARMARK extends CONDUIT_EARMARK { contactTypeOptions = COMMITTEE; title = 'PAC Conduit Earmark'; schema = schema; - override dependentChildTransactionType = ScheduleBTransactionTypes.PAC_CONDUIT_EARMARK_OUT; + override dependentChildTransactionTypes = [ScheduleBTransactionTypes.PAC_CONDUIT_EARMARK_OUT]; override memoCodeTransactionTypes = { true: ScheduleATransactionTypes.PAC_CONDUIT_EARMARK_RECEIPT_UNDEPOSITED, false: ScheduleATransactionTypes.PAC_CONDUIT_EARMARK_RECEIPT_DEPOSITED, diff --git a/front-end/src/app/shared/models/transaction-types/PAC_CONDUIT_EARMARK_OUT.model.ts b/front-end/src/app/shared/models/transaction-types/PAC_CONDUIT_EARMARK_OUT.model.ts index 735c1d1c2d..1a29b40ae2 100644 --- a/front-end/src/app/shared/models/transaction-types/PAC_CONDUIT_EARMARK_OUT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/PAC_CONDUIT_EARMARK_OUT.model.ts @@ -7,10 +7,12 @@ import { COMMITTEE_WITH_CANDIDATE_AND_ELECTION_B_FORM_FIELDS, } from 'app/shared/utils/transaction-type-properties'; import { CONDUIT_EARMARK_OUT } from './common-types/CONDUIT_EARMARK_OUT.model'; +import { STANDARD_AND_CANDIDATE } from '../contact.model'; export class PAC_CONDUIT_EARMARK_OUT extends CONDUIT_EARMARK_OUT { formFields = COMMITTEE_WITH_CANDIDATE_AND_ELECTION_B_FORM_FIELDS; contactTypeOptions = COMMITTEE; + override contactConfig = STANDARD_AND_CANDIDATE; title = 'PAC Conduit Earmark Out'; schema = schema; override parentTriggerFields = ['organization_name'] as TemplateMapKeyType[]; diff --git a/front-end/src/app/shared/models/transaction-types/PAC_EARMARK_RECEIPT.model.ts b/front-end/src/app/shared/models/transaction-types/PAC_EARMARK_RECEIPT.model.ts index 36284beee6..82650d20f4 100644 --- a/front-end/src/app/shared/models/transaction-types/PAC_EARMARK_RECEIPT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/PAC_EARMARK_RECEIPT.model.ts @@ -11,7 +11,7 @@ export class PAC_EARMARK_RECEIPT extends EARMARK { override contactTypeOptions = COMMITTEE; title = LabelUtils.get(ScheduleATransactionTypeLabels, ScheduleATransactionTypes.PAC_EARMARK_RECEIPT); schema = schema; - override dependentChildTransactionType = ScheduleATransactionTypes.PAC_EARMARK_MEMO; + override dependentChildTransactionTypes = [ScheduleATransactionTypes.PAC_EARMARK_MEMO]; override generatePurposeDescription(transaction: SchATransaction): string { if (!transaction.children) return ''; diff --git a/front-end/src/app/shared/models/transaction-types/PAC_IN_KIND_RECEIPT.model.ts b/front-end/src/app/shared/models/transaction-types/PAC_IN_KIND_RECEIPT.model.ts index 3f049cc9dd..076f486553 100644 --- a/front-end/src/app/shared/models/transaction-types/PAC_IN_KIND_RECEIPT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/PAC_IN_KIND_RECEIPT.model.ts @@ -8,7 +8,7 @@ import { IN_KIND } from './common-types/IN_KIND.model'; export class PAC_IN_KIND_RECEIPT extends IN_KIND { title = LabelUtils.get(ScheduleATransactionTypeLabels, ScheduleATransactionTypes.PAC_IN_KIND_RECEIPT); schema = schema; - override dependentChildTransactionType = ScheduleBTransactionTypes.PAC_IN_KIND_OUT; + override dependentChildTransactionTypes = [ScheduleBTransactionTypes.PAC_IN_KIND_OUT]; getNewTransaction() { return SchATransaction.fromJSON({ diff --git a/front-end/src/app/shared/models/transaction-types/PARTY_IN_KIND_RECEIPT.model.ts b/front-end/src/app/shared/models/transaction-types/PARTY_IN_KIND_RECEIPT.model.ts index 1529a248cc..a3e1df37ce 100644 --- a/front-end/src/app/shared/models/transaction-types/PARTY_IN_KIND_RECEIPT.model.ts +++ b/front-end/src/app/shared/models/transaction-types/PARTY_IN_KIND_RECEIPT.model.ts @@ -8,7 +8,7 @@ import { IN_KIND } from './common-types/IN_KIND.model'; export class PARTY_IN_KIND_RECEIPT extends IN_KIND { title = LabelUtils.get(ScheduleATransactionTypeLabels, ScheduleATransactionTypes.PARTY_IN_KIND_RECEIPT); schema = schema; - override dependentChildTransactionType = ScheduleBTransactionTypes.PARTY_IN_KIND_OUT; + override dependentChildTransactionTypes = [ScheduleBTransactionTypes.PARTY_IN_KIND_OUT]; getNewTransaction() { return SchATransaction.fromJSON({ diff --git a/front-end/src/app/shared/models/transaction-types/REFUND_TO_FEDERAL_CANDIDATE.model.ts b/front-end/src/app/shared/models/transaction-types/REFUND_TO_FEDERAL_CANDIDATE.model.ts index 52fd6bffac..559eb8b8fe 100644 --- a/front-end/src/app/shared/models/transaction-types/REFUND_TO_FEDERAL_CANDIDATE.model.ts +++ b/front-end/src/app/shared/models/transaction-types/REFUND_TO_FEDERAL_CANDIDATE.model.ts @@ -5,10 +5,12 @@ import { SchATransaction, ScheduleATransactionTypeLabels, ScheduleATransactionTy import { STANDARD_CONTROLS, TransactionNavigationControls } from '../transaction-navigation-controls.model'; import { AggregationGroups } from '../transaction.model'; import { COMMITTEE, COMMITTEE_WITH_CANDIDATE_FORM_FIELDS } from 'app/shared/utils/transaction-type-properties'; +import { STANDARD_AND_CANDIDATE } from '../contact.model'; export class REFUND_TO_FEDERAL_CANDIDATE extends SchATransactionType { formFields = COMMITTEE_WITH_CANDIDATE_FORM_FIELDS; contactTypeOptions = COMMITTEE; + override contactConfig = STANDARD_AND_CANDIDATE; title = LabelUtils.get(ScheduleATransactionTypeLabels, ScheduleATransactionTypes.REFUND_TO_FEDERAL_CANDIDATE); schema = schema; override hasCandidateCommittee = true; diff --git a/front-end/src/app/shared/models/transaction-types/common-types/CONDUIT_EARMARK.model.ts b/front-end/src/app/shared/models/transaction-types/common-types/CONDUIT_EARMARK.model.ts index 0160a6aba8..5340dc632e 100644 --- a/front-end/src/app/shared/models/transaction-types/common-types/CONDUIT_EARMARK.model.ts +++ b/front-end/src/app/shared/models/transaction-types/common-types/CONDUIT_EARMARK.model.ts @@ -9,7 +9,7 @@ export abstract class CONDUIT_EARMARK extends SchATransactionType { override navigationControls: TransactionNavigationControls = STANDARD_DOUBLE_ENTRY_CONTROLS; override childTriggerFields = ['organization_name', 'last_name', 'first_name'] as TemplateMapKeyType[]; override showAggregate = false; - override apiEndpoint = '/transactions/save-pair'; + override apiEndpoint = '/transactions/save'; override memoCodeMap = { true: 'Undeposited', false: 'Deposited', diff --git a/front-end/src/app/shared/models/transaction-types/common-types/IN_KIND.model.ts b/front-end/src/app/shared/models/transaction-types/common-types/IN_KIND.model.ts index 72e57c2006..70a56a4702 100644 --- a/front-end/src/app/shared/models/transaction-types/common-types/IN_KIND.model.ts +++ b/front-end/src/app/shared/models/transaction-types/common-types/IN_KIND.model.ts @@ -6,7 +6,7 @@ import { } from '../../transaction-navigation-controls.model'; export abstract class IN_KIND extends SchATransactionType { - override apiEndpoint = '/transactions/save-pair'; + override apiEndpoint = '/transactions/save'; override navigationControls: TransactionNavigationControls = STANDARD_DOUBLE_ENTRY_CONTROLS; formFields = COMMITTEE_FORM_FIELDS; contactTypeOptions = COMMITTEE; diff --git a/front-end/src/app/shared/models/transaction.model.ts b/front-end/src/app/shared/models/transaction.model.ts index da670c6616..411e0d20a0 100644 --- a/front-end/src/app/shared/models/transaction.model.ts +++ b/front-end/src/app/shared/models/transaction.model.ts @@ -17,12 +17,14 @@ import { ScheduleC2TransactionGroupsType, ScheduleC2TransactionTypes, } from './schc2-transaction.model'; +import { SchDTransaction, ScheduleDTransactionGroupsType, ScheduleDTransactionTypes } from './schd-transaction.model'; +import { SchETransaction, ScheduleETransactionGroupsType, ScheduleETransactionTypes } from './sche-transaction.model'; export abstract class Transaction extends BaseModel { id: string | undefined; @Type(() => TransactionType) - transactionType: TransactionType | undefined; + transactionType: TransactionType = {} as TransactionType; // FECFile spec properties @@ -156,19 +158,25 @@ export type ScheduleTransaction = | SchBTransaction | SchCTransaction | SchC1Transaction - | SchC2Transaction; + | SchC2Transaction + | SchDTransaction + | SchETransaction; export type TransactionTypes = | ScheduleATransactionTypes | ScheduleBTransactionTypes | ScheduleCTransactionTypes | ScheduleC1TransactionTypes - | ScheduleC2TransactionTypes; + | ScheduleC2TransactionTypes + | ScheduleDTransactionTypes + | ScheduleETransactionTypes; export type TransactionGroupTypes = | ScheduleATransactionGroupsType | ScheduleBTransactionGroupsType | ScheduleCTransactionGroupsType | ScheduleC1TransactionGroupsType - | ScheduleC2TransactionGroupsType; + | ScheduleC2TransactionGroupsType + | ScheduleDTransactionGroupsType + | ScheduleETransactionGroupsType; export enum AggregationGroups { GENERAL = 'GENERAL', diff --git a/front-end/src/app/shared/resolvers/transaction.resolver.spec.ts b/front-end/src/app/shared/resolvers/transaction.resolver.spec.ts index d5bc2e7e4b..6552533362 100644 --- a/front-end/src/app/shared/resolvers/transaction.resolver.spec.ts +++ b/front-end/src/app/shared/resolvers/transaction.resolver.spec.ts @@ -174,7 +174,7 @@ describe('TransactionResolver', () => { }); }); - it('should add new child transaction to new parent if parent has a dependentChildTransactionType', () => { + it('should add new child transaction to new parent if parent has a dependentChildTransactionTypes', () => { resolver .resolve_new_transaction('10', ScheduleATransactionTypes.EARMARK_RECEIPT) .subscribe((transaction: Transaction | undefined) => { diff --git a/front-end/src/app/shared/resolvers/transaction.resolver.ts b/front-end/src/app/shared/resolvers/transaction.resolver.ts index 3961bd6a5f..e2ba497dad 100644 --- a/front-end/src/app/shared/resolvers/transaction.resolver.ts +++ b/front-end/src/app/shared/resolvers/transaction.resolver.ts @@ -8,7 +8,7 @@ import { TransactionTypeUtils } from '../utils/transaction-type.utils'; @Injectable({ providedIn: 'root', }) -export class TransactionResolver { +export class TransactionResolver { constructor(public transactionService: TransactionService) {} resolve(route: ActivatedRouteSnapshot): Observable { @@ -34,8 +34,10 @@ export class TransactionResolver { const transaction: Transaction = transactionType.getNewTransaction(); transaction.report_id = String(reportId); - if (transactionType.dependentChildTransactionType) { - transaction.children = [this.getNewChildTransaction(transaction, transactionType.dependentChildTransactionType)]; + if (transactionType.dependentChildTransactionTypes) { + transaction.children = transactionType.dependentChildTransactionTypes.map((type) => + this.getNewChildTransaction(transaction, type) + ); } return of(transaction); @@ -97,6 +99,13 @@ export class TransactionResolver { ); } + /** + * Build out a child transaction given the parent and the transaction type wanted + * for the new child transaction. + * @param parentTransaction + * @param childTransactionTypeName + * @returns {Transaction} + */ private getNewChildTransaction(parentTransaction: Transaction, childTransactionTypeName: string): Transaction { const childTransactionType = TransactionTypeUtils.factory(childTransactionTypeName); const childTransaction = childTransactionType.getNewTransaction(); diff --git a/front-end/src/app/shared/services/contact.service.spec.ts b/front-end/src/app/shared/services/contact.service.spec.ts index b5a6cf8149..30818885f3 100644 --- a/front-end/src/app/shared/services/contact.service.spec.ts +++ b/front-end/src/app/shared/services/contact.service.spec.ts @@ -237,4 +237,42 @@ describe('ContactService', () => { req.flush(mockResponse); httpTestingController.verify(); }); + + it('#checkFecIdForUniqness should return true if contact matches', () => { + const fecId = 'fecId'; + const contactId = 'contactId'; + spyOn(testApiService, 'get') + .withArgs('/contacts/get_contact_id/', { + fec_id: fecId, + }) + .and.returnValue(of('contactId' as any)); // eslint-disable-line @typescript-eslint/no-explicit-any + + service.checkFecIdForUniqness(fecId, contactId).subscribe((isUnique) => { + expect(isUnique).toBeTrue(); + }); + }); + it('#checkFecIdForUniqness should return false if server comes back with differnt contact id', () => { + const fecId = 'fecId'; + const contactId = 'contactId'; + spyOn(testApiService, 'get') + .withArgs('/contacts/get_contact_id/', { + fec_id: fecId, + }) + .and.returnValue(of('different id' as any)); // eslint-disable-line @typescript-eslint/no-explicit-any + service.checkFecIdForUniqness(fecId, contactId).subscribe((isUnique) => { + expect(isUnique).toBeFalse(); + }); + }); + it('#checkFecIdForUniqness should return true if server comes back no id', () => { + const fecId = 'fecId'; + const contactId = 'contactId'; + spyOn(testApiService, 'get') + .withArgs('/contacts/get_contact_id/', { + fec_id: fecId, + }) + .and.returnValue(of('' as any)); // eslint-disable-line @typescript-eslint/no-explicit-any + service.checkFecIdForUniqness(fecId, contactId).subscribe((isUnique) => { + expect(isUnique).toBeTrue(); + }); + }); }); diff --git a/front-end/src/app/shared/services/contact.service.ts b/front-end/src/app/shared/services/contact.service.ts index 4bf57a2a51..bd2d4228ac 100644 --- a/front-end/src/app/shared/services/contact.service.ts +++ b/front-end/src/app/shared/services/contact.service.ts @@ -1,10 +1,11 @@ import { Injectable } from '@angular/core'; +import { AbstractControl } from '@angular/forms'; import { schema as contactCandidateSchema } from 'fecfile-validate/fecfile_validate_js/dist/Contact_Candidate'; import { schema as contactCommitteeSchema } from 'fecfile-validate/fecfile_validate_js/dist/Contact_Committee'; import { schema as contactIndividualSchema } from 'fecfile-validate/fecfile_validate_js/dist/Contact_Individual'; import { schema as contactOrganizationSchema } from 'fecfile-validate/fecfile_validate_js/dist/Contact_Organization'; import { Observable, of } from 'rxjs'; -import { debounceTime, map, switchMap } from 'rxjs/operators'; +import { map, switchMap } from 'rxjs/operators'; import { JsonSchema } from '../interfaces/json-schema.interface'; import { TableListService } from '../interfaces/table-list-service.interface'; import { @@ -17,7 +18,6 @@ import { } from '../models/contact.model'; import { ListRestResponse } from '../models/rest-api.model'; import { ApiService } from './api.service'; -import { AbstractControl, AsyncValidatorFn } from '@angular/forms'; @Injectable({ providedIn: 'root', @@ -85,21 +85,27 @@ export class ContactService implements TableListService { .pipe(map((response) => CommitteeLookupResponse.fromJSON(response))); } - public checkFecIdForUniqness(fec_id: string): Observable { - return fec_id ? this.apiService.get(`/contacts/fec_id_is_unique/${fec_id}/`) : of(true); + public checkFecIdForUniqness(fecId: string, contactId?: string): Observable { + if (fecId) { + return this.apiService + .get(`/contacts/get_contact_id/`, { fec_id: fecId }) + .pipe(map((matchingContactId) => matchingContactId == '' || matchingContactId == (contactId ?? ''))); + } + return of(true); } - public fecIdValidator: AsyncValidatorFn = (control: AbstractControl) => { - return of(control.value).pipe( - debounceTime(500), - switchMap((fecId) => - this.checkFecIdForUniqness(fecId).pipe( - map((isUnique: boolean) => { - return isUnique ? null : { fecIdMustBeUnique: true }; - }) + public getFecIdValidator = (contactId?: string) => { + return (control: AbstractControl) => { + return of(control.value).pipe( + switchMap((fecId) => + this.checkFecIdForUniqness(fecId, contactId).pipe( + map((isUnique: boolean) => { + return isUnique ? null : { fecIdMustBeUnique: true }; + }) + ) ) - ) - ); + ); + }; }; public individualLookup(search: string, maxFecfileResults: number): Observable { diff --git a/front-end/src/app/shared/shared.module.ts b/front-end/src/app/shared/shared.module.ts index 7d58dd81a3..0b39718f29 100644 --- a/front-end/src/app/shared/shared.module.ts +++ b/front-end/src/app/shared/shared.module.ts @@ -44,6 +44,10 @@ import { MemoCodeInputComponent } from './components/inputs/memo-code/memo-code. import { SelectButtonModule } from 'primeng/selectbutton'; import { LoanInfoInputComponent } from './components/inputs/loan-info-input/loan-info-input.component'; import { LoanTermsInputComponent } from './components/inputs/loan-terms-input/loan-terms-input.component'; +import { LoanTermsDatesInputComponent } from './components/inputs/loan-terms-dates-input/loan-terms-dates-input.component'; +import { LoanAgreementInputComponent } from './components/inputs/loan-agreement-input/loan-agreement-input.component'; +import { SignatureInputComponent } from './components/inputs/signature-input/signature-input.component'; +import { YesNoRadioInputComponent } from './components/inputs/yes-no-radio-input/yes-no-radio-input.component'; @NgModule({ imports: [ @@ -98,6 +102,10 @@ import { LoanTermsInputComponent } from './components/inputs/loan-terms-input/lo CalculationOverlayComponent, LoanInfoInputComponent, LoanTermsInputComponent, + LoanTermsDatesInputComponent, + LoanAgreementInputComponent, + SignatureInputComponent, + YesNoRadioInputComponent, ], exports: [ FecDatePipe, @@ -120,12 +128,17 @@ import { LoanTermsInputComponent } from './components/inputs/loan-terms-input/lo EmployerInputComponent, CommitteeInputComponent, AmountInputComponent, + MemoCodeInputComponent, AdditionalInfoInputComponent, ElectionInputComponent, TableActionsButtonComponent, CalculationOverlayComponent, LoanInfoInputComponent, LoanTermsInputComponent, + LoanTermsDatesInputComponent, + LoanAgreementInputComponent, + SignatureInputComponent, + YesNoRadioInputComponent, ], providers: [DatePipe], }) diff --git a/front-end/src/app/shared/utils/transaction-type-properties.ts b/front-end/src/app/shared/utils/transaction-type-properties.ts index 8624562ff5..7f9c68b9ff 100644 --- a/front-end/src/app/shared/utils/transaction-type-properties.ts +++ b/front-end/src/app/shared/utils/transaction-type-properties.ts @@ -72,6 +72,31 @@ export const CATEGORY_CODE: string[] = ['category_code']; export const LOAN_FINANCE_FIELDS: string[] = ['payment_to_date', 'balance']; export const LOAN_TERMS_FIELDS: string[] = ['due_date', 'interest_rate', 'secured']; +export const SECONDARY_ADDRESS_FIELDS: string[] = [ + 'secondary_street_1', + 'secondary_street_2', + 'secondary_city', + 'secondary_state', + 'secondary_zip', +]; +export const SIGNATORY_1_FIELDS: string[] = [ + 'signatory_1_last_name', + 'signatory_1_first_name', + 'signatory_1_middle_name', + 'signatory_1_prefix', + 'signatory_1_suffix', + 'signatory_1_date', +]; +export const SIGNATORY_2_FIELDS: string[] = [ + 'signatory_2_last_name', + 'signatory_2_first_name', + 'signatory_2_middle_name', + 'signatory_2_prefix', + 'signatory_2_suffix', + 'signatory_2_title', + 'signatory_2_date', +]; + export function hasFields(formFields: string[], fieldsToHave: string[]): boolean { return fieldsToHave.reduce((result, election_field) => result && formFields.includes(election_field), true); } diff --git a/front-end/src/app/shared/utils/transaction-type.utils.ts b/front-end/src/app/shared/utils/transaction-type.utils.ts index 0bf101142e..11861cb930 100644 --- a/front-end/src/app/shared/utils/transaction-type.utils.ts +++ b/front-end/src/app/shared/utils/transaction-type.utils.ts @@ -90,6 +90,7 @@ import { TRIBAL_RECOUNT_RECEIPT } from '../models/transaction-types/TRIBAL_RECOU import { UNREGISTERED_RECEIPT_FROM_PERSON } from '../models/transaction-types/UNREGISTERED_RECEIPT_FROM_PERSON.model'; import { UNREGISTERED_RECEIPT_FROM_PERSON_RETURN } from '../models/transaction-types/UNREGISTERED_RECEIPT_FROM_PERSON_RETURN.model'; import { LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT } from '../models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT.model'; +import { LOAN_RECEIVED_FROM_BANK_RECEIPT } from '../models/transaction-types/LOAN_RECEIVED_FROM_BANK_RECEIPT.model'; // Schedule B ///////////////////////////////////////////////////// @@ -169,8 +170,13 @@ import { LOAN_MADE } from '../models/transaction-types/LOAN_MADE.model'; // Schedule C ///////////////////////////////////////////////////// import { LOAN_RECEIVED_FROM_INDIVIDUAL } from '../models/transaction-types/LOAN_RECEIVED_FROM_INDIVIDUAL.model'; +import { LOAN_RECEIVED_FROM_BANK } from '../models/transaction-types/LOAN_RECEIVED_FROM_BANK.model'; import { LOAN_BY_COMMITTEE } from '../models/transaction-types/LOAN_BY_COMMITTEE.model'; +// Schedule C1 //////////////////////////////////////////////////// + +import { C1_LOAN_AGREEMENT } from '../models/transaction-types/C1_LOAN_AGREEMENT.model'; + // prettier-ignore const transactionTypeClasses: any = { // eslint-disable-line @typescript-eslint/no-explicit-any // Schedule A ///////////////////////////////////////////////////// @@ -266,6 +272,7 @@ const transactionTypeClasses: any = { // eslint-disable-line @typescript-eslint/ CONDUIT_EARMARK_RECEIPT_DEPOSITED: CONDUIT_EARMARK_RECEIPT, CONDUIT_EARMARK_RECEIPT_UNDEPOSITED: CONDUIT_EARMARK_RECEIPT, LOAN_RECEIVED_FROM_INDIVIDUAL_RECEIPT, + LOAN_RECEIVED_FROM_BANK_RECEIPT, // Schedule B ///////////////////////////////////////////////////// PAC_CONDUIT_EARMARK_OUT, PAC_CONDUIT_EARMARK_OUT_DEPOSITED: PAC_CONDUIT_EARMARK_OUT, @@ -340,7 +347,10 @@ const transactionTypeClasses: any = { // eslint-disable-line @typescript-eslint/ LOAN_MADE, // Schedule C ///////////////////////////////////////////////////// LOAN_RECEIVED_FROM_INDIVIDUAL, + LOAN_RECEIVED_FROM_BANK, LOAN_BY_COMMITTEE, + // Schedule C1 //////////////////////////////////////////////////// + C1_LOAN_AGREEMENT, } export class TransactionTypeUtils { diff --git a/front-end/src/app/shared/utils/unit-test.utils.ts b/front-end/src/app/shared/utils/unit-test.utils.ts index f5601eb22e..69fb278e89 100644 --- a/front-end/src/app/shared/utils/unit-test.utils.ts +++ b/front-end/src/app/shared/utils/unit-test.utils.ts @@ -8,7 +8,7 @@ import { initialState as initUserLoginData } from 'app/store/login.reducer'; import { selectUserLoginData } from 'app/store/login.selectors'; import { CashOnHand } from '../interfaces/report.interface'; import { CommitteeAccount } from '../models/committee-account.model'; -import { Contact, ContactTypes } from '../models/contact.model'; +import { CandidateOfficeTypes, Contact, ContactTypes } from '../models/contact.model'; import { F3xSummary } from '../models/f3x-summary.model'; import { MemoText } from '../models/memo-text.model'; import { SchATransaction, ScheduleATransactionTypes } from '../models/scha-transaction.model'; @@ -127,6 +127,35 @@ export const testMockStore = { ], }; +export const testContact = Contact.fromJSON({ + id: '111', + type: ContactTypes.INDIVIDUAL, + candidate_id: '999', + committee_id: '888', + name: 'Organization LLC', + last_name: 'Smith', + first_name: 'Joe', + middle_name: 'James', + prefix: 'Mr', + suffix: 'Jr', + street_1: '123 Main St', + street_2: 'Apt B', + city: 'Anytown', + state: 'VA', + zip: '22201', + employer: 'Plumbing, Inc.', + occupation: 'plumber', + candidate_office: CandidateOfficeTypes.HOUSE, + candidate_state: 'VA', + candidate_district: '1', + telephone: '555-555-5555', + country: 'USA', + created: '8/27/2023', + updated: null, + deleted: null, + transaction_count: 3, +}); + export const testIndividualReceipt: SchATransaction = SchATransaction.fromJSON({ id: '123', transaction_type_identifier: ScheduleATransactionTypes.INDIVIDUAL_RECEIPT, @@ -246,4 +275,23 @@ export const testTemplateMap: TransactionTemplateMapType = { due_date: '', secured: '', interest_rate: '', + secondary_name: 'ind_name_account_location', + secondary_street_1: 'account_street_1', + secondary_street_2: 'account_street_2', + secondary_city: 'account_city', + secondary_state: 'account_state', + secondary_zip: 'account_zip', + signatory_1_last_name: 'treasurer_last_name', + signatory_1_first_name: 'treasurer_first_name', + signatory_1_middle_name: 'treasurer_middle_name', + signatory_1_prefix: 'treasurer_prefix', + signatory_1_suffix: 'treasurer_suffix', + signatory_1_date: 'treasurer_date_signed', + signatory_2_last_name: 'authorized_last_name', + signatory_2_first_name: 'authorized_first_name', + signatory_2_middle_name: 'authorized_middle_name', + signatory_2_prefix: 'authorized_prefix', + signatory_2_suffix: 'authorized_suffix', + signatory_2_title: 'authorized_title', + signatory_2_date: 'authorized_date_signed', }; diff --git a/front-end/src/styles.scss b/front-end/src/styles.scss index 4a4c89c7ee..d4bed066b6 100644 --- a/front-end/src/styles.scss +++ b/front-end/src/styles.scss @@ -2,6 +2,7 @@ p { max-width: 100%; + line-height: 1.5; } .grid {